feature: add quick card labels popup
This commit is contained in:
parent
2a59cddadb
commit
f1f69440c3
@ -67,7 +67,8 @@ interface QuickCardEditorState {
|
|||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
left: number;
|
left: number;
|
||||||
top: number;
|
top: number;
|
||||||
task?: Task;
|
taskID: string | null;
|
||||||
|
taskGroupID: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TitleWrapper = styled.div`
|
const TitleWrapper = styled.div`
|
||||||
@ -200,7 +201,13 @@ interface ProjectParams {
|
|||||||
projectID: string;
|
projectID: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialQuickCardEditorState: QuickCardEditorState = { isOpen: false, top: 0, left: 0 };
|
const initialQuickCardEditorState: QuickCardEditorState = {
|
||||||
|
taskID: null,
|
||||||
|
taskGroupID: null,
|
||||||
|
isOpen: false,
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
};
|
||||||
|
|
||||||
const ProjectBar = styled.div`
|
const ProjectBar = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -417,13 +424,22 @@ const Project = () => {
|
|||||||
top: e.top,
|
top: e.top,
|
||||||
left: e.left,
|
left: e.left,
|
||||||
isOpen: true,
|
isOpen: true,
|
||||||
task: currentTask,
|
taskID: currentTask.id,
|
||||||
|
taskGroupID: currentTask.taskGroup.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
labelsRef.current = data.findProject.labels;
|
labelsRef.current = data.findProject.labels;
|
||||||
|
|
||||||
|
let currentQuickTask = null;
|
||||||
|
if (quickCardEditor.taskID && quickCardEditor.taskGroupID) {
|
||||||
|
const targetGroup = data.findProject.taskGroups.find(t => t.id === quickCardEditor.taskGroupID);
|
||||||
|
if (targetGroup) {
|
||||||
|
currentQuickTask = targetGroup.tasks.find(t => t.id === quickCardEditor.taskID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GlobalTopNavbar
|
<GlobalTopNavbar
|
||||||
@ -535,17 +551,28 @@ const Project = () => {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{quickCardEditor.isOpen && (
|
{quickCardEditor.isOpen && currentQuickTask && (
|
||||||
<QuickCardEditor
|
<QuickCardEditor
|
||||||
isOpen
|
task={currentQuickTask}
|
||||||
taskID={quickCardEditor.task ? quickCardEditor.task.id : ''}
|
|
||||||
taskGroupID={quickCardEditor.task ? quickCardEditor.task.taskGroup.id : ''}
|
|
||||||
cardTitle={quickCardEditor.task ? quickCardEditor.task.name : ''}
|
|
||||||
onCloseEditor={() => setQuickCardEditor(initialQuickCardEditorState)}
|
onCloseEditor={() => setQuickCardEditor(initialQuickCardEditorState)}
|
||||||
onEditCard={(_listId: string, cardId: string, cardName: string) => {
|
onEditCard={(_listId: string, cardId: string, cardName: string) => {
|
||||||
updateTaskName({ variables: { taskID: cardId, name: cardName } });
|
updateTaskName({ variables: { taskID: cardId, name: cardName } });
|
||||||
}}
|
}}
|
||||||
onOpenPopup={() => {}}
|
onOpenLabelsPopup={($targetRef, task) => {
|
||||||
|
taskLabelsRef.current = task.labels;
|
||||||
|
showPopup(
|
||||||
|
$targetRef,
|
||||||
|
<LabelManagerEditor
|
||||||
|
onLabelToggle={labelID => {
|
||||||
|
toggleTaskLabel({ variables: { taskID: task.id, projectLabelID: labelID } });
|
||||||
|
}}
|
||||||
|
labelColors={data.labelColors}
|
||||||
|
labels={labelsRef}
|
||||||
|
taskLabels={taskLabelsRef}
|
||||||
|
projectID={projectID}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
}}
|
||||||
onArchiveCard={(_listId: string, cardId: string) =>
|
onArchiveCard={(_listId: string, cardId: string) =>
|
||||||
deleteTask({
|
deleteTask({
|
||||||
variables: { taskID: cardId },
|
variables: { taskID: cardId },
|
||||||
@ -564,7 +591,6 @@ const Project = () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
labels={[]}
|
|
||||||
top={quickCardEditor.top}
|
top={quickCardEditor.top}
|
||||||
left={quickCardEditor.left}
|
left={quickCardEditor.left}
|
||||||
/>
|
/>
|
||||||
|
@ -67,8 +67,8 @@ type Props = {
|
|||||||
onClick: (e: React.MouseEvent<HTMLDivElement>) => void;
|
onClick: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||||
dueDate?: DueDate;
|
dueDate?: DueDate;
|
||||||
checklists?: Checklist;
|
checklists?: Checklist;
|
||||||
watched?: boolean;
|
|
||||||
labels?: Array<ProjectLabel>;
|
labels?: Array<ProjectLabel>;
|
||||||
|
watched?: boolean;
|
||||||
wrapperProps?: any;
|
wrapperProps?: any;
|
||||||
members?: Array<TaskUser> | null;
|
members?: Array<TaskUser> | null;
|
||||||
onCardMemberClick?: OnCardMemberClick;
|
onCardMemberClick?: OnCardMemberClick;
|
||||||
|
@ -17,8 +17,11 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const labelData: Array<ProjectLabel> = [
|
const labelData: Array<TaskLabel> = [
|
||||||
{
|
{
|
||||||
|
id: 'development',
|
||||||
|
assignedDate: new Date().toString(),
|
||||||
|
projectLabel: {
|
||||||
id: 'development',
|
id: 'development',
|
||||||
name: 'Development',
|
name: 'Development',
|
||||||
createdDate: 'date',
|
createdDate: 'date',
|
||||||
@ -29,6 +32,7 @@ const labelData: Array<ProjectLabel> = [
|
|||||||
position: 1,
|
position: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const Default = () => {
|
export const Default = () => {
|
||||||
@ -40,15 +44,19 @@ export const Default = () => {
|
|||||||
<>
|
<>
|
||||||
{isEditorOpen && (
|
{isEditorOpen && (
|
||||||
<QuickCardEditor
|
<QuickCardEditor
|
||||||
isOpen={isEditorOpen}
|
task={{
|
||||||
taskGroupID="1"
|
id: 'task',
|
||||||
taskID="1"
|
name: 'General',
|
||||||
cardTitle="Hello, world"
|
taskGroup: {
|
||||||
|
id: '1',
|
||||||
|
},
|
||||||
|
position: 1,
|
||||||
|
labels: labelData,
|
||||||
|
}}
|
||||||
onCloseEditor={() => setEditorOpen(false)}
|
onCloseEditor={() => setEditorOpen(false)}
|
||||||
onEditCard={action('edit card')}
|
onEditCard={action('edit card')}
|
||||||
onOpenPopup={action('open popup')}
|
onOpenLabelsPopup={action('open popup')}
|
||||||
onArchiveCard={action('archive card')}
|
onArchiveCard={action('archive card')}
|
||||||
labels={labelData}
|
|
||||||
top={top}
|
top={top}
|
||||||
left={left}
|
left={left}
|
||||||
/>
|
/>
|
||||||
@ -75,7 +83,7 @@ export const Default = () => {
|
|||||||
setEditorOpen(true);
|
setEditorOpen(true);
|
||||||
}}
|
}}
|
||||||
watched
|
watched
|
||||||
labels={labelData}
|
labels={labelData.map(l => l.projectLabel)}
|
||||||
checklists={{ complete: 1, total: 4 }}
|
checklists={{ complete: 1, total: 4 }}
|
||||||
dueDate={{ isPastDue: false, formattedDate: 'Oct 26, 2020' }}
|
dueDate={{ isPastDue: false, formattedDate: 'Oct 26, 2020' }}
|
||||||
/>
|
/>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import styled, { keyframes } from 'styled-components';
|
import styled, { keyframes } from 'styled-components';
|
||||||
import TextareaAutosize from 'react-autosize-textarea';
|
import TextareaAutosize from 'react-autosize-textarea';
|
||||||
|
import { mixin } from 'shared/utils/styles';
|
||||||
|
|
||||||
export const Wrapper = styled.div<{ open: boolean }>`
|
export const Wrapper = styled.div<{ open: boolean }>`
|
||||||
background: rgba(0, 0, 0, 0.4);
|
background: rgba(0, 0, 0, 0.4);
|
||||||
@ -21,9 +22,10 @@ export const Container = styled.div<{ top: number; left: number }>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const Editor = styled.div`
|
export const Editor = styled.div`
|
||||||
background-color: #fff;
|
background-color: ${props => mixin.lighten('#262c49', 0.05)};
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
box-shadow: 0 1px 0 rgba(9, 30, 66, 0.25);
|
box-shadow: 0 1px 0 rgba(9, 30, 66, 0.25);
|
||||||
|
color: #c2c6dc;
|
||||||
padding: 6px 8px 2px;
|
padding: 6px 8px 2px;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
display: block;
|
display: block;
|
||||||
@ -59,6 +61,7 @@ export const EditorTextarea = styled(TextareaAutosize)`
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
|
color: #fff;
|
||||||
&:focus {
|
&:focus {
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -67,7 +70,7 @@ export const EditorTextarea = styled(TextareaAutosize)`
|
|||||||
|
|
||||||
export const SaveButton = styled.button`
|
export const SaveButton = styled.button`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: #5aac44;
|
background: rgb(115, 103, 240);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@ -79,10 +82,12 @@ export const SaveButton = styled.button`
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const FadeInAnimation = keyframes`
|
export const FadeInAnimation = keyframes`
|
||||||
from { opacity: 0; transform: translateX(-20px); }
|
from { opacity: 0; transform: translateX(-20px); }
|
||||||
to { opacity: 1; transform: translateX(0); }
|
to { opacity: 1; transform: translateX(0); }
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const EditorButtons = styled.div`
|
export const EditorButtons = styled.div`
|
||||||
left: 100%;
|
left: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -6,8 +6,8 @@ import {
|
|||||||
Editor,
|
Editor,
|
||||||
EditorDetails,
|
EditorDetails,
|
||||||
EditorTextarea,
|
EditorTextarea,
|
||||||
SaveButton,
|
|
||||||
EditorButtons,
|
EditorButtons,
|
||||||
|
SaveButton,
|
||||||
EditorButton,
|
EditorButton,
|
||||||
CloseButton,
|
CloseButton,
|
||||||
ListCardLabels,
|
ListCardLabels,
|
||||||
@ -15,33 +15,17 @@ import {
|
|||||||
} from './Styles';
|
} from './Styles';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
taskID: string;
|
task: Task;
|
||||||
taskGroupID: string;
|
|
||||||
cardTitle: string;
|
|
||||||
onCloseEditor: () => void;
|
onCloseEditor: () => void;
|
||||||
onEditCard: (taskGroupID: string, taskID: string, cardName: string) => void;
|
onEditCard: (taskGroupID: string, taskID: string, cardName: string) => void;
|
||||||
onOpenPopup: (popupType: number, top: number, left: number) => void;
|
onOpenLabelsPopup: ($targetRef: React.RefObject<HTMLElement>, task: Task) => void;
|
||||||
onArchiveCard: (taskGroupID: string, taskID: string) => void;
|
onArchiveCard: (taskGroupID: string, taskID: string) => void;
|
||||||
labels?: Array<ProjectLabel>;
|
|
||||||
isOpen: boolean;
|
|
||||||
top: number;
|
top: number;
|
||||||
left: number;
|
left: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const QuickCardEditor = ({
|
const QuickCardEditor = ({ task, onCloseEditor, onOpenLabelsPopup, onArchiveCard, onEditCard, top, left }: Props) => {
|
||||||
taskGroupID,
|
const [currentCardTitle, setCardTitle] = useState(task.name);
|
||||||
taskID,
|
|
||||||
cardTitle,
|
|
||||||
onCloseEditor,
|
|
||||||
onOpenPopup,
|
|
||||||
onArchiveCard,
|
|
||||||
onEditCard,
|
|
||||||
labels,
|
|
||||||
isOpen,
|
|
||||||
top,
|
|
||||||
left,
|
|
||||||
}: Props) => {
|
|
||||||
const [currentCardTitle, setCardTitle] = useState(cardTitle);
|
|
||||||
const $editorRef: any = useRef();
|
const $editorRef: any = useRef();
|
||||||
const $labelsRef: any = useRef();
|
const $labelsRef: any = useRef();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -57,23 +41,23 @@ const QuickCardEditor = ({
|
|||||||
const handleKeyDown = (e: any) => {
|
const handleKeyDown = (e: any) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
onEditCard(taskGroupID, taskID, currentCardTitle);
|
onEditCard(task.taskGroup.id, task.id, currentCardTitle);
|
||||||
onCloseEditor();
|
onCloseEditor();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper onClick={handleCloseEditor} open={isOpen}>
|
<Wrapper onClick={handleCloseEditor} open>
|
||||||
<CloseButton onClick={handleCloseEditor}>
|
<CloseButton onClick={handleCloseEditor}>
|
||||||
<Cross size={16} color="#000" />
|
<Cross size={16} color="#000" />
|
||||||
</CloseButton>
|
</CloseButton>
|
||||||
<Container left={left} top={top}>
|
<Container left={left} top={top}>
|
||||||
<Editor>
|
<Editor>
|
||||||
<ListCardLabels>
|
<ListCardLabels>
|
||||||
{labels &&
|
{task.labels &&
|
||||||
labels.map(label => (
|
task.labels.map(label => (
|
||||||
<ListCardLabel color={label.labelColor.colorHex} key={label.id}>
|
<ListCardLabel color={label.projectLabel.labelColor.colorHex} key={label.id}>
|
||||||
{label.name}
|
{label.projectLabel.name}
|
||||||
</ListCardLabel>
|
</ListCardLabel>
|
||||||
))}
|
))}
|
||||||
</ListCardLabels>
|
</ListCardLabels>
|
||||||
@ -89,14 +73,13 @@ const QuickCardEditor = ({
|
|||||||
/>
|
/>
|
||||||
</EditorDetails>
|
</EditorDetails>
|
||||||
</Editor>
|
</Editor>
|
||||||
<SaveButton onClick={e => onEditCard(taskGroupID, taskID, currentCardTitle)}>Save</SaveButton>
|
<SaveButton onClick={e => onEditCard(task.taskGroup.id, task.id, currentCardTitle)}>Save</SaveButton>
|
||||||
<EditorButtons>
|
<EditorButtons>
|
||||||
<EditorButton
|
<EditorButton
|
||||||
ref={$labelsRef}
|
ref={$labelsRef}
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const pos = $labelsRef.current.getBoundingClientRect();
|
onOpenLabelsPopup($labelsRef, task);
|
||||||
onOpenPopup(1, pos.top + $labelsRef.current.clientHeight + 4, pos.left);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Edit Labels
|
Edit Labels
|
||||||
@ -104,7 +87,7 @@ const QuickCardEditor = ({
|
|||||||
<EditorButton
|
<EditorButton
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onArchiveCard(taskGroupID, taskID);
|
onArchiveCard(task.taskGroup.id, task.id);
|
||||||
onCloseEditor();
|
onCloseEditor();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
Loading…
Reference in New Issue
Block a user