diff --git a/docs/styles.md b/docs/styles.md new file mode 100644 index 0000000..2e81b2b --- /dev/null +++ b/docs/styles.md @@ -0,0 +1,41 @@ +# Styles + +The kanbn board has a default style which is based on the current vscode theme, however this can be overridden by creating a CSS file `board.css` inside the `.kanbn/` directory. + +## CSS class structure + +### Kanbn board + +- `div.kanbn-header` + - `h1.kanbn-header-name` + - `p.kanbn-header-description` +- `div.kanbn-board` + - `div.kanbn-column.kanbn-column-{column name in snakecase}` + - `h2.kanbn-column-name` + - `i.codicon.codicon-{chevron-right or check}` + - `span.kanbn-column-count` + - `button.kanbn-create-task-button` + - `i.codicon.codicon-add` + - `div.kanbn-column-task-list[.drag-over when dragging a task over this column]` + - `div.kanbn-task[.drag when being dragged]` + - `div.kanbn-task-row` + - `button.kanbn-task-name` + - `div.kanbn-task-row` + - `div.kanbn-task-data.kanbn-task-tags` + - `span.kanbn-task-tag.kanbn-task-tag-{tag name in snakecase}` + - `div.kanbn-task-row` + - `div.kanbn-task-data.kanbn-task-assigned` + - `i.codicon.codicon-account` + - `div.kanbn-task-data.kanbn-task-date` + - `i.codicon.codicon-clock` + - `div.kanbn-task-data.kanbn-task-comments` + - `i.codicon.codicon-comment` + - `div.kanbn-task-data.kanbn-task-sub-tasks` + - `i.codicon.codicon-tasklist` + - `div.kanbn-task-data.kanbn-task-workload` + - `i.codicon.codicon-run` + - `div.kanbn-task-progress` + +### Task editor + +- `// TODO` diff --git a/docs/test-themes.md b/docs/test-themes.md new file mode 100644 index 0000000..b47bd2a --- /dev/null +++ b/docs/test-themes.md @@ -0,0 +1,10 @@ +Tested with the following themes: +https://vscodethemes.com/e/Yummygum.city-lights-theme +https://vscodethemes.com/e/Luxcium.pop-n-lock-theme-vscode +https://vscodethemes.com/e/wwmyers.hackpot +https://vscodethemes.com/e/selfrefactor.Niketa-theme +https://vscodethemes.com/e/liviuschera.noctis +https://vscodethemes.com/e/johnpapa.winteriscoming +https://vscodethemes.com/e/Gyunbie.high-contrast-yellow-theme +https://vscodethemes.com/e/high-contrast-light.high-contrast-light +https://vscodethemes.com/e/danibram.theme-clear diff --git a/ext-src/KanbnBoardPanel.ts b/ext-src/KanbnBoardPanel.ts index 04f4343..1f991d6 100644 --- a/ext-src/KanbnBoardPanel.ts +++ b/ext-src/KanbnBoardPanel.ts @@ -126,7 +126,7 @@ export default class KanbnBoardPanel { return; // Create a task - case 'kanbn.create': + case 'kanbn.addTask': KanbnTaskPanel.show( this._extensionPath, this._workspacePath, diff --git a/ext-src/KanbnTaskPanel.ts b/ext-src/KanbnTaskPanel.ts index e6e1a7c..9dc829e 100644 --- a/ext-src/KanbnTaskPanel.ts +++ b/ext-src/KanbnTaskPanel.ts @@ -18,9 +18,30 @@ export default class KanbnTaskPanel { workspacePath: string, kanbn: typeof import('@basementuniverse/kanbn/src/main'), taskId: string|null, - columnName: string + columnName: string|null ) { const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined; + let index: any; + try { + index = await kanbn.getIndex(); + } catch (error) { + vscode.window.showErrorMessage(error instanceof Error ? error.message : error); + return; + } + let task: any = null; + if (taskId) { + try { + task = await kanbn.hydrateTask(index, await kanbn.getTask(taskId)); + } catch (error) { + vscode.window.showErrorMessage(error instanceof Error ? error.message : error); + return; + } + } + + // If no columnName is specified, use the first column + if (!columnName) { + columnName = Object.keys(index.columns)[0]; + } // Create a new panel const taskPanel = new KanbnTaskPanel( @@ -33,24 +54,10 @@ export default class KanbnTaskPanel { ); KanbnTaskPanel.panels.push(taskPanel); - let index: any; - try { - index = await kanbn.getIndex(); - } catch (error) { - vscode.window.showErrorMessage(error instanceof Error ? error.message : error); - return; - } - let task: any = null; - if (taskId) { - try { - task = await kanbn.getTask(taskId); - } catch (error) { - vscode.window.showErrorMessage(error instanceof Error ? error.message : error); - return; - } - } + // Send task data to the webview taskPanel._panel.webview.postMessage({ type: 'task', + index, task, columnName: taskPanel._columnName, tasks: await kanbn.loadAllTrackedTasks(index), @@ -78,7 +85,7 @@ export default class KanbnTaskPanel { enableScripts: true, // Retain state even when hidden - // retainContextWhenHidden: true, + retainContextWhenHidden: true, // Restrict the webview to only loading content from allowed paths localResourceRoots: [ @@ -111,16 +118,27 @@ export default class KanbnTaskPanel { vscode.window.showErrorMessage(message.text); return; + // Update the task webview panel title + case 'kanbn.updatePanelTitle': + this._panel.title = message.title; + return; + + // Create a task + case 'kanbn.create': + // TODO create task + vscode.window.showInformationMessage('create task'); + return; + // Update a task case 'kanbn.update': // TODO update task - vscode.window.showInformationMessage(`Updating task ${message.taskId}`); + vscode.window.showInformationMessage('update task'); return; // Delete a task case 'kanbn.delete': // TODO delete task - vscode.window.showInformationMessage(`Deleting task ${message.taskId}`); + vscode.window.showInformationMessage('delete task'); return; } }, null, this._disposables); diff --git a/ext-src/extension.ts b/ext-src/extension.ts index 0042764..7697bf9 100644 --- a/ext-src/extension.ts +++ b/ext-src/extension.ts @@ -1,6 +1,7 @@ import * as vscode from 'vscode'; import KanbnStatusBarItem from './KanbnStatusBarItem'; import KanbnBoardPanel from './KanbnBoardPanel'; +import KanbnTaskPanel from './KanbnTaskPanel'; let kanbnStatusBarItem: KanbnStatusBarItem; @@ -73,6 +74,33 @@ export async function activate(context: vscode.ExtensionContext) { } })); + // Register a command to add a new kanbn task. + context.subscriptions.push(vscode.commands.registerCommand('kanbn.addTask', async () => { + + // If no workspace folder is opened, we can't add a new task + if (vscode.workspace.workspaceFolders === undefined) { + vscode.window.showErrorMessage('You need to open a workspace before adding a new task.'); + return; + } + + // Set the node process directory and import kanbn + process.chdir(vscode.workspace.workspaceFolders[0].uri.fsPath); + const kanbn = await import('@basementuniverse/kanbn/src/main'); + + // If kanbn is initialised, open the task webview + if (await kanbn.initialised()) { + KanbnTaskPanel.show( + context.extensionPath, + vscode.workspace.workspaceFolders[0].uri.fsPath, + kanbn, + null, + null + ); + } else { + vscode.window.showErrorMessage('You need to initialise kanbn before adding a new task.'); + } + })); + // If a workspace folder is open, add a status bar item and start watching for file changes if (vscode.workspace.workspaceFolders !== undefined) { diff --git a/package-lock.json b/package-lock.json index 32dc493..73b34fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3361,6 +3361,12 @@ "integrity": "sha512-Q5hTcfdudEL2yOmluA1zaSyPbzWPmJ3XfSWeP3RyoYvS9hnje1ZyagrZOuQ6+1nQC1Gw+7gap3pLNL3xL6UBug==", "dev": true }, + "@types/lodash": { + "version": "4.14.168", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz", + "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==", + "dev": true + }, "@types/node": { "version": "10.17.56", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.56.tgz", @@ -9019,6 +9025,11 @@ } } }, + "fs-exists-sync": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", + "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=" + }, "fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -9686,6 +9697,46 @@ "assert-plus": "^1.0.0" } }, + "git-config-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz", + "integrity": "sha1-bTP37WPbDQ4RgTFQO6s6ykfVRmQ=", + "requires": { + "extend-shallow": "^2.0.1", + "fs-exists-sync": "^0.1.0", + "homedir-polyfill": "^1.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "git-user-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-user-name/-/git-user-name-2.0.0.tgz", + "integrity": "sha512-1DC8rUNm2I5V9v4eIpK6PSjKCp9bI0t6Wl05WSk+xEMS8GhR8GWzxM3aGZfPrfuqEfWxSbui5/pQJryJFXqCzQ==", + "requires": { + "extend-shallow": "^2.0.1", + "git-config-path": "^1.0.1", + "parse-git-config": "^1.1.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -10048,6 +10099,14 @@ "os-tmpdir": "^1.0.1" } }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "requires": { + "parse-passwd": "^1.0.0" + } + }, "hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -10642,10 +10701,9 @@ "dev": true }, "immer": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", - "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==", - "dev": true + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.1.tgz", + "integrity": "sha512-7CCw1DSgr8kKYXTYOI1qMM/f5qxT5vIVMeGLDCDX8CSxsggr1Sjdoha4OhsP0AZ1UvWbyZlILHvLjaynuu02Mg==" }, "import-cwd": { "version": "2.1.0", @@ -10725,8 +10783,7 @@ "ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "inquirer": { "version": "6.5.2", @@ -10965,8 +11022,7 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" }, "is-extglob": { "version": "1.0.0", @@ -12186,8 +12242,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -13403,6 +13458,27 @@ "safe-buffer": "^5.1.1" } }, + "parse-git-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-1.1.1.tgz", + "integrity": "sha1-06mYQxcTL1c5hxK7pDjhKVkN34w=", + "requires": { + "extend-shallow": "^2.0.1", + "fs-exists-sync": "^0.1.0", + "git-config-path": "^1.0.1", + "ini": "^1.3.4" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", @@ -13425,6 +13501,11 @@ "json-parse-better-errors": "^1.0.1" } }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + }, "parse5": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", @@ -16602,6 +16683,12 @@ "locate-path": "^3.0.0" } }, + "immer": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", + "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==", + "dev": true + }, "inquirer": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz", diff --git a/package.json b/package.json index 8c1a1ad..4e2bf9f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,11 @@ "command": "kanbn.board", "title": "Open board", "category": "Kanbn" + }, + { + "command": "kanbn.addTask", + "title": "Add task", + "category": "Kanbn" } ] }, @@ -27,6 +32,9 @@ "@basementuniverse/kanbn": "file:~/Projects/kanbn", "@types/dateformat": "^3.0.1", "dateformat": "^4.5.1", + "git-user-name": "^2.0.0", + "immer": "^9.0.1", + "lodash": "^4.17.21", "param-case": "^3.0.4", "react": "^16.3.2", "react-beautiful-dnd": "12.2.0", @@ -45,6 +53,7 @@ }, "devDependencies": { "@types/jest": "^23.3.14", + "@types/lodash": "^4.14.168", "@types/node": "^10.17.56", "@types/react": "^16.14.5", "@types/react-dom": "^16.9.12", diff --git a/src/App.tsx b/src/App.tsx index 33a7154..2a81b6f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,6 +19,7 @@ function App() { const [dateFormat, setDateFormat] = useState(''); const [task, setTask] = useState({}); const [columnName, setColumnName] = useState(''); + const [columnNames, setColumnNames] = useState([] as string[]); window.addEventListener('message', event => { switch (event.data.type) { @@ -39,6 +40,7 @@ function App() { case 'task': setTask(event.data.task); setColumnName(event.data.columnName); + setColumnNames(Object.keys(event.data.index.columns)); break; } setType(event.data.type); @@ -46,7 +48,7 @@ function App() { }); return ( -
+ { type === 'index' && @@ -68,11 +70,12 @@ function App() { } -
+ ); } diff --git a/src/Board.tsx b/src/Board.tsx index f84dd23..40bf47f 100644 --- a/src/Board.tsx +++ b/src/Board.tsx @@ -88,11 +88,11 @@ const Board = ({ columns, startedColumns, completedColumns, dateFormat, vscode }

{ startedColumns.indexOf(columnName) > -1 && - + } { completedColumns.indexOf(columnName) > -1 && - + } {columnName} {column.length || ''} @@ -101,7 +101,7 @@ const Board = ({ columns, startedColumns, completedColumns, dateFormat, vscode } className="kanbn-create-task-button" onClick={() => { vscode.postMessage({ - command: 'kanbn.create', + command: 'kanbn.addTask', columnName }) }} @@ -122,9 +122,9 @@ const Board = ({ columns, startedColumns, completedColumns, dateFormat, vscode } snapshot.isDraggingOver ? 'drag-over' : null ].filter(i => i).join(' ')} > - {column.map((task, index) => )} diff --git a/src/KanbnTask.d.ts b/src/KanbnTask.d.ts index 8679b28..56c8d34 100644 --- a/src/KanbnTask.d.ts +++ b/src/KanbnTask.d.ts @@ -7,11 +7,11 @@ declare type KanbnTask = { remainingWorkload?: number, progress?: number, metadata: { - created: Date, - updated?: Date, - started?: Date, - due?: Date, - completed?: Date, + created: string, + updated?: string, + started?: string, + due?: string, + completed?: string, assigned?: string, tags?: string[] }, @@ -25,7 +25,7 @@ declare type KanbnTask = { }>, comments: Array<{ author: string, - date: Date, + date: string, text: string }> }; diff --git a/src/TaskEditor.tsx b/src/TaskEditor.tsx index 92722a6..a4d0820 100644 --- a/src/TaskEditor.tsx +++ b/src/TaskEditor.tsx @@ -1,18 +1,213 @@ -import React from "react"; +import React, { useReducer, useCallback } from "react"; import formatDate from 'dateformat'; import VSCodeApi from "./VSCodeApi"; +import { paramCase } from 'param-case'; +import produce from 'immer'; +import { set, has } from 'lodash'; +import * as gitUsername from 'git-user-name'; -const TaskEditor = ({ task, columnName, dateFormat, vscode }: { +// https://levelup.gitconnected.com/handling-complex-form-state-using-react-hooks-76ee7bc937 +function reducer(state, action) { + if (action.constructor === Function) { + return { ...state, ...action(state) }; + } + if (action.constructor === Object) { + if (has(action, "_path") && has(action, "_value")) { + const { _path, _value } = action; + + return produce(state, draft => { + set(draft, _path, _value); + }); + } else { + return { ...state, ...action }; + } + } +} + +const TaskEditor = ({ task, columnName, columnNames, dateFormat, vscode }: { task: KanbnTask|null, columnName: string, + columnNames: string[], dateFormat: string, vscode: VSCodeApi }) => { + const editing = task !== null; + const [taskData, setTaskData] = useReducer(reducer, { + id: task ? task.id : '', + name: task ? task.name : '', + description: task ? task.description : '', + column: columnName, + progress: task ? task.progress : 0, + metadata: { + due: (task && 'due' in task.metadata) ? formatDate(new Date(task.metadata.due!), 'yyyy-mm-dd') : '', + assigned: (task && 'assigned' in task.metadata) ? task.metadata.assigned : gitUsername(), + tags: (task && 'tags' in task.metadata) ? task.metadata.tags : [] + }, + relations: [], + subTasks: [], + comments: [] + }); + + const handleChange = useCallback(({ target: { value, name, type } }) => { + const updatePath = name.split("."); + + // Handle updating checkbox states (depends on previous state) + if (type === 'checkbox') { + setTaskData((previousState) => ({ + [name]: !previousState[name] + })); + return; + } + + // Handle updating root-level properties + if (updatePath.length === 1) { + const [key] = updatePath; + const newTaskData = { + [key]: value + }; + + // If the name is updated, generate a new id and set the webview panel title + if (key === 'name') { + newTaskData['id'] = paramCase(value); + vscode.postMessage({ + command: 'kanbn.updatePanelTitle', + title: value || 'Untitled task' + }); + } + setTaskData(newTaskData); + } + + // Handle updating nested properties using _path and _value + if (updatePath.length > 1) { + setTaskData({ + _path: updatePath, + _value: value + }); + } + }, []); + + const handleSubmit = e => { + e.preventDefault(); + + // If a task prop was passed in, we're updating a task, otherwise we're creating a new task + if (editing) { + vscode.postMessage({ + command: 'kanbn.update' + }); + } else { + vscode.postMessage({ + command: 'kanbn.create' + }); + } + console.log(e); + }; + return ( -
- Viewing or editing task: {task ? task.name : '(creating new task)'}
- Column: {columnName} -
+
+

{editing ? 'Update task' : 'Create new task'}

+
+
+
+ + {taskData.id} +
+
+ +
+
+
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
); } diff --git a/src/TaskItem.tsx b/src/TaskItem.tsx index 950b5de..03001bf 100644 --- a/src/TaskItem.tsx +++ b/src/TaskItem.tsx @@ -1,11 +1,12 @@ import React from "react"; import { Draggable } from "react-beautiful-dnd"; import formatDate from 'dateformat'; +import { paramCase } from 'param-case'; import VSCodeApi from "./VSCodeApi"; -const TaskItem = ({ task, index, dateFormat, vscode }: { +const TaskItem = ({ task, position, dateFormat, vscode }: { task: KanbnTask, - index: number, + position: number, dateFormat: string, vscode: VSCodeApi }) => { @@ -18,7 +19,7 @@ const TaskItem = ({ task, index, dateFormat, vscode }: { {(provided, snapshot) => { return ( @@ -59,7 +60,7 @@ const TaskItem = ({ task, index, dateFormat, vscode }: { return ( {tag} diff --git a/src/index.css b/src/index.css index b3343ac..2b29865 100644 --- a/src/index.css +++ b/src/index.css @@ -23,7 +23,7 @@ body { padding-left: 8px; } -.kanbn-column-icon { +.kanbn-column-name .codicon { font-size: 0.8em !important; margin-right: 0.5em; } @@ -65,7 +65,7 @@ body { .kanbn-column-task-list { margin: 0 8px; - border-left: 3px var(--vscode-activityBar-inactiveForeground) solid; + border-left: 4px var(--vscode-activityBar-inactiveForeground) solid; } .kanbn-column-task-list.drag-over { @@ -200,7 +200,67 @@ body { position: absolute; bottom: -2px; left: 0; - height: 4px; + height: 6px; background-color: #3c7; opacity: 0.7; } + +.kanbn-task-editor-title { + font-size: 1.5em; + margin-top: 0; + padding-bottom: 0.5em; + border-bottom: 1px var(--vscode-activityBar-inactiveForeground) solid; +} + +.kanbn-task-editor-column-left { + width: 70%; + padding-right: 1em; +} + +.kanbn-task-editor-column-right { + width: 30%; +} + +.kanbn-task-field { + margin-bottom: 1em; +} + +.kanbn-task-field-label p { + color: var(--vscode-editor-foreground); + font-size: 0.8em; + letter-spacing: 0.1em; + font-weight: bold; + text-transform: uppercase; + padding: 4px 0; +} + +body.vscode-dark .kanbn-task-field-input[type="date"]::-webkit-calendar-picker-indicator { + filter: invert(1); +} + +.kanbn-task-field-input, +.kanbn-task-field-select, +.kanbn-task-field-textarea { + box-sizing: border-box; + display: block; + width: 100%; + padding: 8px; + margin: 8px 0; + background-color: var(--vscode-input-background); + color: var(--vscode-input-foreground); + border: 1px transparent solid; +} + +.kanbn-task-field-textarea { + min-height: 200px; + resize: vertical; +} + +.kanbn-task-field-input:hover, .kanbn-task-field-input:focus { + border-color: var(--vscode-input-border); +} + +.kanbn-task-id { + font-style: italic; + opacity: 0.8; +}