Task editing

This commit is contained in:
Gordon 2021-04-05 02:02:03 +01:00
parent 708b130059
commit 29fca87a99
13 changed files with 509 additions and 57 deletions

41
docs/styles.md Normal file
View File

@ -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`

10
docs/test-themes.md Normal file
View File

@ -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

View File

@ -126,7 +126,7 @@ export default class KanbnBoardPanel {
return;
// Create a task
case 'kanbn.create':
case 'kanbn.addTask':
KanbnTaskPanel.show(
this._extensionPath,
this._workspacePath,

View File

@ -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);

View File

@ -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) {

107
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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 (
<div>
<React.Fragment>
{
type === 'index' &&
<React.Fragment>
@ -68,11 +70,12 @@ function App() {
<TaskEditor
task={task as KanbnTask|null}
columnName={columnName}
columnNames={columnNames}
dateFormat={dateFormat}
vscode={vscode}
/>
}
</div>
</React.Fragment>
);
}

View File

@ -88,11 +88,11 @@ const Board = ({ columns, startedColumns, completedColumns, dateFormat, vscode }
<h2 className="kanbn-column-name">
{
startedColumns.indexOf(columnName) > -1 &&
<i className="kanbn-column-icon codicon codicon-chevron-right"></i>
<i className="codicon codicon-chevron-right"></i>
}
{
completedColumns.indexOf(columnName) > -1 &&
<i className="kanbn-column-icon codicon codicon-check"></i>
<i className="codicon codicon-check"></i>
}
{columnName}
<span className="kanbn-column-count">{column.length || ''}</span>
@ -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) => <TaskItem
{column.map((task, position) => <TaskItem
task={task}
index={index}
position={position}
dateFormat={dateFormat}
vscode={vscode}
/>)}

12
src/KanbnTask.d.ts vendored
View File

@ -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
}>
};

View File

@ -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 (
<div>
Viewing or editing task: {task ? task.name : '(creating new task)'}<br />
Column: {columnName}
</div>
<form className="kanbn-task-editor" onSubmit={handleSubmit}>
<h1 className="kanbn-task-editor-title">{editing ? 'Update task' : 'Create new task'}</h1>
<div
style={{
display: "flex"
}}
>
<div className="kanbn-task-editor-column-left">
<div className="kanbn-task-field kanbn-task-field-name">
<label className="kanbn-task-field-label">
<p>Name</p>
<input
className="kanbn-task-field-input"
placeholder="Name"
name="name"
value={taskData.name}
onChange={handleChange}
></input>
</label>
<span className="kanbn-task-id">{taskData.id}</span>
</div>
<div className="kanbn-task-field kanbn-task-field-description">
<label className="kanbn-task-field-label">
<p>Description</p>
<textarea
className="kanbn-task-field-textarea"
placeholder="Description"
name="description"
value={taskData.description}
onChange={handleChange}
></textarea>
</label>
</div>
</div>
<div className="kanbn-task-editor-column-right">
<div>
<button
type="submit"
className="kanbn-task-editor-button kanbn-task-editor-button-submit"
title="Save"
>
Save
</button>
<button
type="button"
className="kanbn-task-editor-button kanbn-task-editor-button-delete"
title="Delete"
>
Delete
</button>
</div>
<div className="kanbn-task-field kanbn-task-field-column">
<label className="kanbn-task-field-label">
<p>Column</p>
<select
className="kanbn-task-field-select"
name="column"
value={taskData.column}
onChange={handleChange}
>
{columnNames.map(c => <option value={c}>{c}</option>)}
</select>
</label>
</div>
<div className="kanbn-task-field kanbn-task-field-assigned">
<label className="kanbn-task-field-label">
<p>Assigned to</p>
<input
className="kanbn-task-field-input"
name="metadata.assigned"
value={taskData.metadata.assigned}
onChange={handleChange}
></input>
</label>
</div>
<div className="kanbn-task-field kanbn-task-field-due">
<label className="kanbn-task-field-label">
<p>Due date</p>
<input
type="date"
className="kanbn-task-field-input"
name="metadata.due"
value={taskData.metadata.due}
onChange={handleChange}
></input>
</label>
</div>
<div className="kanbn-task-field kanbn-task-field-progress">
<label className="kanbn-task-field-label">
<p>Progress</p>
<input
type="number"
className="kanbn-task-field-input"
name="progress"
value={taskData.progress}
onChange={handleChange}
min="0"
max="1"
step="0.05"
></input>
</label>
</div>
</div>
</div>
</form>
);
}

View File

@ -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 }: {
<Draggable
key={task.id}
draggableId={task.id}
index={index}
index={position}
>
{(provided, snapshot) => {
return (
@ -59,7 +60,7 @@ const TaskItem = ({ task, index, dateFormat, vscode }: {
return (
<span className={[
'kanbn-task-tag',
`kanbn-task-tag-${tag}`
`kanbn-task-tag-${paramCase(tag)}`
].join(' ')}>
{tag}
</span>

View File

@ -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;
}