Refactor todo format to remove dash prefix
This commit is contained in:
parent
3abd4447b2
commit
785d90e140
28
bun.lock
28
bun.lock
|
|
@ -103,6 +103,7 @@
|
|||
"@codemirror/autocomplete": "^6.18.6",
|
||||
"@codemirror/commands": "^6.8.1",
|
||||
"@codemirror/language": "^6.11.1",
|
||||
"@codemirror/search": "^6.5.11",
|
||||
"@codemirror/state": "^6.5.2",
|
||||
"@codemirror/view": "^6.37.2",
|
||||
"@lezer/generator": "^1.7.3",
|
||||
|
|
@ -121,10 +122,9 @@
|
|||
},
|
||||
},
|
||||
"packages/werewolf-ui": {
|
||||
"name": "werewolfUI",
|
||||
"name": "@workshop/werewolf-ui",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"bun-plugin-tailwind": "^0.0.15",
|
||||
"hono": "^4.8.3",
|
||||
"lucide-static": "^0.525.0",
|
||||
"tailwindcss": "^4.0.6",
|
||||
|
|
@ -146,6 +146,8 @@
|
|||
|
||||
"@codemirror/language": ["@codemirror/language@6.11.1", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", "@lezer/common": "^1.1.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "style-mod": "^4.0.0" } }, "sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ=="],
|
||||
|
||||
"@codemirror/search": ["@codemirror/search@6.5.11", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "crelt": "^1.0.5" } }, "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA=="],
|
||||
|
||||
"@codemirror/state": ["@codemirror/state@6.5.2", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA=="],
|
||||
|
||||
"@codemirror/view": ["@codemirror/view@6.37.2", "", { "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw=="],
|
||||
|
|
@ -218,6 +220,8 @@
|
|||
|
||||
"@workshop/todo": ["@workshop/todo@workspace:packages/todo"],
|
||||
|
||||
"@workshop/werewolf-ui": ["@workshop/werewolf-ui@workspace:packages/werewolf-ui"],
|
||||
|
||||
"accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="],
|
||||
|
||||
"ajv": ["ajv@6.10.0", "", { "dependencies": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg=="],
|
||||
|
|
@ -730,8 +734,6 @@
|
|||
|
||||
"w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="],
|
||||
|
||||
"werewolfUI": ["werewolfUI@workspace:packages/werewolf-ui"],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="],
|
||||
|
|
@ -780,6 +782,14 @@
|
|||
|
||||
"@workshop/nano-remix/hono": ["hono@4.8.4", "", {}, "sha512-KOIBp1+iUs0HrKztM4EHiB2UtzZDTBihDtOF5K6+WaJjCPeaW4Q92R8j63jOhvJI5+tZSMuKD9REVEXXY9illg=="],
|
||||
|
||||
"@workshop/todo/@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
|
||||
"@workshop/todo/hono": ["hono@4.8.4", "", {}, "sha512-KOIBp1+iUs0HrKztM4EHiB2UtzZDTBihDtOF5K6+WaJjCPeaW4Q92R8j63jOhvJI5+tZSMuKD9REVEXXY9illg=="],
|
||||
|
||||
"@workshop/werewolf-ui/@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
|
||||
"@workshop/werewolf-ui/hono": ["hono@4.8.4", "", {}, "sha512-KOIBp1+iUs0HrKztM4EHiB2UtzZDTBihDtOF5K6+WaJjCPeaW4Q92R8j63jOhvJI5+tZSMuKD9REVEXXY9illg=="],
|
||||
|
||||
"ajv/fast-deep-equal": ["fast-deep-equal@2.0.1", "", {}, "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w=="],
|
||||
|
||||
"amqplib/readable-stream": ["readable-stream@1.1.14", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" } }, "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ=="],
|
||||
|
|
@ -836,10 +846,6 @@
|
|||
|
||||
"string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||
|
||||
"werewolfUI/@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
|
||||
"werewolfUI/hono": ["hono@4.8.4", "", {}, "sha512-KOIBp1+iUs0HrKztM4EHiB2UtzZDTBihDtOF5K6+WaJjCPeaW4Q92R8j63jOhvJI5+tZSMuKD9REVEXXY9illg=="],
|
||||
|
||||
"which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
|
||||
|
||||
"@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
||||
|
|
@ -890,6 +896,10 @@
|
|||
|
||||
"@workshop/nano-remix/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
|
||||
"@workshop/todo/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
|
||||
"@workshop/werewolf-ui/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
|
||||
"amqplib/readable-stream/inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"amqplib/readable-stream/string_decoder": ["string_decoder@0.10.31", "", {}, "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="],
|
||||
|
|
@ -904,8 +914,6 @@
|
|||
|
||||
"morgan/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"werewolfUI/@types/bun/bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
|
||||
"@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
||||
|
||||
"@modelcontextprotocol/sdk/express/body-parser/bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
||||
|
|
|
|||
1
main.ts
1
main.ts
|
|
@ -27,7 +27,6 @@ try {
|
|||
await Promise.all([run(["bun", "run", "--filter=@workshop/http", "start"]), run(["bun", "bot:discord"])])
|
||||
console.log("✅ All processes completed successfully")
|
||||
} catch (error) {
|
||||
console.log(`🌭`, error.message)
|
||||
console.error("❌ One or more processes failed:", error)
|
||||
process.exit(1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,12 +9,9 @@ type BuildRouteOptions = {
|
|||
|
||||
export const buildRoute = async ({ distDir, routeName, filepath, force = false }: BuildRouteOptions) => {
|
||||
if (!force && !(await shouldRebuild(routeName, filepath, distDir))) {
|
||||
console.log(`🌭 Skipping build for ${routeName} - up to date`)
|
||||
return
|
||||
}
|
||||
|
||||
console.log(`🌭 Building route ${routeName} from ${filepath}`)
|
||||
|
||||
const scriptPath = join(import.meta.dirname, "../scripts/build.ts")
|
||||
|
||||
const proc = Bun.spawn({
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
"@codemirror/autocomplete": "^6.18.6",
|
||||
"@codemirror/commands": "^6.8.1",
|
||||
"@codemirror/language": "^6.11.1",
|
||||
"@codemirror/search": "^6.5.11",
|
||||
"@codemirror/state": "^6.5.2",
|
||||
"@codemirror/view": "^6.37.2",
|
||||
"@lezer/generator": "^1.7.3",
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ const handleNewlineChange = (opts: HandleNewlineChangeOpts) => {
|
|||
userEvent: "delete",
|
||||
})
|
||||
} else {
|
||||
const prefix = `- [ ] `
|
||||
const prefix = `[ ] `
|
||||
opts.update.view.dispatch({
|
||||
changes: { from: insertPos, to: insertPos, insert: prefix },
|
||||
selection: { anchor: insertPos + prefix.length },
|
||||
|
|
|
|||
|
|
@ -4,11 +4,14 @@
|
|||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.todo-completed {
|
||||
text-decoration: line-through !important;
|
||||
.todo-completed * {
|
||||
text-decoration: line-through;
|
||||
color: black !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.todo-completed .todo-indent {
|
||||
text-decoration: none #10B981 !important;
|
||||
}
|
||||
|
||||
@keyframes todoCompleting {
|
||||
|
|
|
|||
|
|
@ -3,26 +3,26 @@ import { Todo } from "@/todo"
|
|||
import { test, expect } from "bun:test"
|
||||
|
||||
test("parsing valid todos", () => {
|
||||
expectTodo("- [ ] some words and that is it", { done: false, text: "some words and that is it" })
|
||||
expectTodo("- [x] has #some #tags and @2/5/25 5m", {
|
||||
expectTodo("[ ] some words and that is it", { done: false, text: "some words and that is it" })
|
||||
expectTodo("[x] has #some #tags and @2/5/25 5m", {
|
||||
done: true,
|
||||
text: "has #some #tags and @2/5/25 5m",
|
||||
tags: ["some", "tags"],
|
||||
timeEstimate: 300,
|
||||
dueDate: DateTime.fromISO("2025-02-05"),
|
||||
})
|
||||
expectTodo("- [ ] works with iso dates @2055/01/2", {
|
||||
expectTodo("[ ] works with iso dates @2055/01/2", {
|
||||
text: "works with iso dates @2055/01/2",
|
||||
dueDate: DateTime.fromISO("2055-01-02"),
|
||||
})
|
||||
expectTodo(" - [ ] handles nested todos", { text: "handles nested todos", indent: " " })
|
||||
expectTodo(" [ ] handles nested todos", { text: "handles nested todos", indent: " " })
|
||||
})
|
||||
|
||||
test("todo nodes", () => {
|
||||
const todo = Todo.parse(" - [ ] some #words and @2/2/25")
|
||||
const todo = Todo.parse(" [ ] some #words and @2/2/25")
|
||||
expect(todo!.nodes).toEqual([
|
||||
{ type: "indent", content: " " },
|
||||
{ type: "checkbox", content: "- [ ] ", checked: false },
|
||||
{ type: "checkbox", content: "[ ] ", checked: false },
|
||||
{ type: "text", content: "some" },
|
||||
{ type: "whitespace", content: " " },
|
||||
{ type: "tag", content: "#words" },
|
||||
|
|
@ -34,18 +34,18 @@ test("todo nodes", () => {
|
|||
})
|
||||
|
||||
test("parsing invalid todos", () => {
|
||||
expectInvalidTodo("- [ ]")
|
||||
expectInvalidTodo(" -[x")
|
||||
expectInvalidTodo("-[omg] some text")
|
||||
expectInvalidTodo("[ ")
|
||||
expectInvalidTodo(" -[]")
|
||||
expectInvalidTodo("-[] some text")
|
||||
})
|
||||
|
||||
// Helpers
|
||||
test("todo to string", () => {
|
||||
const todo = Todo.parse("- [ ] some #words and @2/2/25")
|
||||
expect(todo!.toString()).toBe("- [ ] some #words and @2/2/25")
|
||||
const todo = Todo.parse("[ ] some #words and @2/2/25")
|
||||
expect(todo!.toString()).toBe("[ ] some #words and @2/2/25")
|
||||
|
||||
const nestedTodo = Todo.parse(" - [x] more #words and @2/2/25")
|
||||
expect(nestedTodo!.toString()).toBe(" - [x] more #words and @2/2/25")
|
||||
const nestedTodo = Todo.parse(" [x] more #words and @2/2/25")
|
||||
expect(nestedTodo!.toString()).toBe(" [x] more #words and @2/2/25")
|
||||
})
|
||||
|
||||
const expectTodo = (input: string, expectation: Partial<Todo>) => {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export type TodoJSON = {
|
|||
children: TodoJSON[]
|
||||
}
|
||||
|
||||
export const checkboxRegex = /^\s*-\s*\[\s*(\w?)\s*\]\s*/
|
||||
export const checkboxRegex = /^\s*\[\s*(\w?)\s*\]\s*/
|
||||
|
||||
export class Todo {
|
||||
done: boolean
|
||||
|
|
@ -28,7 +28,7 @@ export class Todo {
|
|||
}
|
||||
|
||||
toString() {
|
||||
let string = `${this.indent}- [${this.done ? "x" : " "}] ${this.text}`
|
||||
let string = `${this.indent}[${this.done ? "x" : " "}] ${this.text}`
|
||||
this.children.forEach((child) => {
|
||||
string += "\n" + child.toString()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { todoClickHandler } from "@/todoClickHandler"
|
|||
import { dateAutocompletion } from "@/dateAutocompletion"
|
||||
import { todoTimer } from "@/todoTimer"
|
||||
import { DateTime } from "luxon"
|
||||
import { searchKeymap } from "@codemirror/search"
|
||||
|
||||
import "./todo.css"
|
||||
|
||||
|
|
@ -44,6 +45,7 @@ const createEditorExtensions = (
|
|||
keymap.of(historyKeymap),
|
||||
keymap.of(defaultKeymap),
|
||||
keymap.of(foldKeymap),
|
||||
keymap.of(searchKeymap),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +122,7 @@ export const TodoEditor = ({ defaultValue, onChange }: TodoEditorProps) => {
|
|||
}
|
||||
|
||||
const KeyboardShortcuts = ({ onClose }: { onClose: () => void }) => {
|
||||
const shortcuts = buildKeyBindings(undefined as any).filter((k) => !k.hidden)
|
||||
const shortcuts = buildKeyBindings(undefined as any).filter((k) => k.label)
|
||||
|
||||
return (
|
||||
<div class="fixed inset-0 bg-[#00000088] z-50" onClick={onClose}>
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ import { type RefObject } from "hono/jsx"
|
|||
import { parseTodoList, todoListToString } from "@/todoList"
|
||||
import { todoTimer } from "./todoTimer"
|
||||
import { triggerTodoCompletionEffect } from "./todoCompletion"
|
||||
import { selectNextOccurrence } from "@codemirror/search"
|
||||
|
||||
export type Command = KeyBinding & { label: string; key: string; hidden?: boolean }
|
||||
export type Command = KeyBinding & { label?: string; key: string }
|
||||
|
||||
export const buildKeyBindings = (
|
||||
filterElRef: RefObject<HTMLInputElement>,
|
||||
|
|
@ -79,9 +80,7 @@ export const buildKeyBindings = (
|
|||
},
|
||||
},
|
||||
{
|
||||
label: "Stop the todo timer",
|
||||
key: "Escape",
|
||||
hidden: true,
|
||||
run: (view: EditorView) => {
|
||||
const timerPlugin = view.plugin(todoTimer)
|
||||
if (timerPlugin?.currentWidget) {
|
||||
|
|
@ -100,13 +99,11 @@ export const buildKeyBindings = (
|
|||
},
|
||||
},
|
||||
{
|
||||
label: "Indent the todo item",
|
||||
key: "Tab",
|
||||
preventDefault: true,
|
||||
run: indentMore,
|
||||
},
|
||||
{
|
||||
label: "Unindent the todo item",
|
||||
key: "Shift-Tab",
|
||||
preventDefault: true,
|
||||
run: indentLess,
|
||||
|
|
|
|||
|
|
@ -30,13 +30,13 @@ test("todoListToString", () => {
|
|||
const result = todoListToString(todoList)
|
||||
|
||||
const expected = `# Today
|
||||
- [ ] a task with a #tag
|
||||
- [x] a #tag and date @2/2/25 in a task
|
||||
[ ] a task with a #tag
|
||||
[x] a #tag and date @2/2/25 in a task
|
||||
# Tomorrow
|
||||
- [ ] another task
|
||||
- [ ] a subtask
|
||||
- [x] completed
|
||||
- [ ] a task with a @1/2/25 date
|
||||
[ ] another task
|
||||
[ ] a subtask
|
||||
[x] completed
|
||||
[ ] a task with a @1/2/25 date
|
||||
`
|
||||
|
||||
expect(result).toEqual(expected)
|
||||
|
|
@ -44,15 +44,15 @@ test("todoListToString", () => {
|
|||
|
||||
test("parseTodoList", () => {
|
||||
const todoListString = `# Today
|
||||
- [ ] a task with a #tag
|
||||
- [x] a #tag and date @2/2/25 in a task
|
||||
[ ] a task with a #tag
|
||||
[x] a #tag and date @2/2/25 in a task
|
||||
|
||||
# Tomorrow
|
||||
- [ ] another task
|
||||
- [ ] a subtask
|
||||
- [x] completed
|
||||
[ ] another task
|
||||
[ ] a subtask
|
||||
[x] completed
|
||||
|
||||
- [ ] a task with a @1/2/25 date`
|
||||
[ ] a task with a @1/2/25 date`
|
||||
|
||||
const result = parseTodoList(todoListString)
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export const todoListToString = (todoList: TodoList): string => {
|
|||
}
|
||||
|
||||
const todoJsonToString = (todoOrString: Todo): string => {
|
||||
let result = `${todoOrString.indent}- [${todoOrString.done ? "x" : " "}] ${todoOrString.text}\n`
|
||||
let result = `${todoOrString.indent}[${todoOrString.done ? "x" : " "}] ${todoOrString.text}\n`
|
||||
|
||||
todoOrString.children.forEach((child) => {
|
||||
result += todoJsonToString(child)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user