Ui changes feedback changes
This commit is contained in:
parent
f39ff186d6
commit
a0d0da3a42
@ -1,10 +1,6 @@
|
||||
import { faPencilAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
import { Tooltip } from './tooltip';
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -32,34 +28,27 @@ const Input = styled.input<{ visible?: boolean }>`
|
||||
`;
|
||||
|
||||
const Label = styled.div<{ visible?: boolean }>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--blue);
|
||||
opacity: 0;
|
||||
|
||||
${props =>
|
||||
props.visible &&
|
||||
css`
|
||||
opacity: 1;
|
||||
`}
|
||||
`;
|
||||
|
||||
const PencilIcon = ({ ...props }) => (
|
||||
<FontAwesomeIcon {...props} icon={faPencilAlt} size="sm"></FontAwesomeIcon>
|
||||
);
|
||||
|
||||
const Pencil = styled(PencilIcon)<{ visible: boolean }>`
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
color: var(--label_foreground);
|
||||
opacity: 0;
|
||||
padding-left: 0.5em;
|
||||
|
||||
:hover {
|
||||
opacity: 1;
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
border-radius: var(--border_radius);
|
||||
height: 2em;
|
||||
|
||||
border: none;
|
||||
outline: none;
|
||||
width: 15em;
|
||||
}
|
||||
|
||||
${props =>
|
||||
props.visible &&
|
||||
css`
|
||||
opacity: 0.5;
|
||||
opacity: 1;
|
||||
`}
|
||||
`;
|
||||
|
||||
@ -102,20 +91,18 @@ export const EditableTitleComponent = (props: {
|
||||
}
|
||||
}}
|
||||
></Input>
|
||||
<Label visible={!showInput}>{newTitle ? newTitle : 'Untitled'}</Label>
|
||||
<div>
|
||||
<Pencil
|
||||
visible={!showInput}
|
||||
onClick={() => {
|
||||
if (inputEl.current) {
|
||||
inputEl.current.select();
|
||||
inputEl.current.setSelectionRange(0, 99999);
|
||||
setShowInput(true);
|
||||
}
|
||||
}}
|
||||
></Pencil>
|
||||
<Tooltip>Rename</Tooltip>
|
||||
</div>
|
||||
<Label
|
||||
visible={!showInput}
|
||||
onClick={() => {
|
||||
if (inputEl.current) {
|
||||
inputEl.current.select();
|
||||
inputEl.current.setSelectionRange(0, 99999);
|
||||
setShowInput(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{newTitle ? newTitle : 'Untitled'}
|
||||
</Label>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
@ -14,16 +14,6 @@ const Container = styled.div`
|
||||
`;
|
||||
|
||||
const Header = styled.div`
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
|
||||
min-height: 2.5em;
|
||||
border-bottom: 5px solid var(--blue_trans1);
|
||||
`;
|
||||
|
||||
const Subheader = styled.div`
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@ -31,10 +21,17 @@ const Subheader = styled.div`
|
||||
|
||||
background: var(--blue_trans1);
|
||||
border: 5px solid rgba(0, 0, 0, 0);
|
||||
border-top: none;
|
||||
padding: 0 10px;
|
||||
`;
|
||||
|
||||
const LeftActions = styled.div`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const StyledEditableTitleComponent = styled(EditableTitleComponent)`
|
||||
margin-left: 20px;
|
||||
`;
|
||||
|
||||
export const EditorComponent = () => {
|
||||
const dispatch = useDispatch();
|
||||
const title = useSelector<AppState, string>(state => state.editor.title);
|
||||
@ -42,18 +39,18 @@ export const EditorComponent = () => {
|
||||
return (
|
||||
<Container>
|
||||
<Header>
|
||||
<ShareComponent></ShareComponent>
|
||||
</Header>
|
||||
<Subheader>
|
||||
<EditableTitleComponent
|
||||
id="editor-title"
|
||||
title={title}
|
||||
onChanged={value => {
|
||||
dispatch({ ...new ChangeTitleAction(value) });
|
||||
}}
|
||||
></EditableTitleComponent>
|
||||
<LeftActions>
|
||||
<ShareComponent></ShareComponent>
|
||||
<StyledEditableTitleComponent
|
||||
id="editor-title"
|
||||
title={title}
|
||||
onChanged={value => {
|
||||
dispatch({ ...new ChangeTitleAction(value) });
|
||||
}}
|
||||
></StyledEditableTitleComponent>
|
||||
</LeftActions>
|
||||
<SyntaxSelectComponent></SyntaxSelectComponent>
|
||||
</Subheader>
|
||||
</Header>
|
||||
<MonacoComponent></MonacoComponent>
|
||||
</Container>
|
||||
);
|
||||
|
@ -19,7 +19,7 @@ const Container = styled.div`
|
||||
|
||||
const MenuItem = styled.div<{ selected?: boolean }>`
|
||||
padding: ${verticalPadding} 0 ${verticalPadding} 1em;
|
||||
height: 1.5em;
|
||||
height: 1em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
@ -13,6 +13,7 @@ export const HGroup = styled.div`
|
||||
export const Label = styled.label`
|
||||
font-size: 1em;
|
||||
color: var(--label_foreground);
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
export const Input = styled.input`
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { faCopy } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faCopy, faLink } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import OutsideClickHandler from 'react-outside-click-handler';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import styled, { css } from 'styled-components';
|
||||
@ -16,84 +17,66 @@ const Container = styled.div`
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const Icon = styled(FontAwesomeIcon)`
|
||||
pointer-events: none;
|
||||
`;
|
||||
|
||||
const Button = styled.div<{ clicked?: boolean }>`
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
z-index: 3;
|
||||
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
height: 2em;
|
||||
width: 6em;
|
||||
color: var(--blue);
|
||||
background-color: white;
|
||||
border-radius: 1em;
|
||||
transition: width 0.3s ease-in;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
border-radius: 50%;
|
||||
|
||||
background-color: #aaa;
|
||||
color: var(--blue_opaque1);
|
||||
|
||||
&:hover {
|
||||
background-color: white;
|
||||
color: var(--blue);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
${props =>
|
||||
props.clicked &&
|
||||
css`
|
||||
width: 2em;
|
||||
background-color: white;
|
||||
`}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--blue_opaque1);
|
||||
}
|
||||
`;
|
||||
|
||||
const Label = styled.span<{ visible?: boolean }>`
|
||||
pointer-events: none;
|
||||
opacity: 1;
|
||||
transition: opacity 0.3s ease-in;
|
||||
|
||||
${props =>
|
||||
!props.visible &&
|
||||
css`
|
||||
opacity: 0;
|
||||
`}
|
||||
`;
|
||||
|
||||
const CopyIcon = ({ visible, ...props }: { visible: boolean }) => (
|
||||
<FontAwesomeIcon {...props} icon={faCopy}></FontAwesomeIcon>
|
||||
);
|
||||
|
||||
const Copy = styled(CopyIcon)`
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
opacity: 1;
|
||||
transition: opacity 0.3s ease-in;
|
||||
|
||||
${props =>
|
||||
!props.visible &&
|
||||
css`
|
||||
opacity: 0;
|
||||
color: var(--blue);
|
||||
opacity: 1;
|
||||
`}
|
||||
`;
|
||||
|
||||
const Input = styled.input<{ visible?: boolean }>`
|
||||
position: absolute;
|
||||
background-color: var(--blue);
|
||||
border-radius: 1em;
|
||||
|
||||
opacity: 0;
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
transform: translateX(0.3em);
|
||||
border: none;
|
||||
padding-left: 2em;
|
||||
outline: none;
|
||||
border-radius: 1em;
|
||||
z-index: 2;
|
||||
|
||||
padding-left: 1.5em;
|
||||
transform: translateX(0.3em);
|
||||
|
||||
font-size: 1em;
|
||||
color: white;
|
||||
background-color: var(--blue);
|
||||
|
||||
width: 2em;
|
||||
height: 1.5em;
|
||||
opacity: 0;
|
||||
transition: width 0.1s ease-in-out, opacity 0s 0.1s;
|
||||
|
||||
transition: width 0.3s ease-in;
|
||||
outline: none;
|
||||
${props =>
|
||||
props.visible &&
|
||||
css`
|
||||
opacity: 1;
|
||||
width: 25em;
|
||||
opacity: 1;
|
||||
transition: width 0.3s ease-in-out;
|
||||
`}
|
||||
`;
|
||||
|
||||
@ -118,59 +101,68 @@ export const ShareComponent = () => {
|
||||
const shareLink = useSelector<AppState, ShareState['link']>(
|
||||
state => state.share.link
|
||||
);
|
||||
const [clicked, setClicked] = useState(false);
|
||||
|
||||
const SHARE_TOOLTIP = 'Share code';
|
||||
const COPY_TOOLTIP = 'Copy link';
|
||||
const COPIED_TOOLTIP = 'Copied!';
|
||||
const [tooltipMessage, setTooltipMessage] = useState(SHARE_TOOLTIP);
|
||||
const [clicked, setClicked] = useState(false);
|
||||
const [icon, setIcon] = useState(faLink);
|
||||
|
||||
const setInitialState = () => {
|
||||
setClicked(false);
|
||||
setIcon(faLink);
|
||||
setTooltipMessage(SHARE_TOOLTIP);
|
||||
};
|
||||
|
||||
const setClickedState = () => {
|
||||
setClicked(true);
|
||||
setIcon(faCopy);
|
||||
setTooltipMessage(COPY_TOOLTIP);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (shareLink) {
|
||||
if (inputEl.current && copy(inputEl.current)) {
|
||||
setTooltipMessage(COPIED_TOOLTIP);
|
||||
} else {
|
||||
setClicked(true);
|
||||
setTooltipMessage(COPY_TOOLTIP);
|
||||
}
|
||||
} else {
|
||||
setClicked(false);
|
||||
setTooltipMessage(SHARE_TOOLTIP);
|
||||
setInitialState();
|
||||
}
|
||||
}, [shareLink]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Input
|
||||
id="share-link"
|
||||
visible={!!shareLink}
|
||||
readOnly
|
||||
ref={inputEl}
|
||||
value={shareLink ? `${window.location.origin}/p/${shareLink}` : ''}
|
||||
></Input>
|
||||
<Button
|
||||
id="share"
|
||||
clicked={clicked}
|
||||
onMouseOver={() => {
|
||||
if (tooltipMessage === COPIED_TOOLTIP) {
|
||||
setTooltipMessage(COPY_TOOLTIP);
|
||||
}
|
||||
}}
|
||||
onClick={() => {
|
||||
if (!shareLink) {
|
||||
dispatch(shareAction());
|
||||
setClicked(true);
|
||||
setTooltipMessage(COPY_TOOLTIP);
|
||||
} else if (inputEl.current) {
|
||||
copy(inputEl.current);
|
||||
setTooltipMessage(COPIED_TOOLTIP);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Label visible={!clicked}>Share</Label>
|
||||
<Copy visible={clicked}></Copy>
|
||||
<Tooltip>{tooltipMessage}</Tooltip>
|
||||
</Button>
|
||||
</Container>
|
||||
<OutsideClickHandler onOutsideClick={() => setInitialState()}>
|
||||
<Container>
|
||||
<Input
|
||||
id="share-link"
|
||||
visible={!!shareLink && clicked}
|
||||
readOnly
|
||||
ref={inputEl}
|
||||
value={shareLink ? `${window.location.origin}/p/${shareLink}` : ''}
|
||||
></Input>
|
||||
<Button
|
||||
id="share"
|
||||
clicked={clicked}
|
||||
onClick={() => {
|
||||
if (!clicked) {
|
||||
dispatch(shareAction());
|
||||
setClickedState();
|
||||
} else if (inputEl.current) {
|
||||
copy(inputEl.current);
|
||||
setTooltipMessage(COPIED_TOOLTIP);
|
||||
}
|
||||
}}
|
||||
onMouseOver={() => {
|
||||
if (tooltipMessage === COPIED_TOOLTIP) {
|
||||
setTooltipMessage(COPY_TOOLTIP);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Icon icon={icon}></Icon>
|
||||
<Tooltip>{tooltipMessage}</Tooltip>
|
||||
</Button>
|
||||
</Container>
|
||||
</OutsideClickHandler>
|
||||
);
|
||||
};
|
||||
|
@ -48,7 +48,7 @@
|
||||
--font_ghost_weight: 700;
|
||||
--font_ghost_color: rgba(153, 153, 153, 0.5); /* or #CFCFCF */
|
||||
|
||||
--content_height: 80vh;
|
||||
--content_height: 85vh;
|
||||
|
||||
--tooltip_foreground: white;
|
||||
--tooltip_background: rgba(0, 0, 0, 0.75) /*#404040*/;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import latestSchema from '../../src/schemas/share-latest';
|
||||
|
||||
describe('Latest Share Schema Migration', () => {
|
||||
it('should be v1', () => {
|
||||
expect(latestSchema.VERSION).toEqual('v1');
|
||||
it('should be v2', () => {
|
||||
expect(latestSchema.VERSION).toEqual('v2');
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user