diff --git a/.tkb b/.tkb new file mode 100644 index 0000000..9130988 --- /dev/null +++ b/.tkb @@ -0,0 +1,29 @@ +{ + "scope": "Workspace", + "tasks": { + "task-MMVBTdvRS-hXujgWL4gLW": { + "id": "task-MMVBTdvRS-hXujgWL4gLW", + "description": "Create new tasks\n\nTask can also contain lists\n\n- list item 1\n\n- list item 2", + "columnId": "column-todo" + } + }, + "columns": [ + { + "id": "column-todo", + "title": "To do", + "tasksIds": [ + "task-MMVBTdvRS-hXujgWL4gLW" + ] + }, + { + "id": "column-doing", + "title": "Doing", + "tasksIds": [] + }, + { + "id": "column-done", + "title": "Done", + "tasksIds": [] + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index bf3e06b..dac9a51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Trello Kanban Board +## 0.7.0 + +### Minor Changes + +- 9ea8bcd: You can now select custom colors for your taks and columns. + ## 0.6.1 ### Patch Changes diff --git a/extension/interface.ts b/extension/interface.ts index a8efdfa..548a2e5 100644 --- a/extension/interface.ts +++ b/extension/interface.ts @@ -9,11 +9,13 @@ export interface TaskType { id: string; description: string; columnId: string; + color?: string; } export interface ColumnType { id: string; title: string; + color?: string; description?: string; archived?: boolean; tasksIds: string[]; diff --git a/package.json b/package.json index ff801d9..855a904 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "trello-kanban-task-board", "private": true, - "version": "0.6.1", + "version": "0.7.0", "type": "module", "scripts": { "dev": "vite --port 3000", @@ -19,6 +19,7 @@ "nextjs-themes": "^2.1.1", "react": "^18.2.0", "react-beautiful-dnd": "^13.1.1", + "react-color-palette": "^7.2.0", "react-dom": "^18.2.0", "react-markdown": "^9.0.1", "react-toastify": "^9.1.3", diff --git a/src/App.test.tsx b/src/App.test.tsx index dfdb4af..0e9661e 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -137,7 +137,7 @@ describe("Test Board", () => { test("Edit task", async ({ expect }) => { const columnEl = screen.getByTestId("column-0"); const taskEl = columnEl.getElementsByClassName(taskStyles.task)[0]; - const editBtn = taskEl.getElementsByTagName("button")[0]; + const editBtn = taskEl.getElementsByTagName("button")[1]; act(() => fireEvent.click(editBtn)); const inputEl = taskEl.getElementsByTagName("textarea")[0]; act(() => fireEvent.input(inputEl, { target: { value: "Task 1" } })); @@ -170,4 +170,21 @@ describe("Test Board", () => { expect(el).toBeDefined(); act(() => fireEvent.click(el)); }); + + test("Set Column color renders", () => { + const columnEl = screen.getByTestId("column-0"); + const colorBtn = columnEl + .getElementsByClassName(columnListStyles.headerContent)[0] + .getElementsByTagName("button")[0]; + act(() => fireEvent.click(colorBtn)); + act(() => fireEvent.click(screen.getByText("Ok"))); + }); + + test("Set Task color renders", () => { + const columnEl = screen.getByTestId("column-0"); + const taskHEaderEl = columnEl.getElementsByClassName(taskStyles.task)[0].getElementsByTagName("header")[0]; + const colorBtn = taskHEaderEl.getElementsByTagName("button")[0]; + act(() => fireEvent.click(colorBtn)); + act(() => fireEvent.click(screen.getByText("Ok"))); + }); }); diff --git a/src/components/color-selector.tsx b/src/components/color-selector.tsx new file mode 100644 index 0000000..4f0e080 --- /dev/null +++ b/src/components/color-selector.tsx @@ -0,0 +1,15 @@ +import { ColorPicker, useColor } from "react-color-palette"; +import "react-color-palette/css"; + +export function ColorSelector(props: { color?: string; setColor: (color: string) => void; onClose: () => void }) { + const [color, setColor] = useColor(props.color || "gray"); + return ( +
+
+ + + +
+
+ ); +} diff --git a/src/components/column-list/column-header.tsx b/src/components/column-list/column-header.tsx index 082fa8f..9b365e4 100644 --- a/src/components/column-list/column-header.tsx +++ b/src/components/column-list/column-header.tsx @@ -3,11 +3,13 @@ import { HTMLProps, useId, useState } from "react"; import styles from "./column-list.module.scss"; import { useGlobalState } from "utils/context"; import { vscode } from "utils/vscode"; +import { ColorSelector } from "components/color-selector"; export default function ColumnHeader(props: HTMLProps & { column: ColumnType }) { const { state, setState } = useGlobalState(); const { column, ...rest } = props; const [text, setText] = useState(column.title); + const [showColorSelector, setShowColorSelector] = useState(false); const [isEditing, setIsEditing] = useState(false); const id = useId(); const onBlur = () => { @@ -25,25 +27,37 @@ export default function ColumnHeader(props: HTMLProps & { column: C setState({ ...state, columns: state.columns.filter((c) => c !== column), tasks }); vscode.toast(`"${column.title}" column and ${column.tasksIds.length} tasks deleted!`, "warn"); }; + const setColor = (color: string) => { + column.color = color; + setState({ ...state, columns: [...state.columns] }); + setShowColorSelector(false); + }; return ( -
- -
+ <> +
+ +
+ {showColorSelector && ( + setShowColorSelector(false)} /> + )} + ); } diff --git a/src/components/column-list/column-list.module.scss b/src/components/column-list/column-list.module.scss index 933dfa7..e86a375 100644 --- a/src/components/column-list/column-list.module.scss +++ b/src/components/column-list/column-list.module.scss @@ -23,15 +23,28 @@ background: var(--bg); } .header { - &:hover .close { + button { + all: unset; + display: none; + padding: 0 5px; + cursor: pointer; + } + &:hover button { display: inline-block; } + button:hover { + color: orange; + } + + .close:hover { + color: red; + } } .headerContent { cursor: grab; display: flex; padding: 0 5px; - justify-content: space-between; + align-items: center; } .placeholder { opacity: 0.5; @@ -56,10 +69,3 @@ padding: 0 10px; margin: 0 -10px; } -.close { - display: none; - cursor: pointer; - &:hover { - color: red; - } -} diff --git a/src/components/column-list/column.tsx b/src/components/column-list/column.tsx index d1292d6..c9857d3 100644 --- a/src/components/column-list/column.tsx +++ b/src/components/column-list/column.tsx @@ -24,7 +24,7 @@ export default function Column({ column, index }: { column: ColumnType; index: n // listRef.current?.scrollTo({ top: listRef.current.scrollHeight, behavior: "smooth" }); const newTaskElement = listRef.current?.children[listRef.current.children.length - 1] as HTMLLabelElement; newTaskElement?.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" }); - newTaskElement?.getElementsByTagName("button")[0].click(); + newTaskElement?.getElementsByTagName("button")[1].click(); setTimeout(() => { newTaskElement?.getElementsByTagName("textarea")[0].focus(); newTaskElement?.getElementsByTagName("textarea")[0].click(); @@ -47,7 +47,7 @@ export default function Column({ column, index }: { column: ColumnType; index: n {(provided1) => (
-
+

    diff --git a/src/components/task/index.tsx b/src/components/task/index.tsx index d0d03dd..415e396 100644 --- a/src/components/task/index.tsx +++ b/src/components/task/index.tsx @@ -7,6 +7,7 @@ import remarkGfm from "remark-gfm"; import { useGlobalState } from "utils/context"; import styles from "./task.module.scss"; import { vscode } from "utils/vscode"; +import { ColorSelector } from "components/color-selector"; function resizeTextArea(textareaRef: RefObject) { const target = textareaRef.current; @@ -18,6 +19,7 @@ function resizeTextArea(textareaRef: RefObject) { export default function Task({ task, index }: { task: TaskType; index: number }) { const { state, setState } = useGlobalState(); const [isEditing, setIsEditing] = useState(false); + const [showColorSelector, setShowColorSelector] = useState(false); const textareaRef = useRef(null); const id = useId(); @@ -32,58 +34,75 @@ export default function Task({ task, index }: { task: TaskType; index: number }) setState({ ...state, tasks, columns }); vscode.toast("Task deleted!", "success"); }; + + const setColor = (color: string) => { + task.color = color; + setState({ ...state, tasks: { ...state.tasks } }); + setShowColorSelector(false); + }; return ( - - {(provided, snapshot) => { - if (snapshot.isDragging && provided.draggableProps.style?.transform) - provided.draggableProps.style.transform += " rotate(5deg)"; - return ( -