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