From 5e3bdca3eec28eaf1d8242539ea3c6320c519043 Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Tue, 22 Feb 2022 17:36:24 +0100 Subject: [PATCH] Task lists --- notes/start.md | 3 ++- webapp/src/app.tsx | 38 +++++++++++++++++++++++++++++++++++++- webapp/src/customtags.ts | 2 ++ webapp/src/parser.ts | 7 +++++-- webapp/src/style.ts | 2 ++ webapp/src/styles.css | 8 ++++++-- 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/notes/start.md b/notes/start.md index 8c15afc6..3015cc06 100644 --- a/notes/start.md +++ b/notes/start.md @@ -1,3 +1,4 @@ Home page -[[Great Parenting]] \ No newline at end of file +[[Great Parenting]] +[[1:1s]] \ No newline at end of file diff --git a/webapp/src/app.tsx b/webapp/src/app.tsx index bec8032e..5d754f7f 100644 --- a/webapp/src/app.tsx +++ b/webapp/src/app.tsx @@ -28,6 +28,7 @@ import { Action, AppViewState } from "./types"; import { syntaxTree } from "@codemirror/language"; import * as util from "./util"; +import { NoteMeta } from "./types"; const fs = new HttpFileSystem("http://localhost:2222/fs"); @@ -39,10 +40,13 @@ const initialViewState: AppViewState = { allNotes: [], }; +import { CompletionContext, CompletionResult } from "@codemirror/autocomplete"; + class Editor { view: EditorView; currentNote: string; dispatch: React.Dispatch; + allNotes: NoteMeta[]; constructor( parent: Element, @@ -56,6 +60,7 @@ class Editor { }); this.currentNote = currentNote; this.dispatch = dispatch; + this.allNotes = []; } createEditorState(text: string): EditorState { @@ -71,7 +76,9 @@ class Editor { customMarkdownStyle, bracketMatching(), closeBrackets(), - autocompletion(), + autocompletion({ + override: [this.noteCompleter.bind(this)], + }), EditorView.lineWrapping, lineWrapper([ { selector: "ATXHeading1", class: "line-h1" }, @@ -161,6 +168,22 @@ class Editor { }); } + noteCompleter(ctx: CompletionContext): CompletionResult | null { + let prefix = ctx.matchBefore(/\[\[\w*/); + if (!prefix) { + return null; + } + // TODO: Lots of optimization potential here + // TODO: put something in the cm-completionIcon-note style + return { + from: prefix.from + 2, + options: this.allNotes.map((noteMeta) => ({ + label: noteMeta.name, + type: "note", + })), + }; + } + update(value: null, transaction: Transaction): null { if (transaction.docChanged) { this.dispatch({ @@ -184,6 +207,18 @@ class Editor { let noteName = view.state.sliceDoc(node.from, node.to); this.navigate(noteName); } + if (node && node.name === "TaskMarker") { + let checkBoxText = view.state.sliceDoc(node.from, node.to); + if (checkBoxText === "[x]" || checkBoxText === "[X]") { + view.dispatch({ + changes: { from: node.from, to: node.to, insert: "[ ]" }, + }); + } else { + view.dispatch({ + changes: { from: node.from, to: node.to, insert: "[x]" }, + }); + } + } return false; } } @@ -202,6 +237,7 @@ class Editor { async loadNoteList() { let notesMeta = await fs.listNotes(); + this.allNotes = notesMeta; this.dispatch({ type: "notes-listed", notes: notesMeta, diff --git a/webapp/src/customtags.ts b/webapp/src/customtags.ts index 9e26b3ee..337f2fda 100644 --- a/webapp/src/customtags.ts +++ b/webapp/src/customtags.ts @@ -4,3 +4,5 @@ export const WikiLinkTag = Tag.define(); export const WikiLinkPageTag = Tag.define(); export const TagTag = Tag.define(); export const MentionTag = Tag.define(); +export const TaskTag = Tag.define(); +export const TaskMarkerTag = Tag.define(); diff --git a/webapp/src/parser.ts b/webapp/src/parser.ts index c8cdc98a..63c0211c 100644 --- a/webapp/src/parser.ts +++ b/webapp/src/parser.ts @@ -1,5 +1,5 @@ import { styleTags } from "@codemirror/highlight"; -import { MarkdownConfig } from "@lezer/markdown"; +import { MarkdownConfig, TaskList } from "@lezer/markdown"; import { commonmark, mkLang } from "./markdown/markdown"; import * as ct from "./customtags"; @@ -49,7 +49,7 @@ const AtMention: MarkdownConfig = { ], }; const TagLink: MarkdownConfig = { - defineNodes: ["TagLink"], + defineNodes: ["Checkbox"], parseInline: [ { name: "TagLink", @@ -71,6 +71,7 @@ const WikiMarkdown = commonmark.configure([ WikiLink, AtMention, TagLink, + TaskList, { props: [ styleTags({ @@ -78,6 +79,8 @@ const WikiMarkdown = commonmark.configure([ WikiLinkPage: ct.WikiLinkPageTag, AtMention: ct.MentionTag, TagLink: ct.TagTag, + Task: ct.TaskTag, + TaskMarker: ct.TaskMarkerTag, }), ], }, diff --git a/webapp/src/style.ts b/webapp/src/style.ts index 272f3005..9acb6f3b 100644 --- a/webapp/src/style.ts +++ b/webapp/src/style.ts @@ -13,6 +13,8 @@ export default HighlightStyle.define([ { tag: ct.WikiLinkPageTag, class: "wiki-link-page" }, { tag: ct.TagTag, class: "tag" }, { tag: ct.MentionTag, class: "mention" }, + { tag: ct.TaskTag, class: "task" }, + { tag: ct.TaskMarkerTag, class: "task-marker" }, { tag: t.emphasis, class: "emphasis" }, { tag: t.strong, class: "strong" }, { tag: t.atom, class: "atom" }, diff --git a/webapp/src/styles.css b/webapp/src/styles.css index 0610a79b..74daa767 100644 --- a/webapp/src/styles.css +++ b/webapp/src/styles.css @@ -1,8 +1,8 @@ :root { --ident: 18px; - --editor-font: "Avenir"; + /* --editor-font: "Avenir"; */ + --editor-font: "Menlo"; --top-bar-bg: rgb(41, 41, 41); - /* --editor-font: "Menlo"; */ } html, @@ -148,6 +148,10 @@ body { margin-left: var(--ident); } +.cm-editor .task-marker { + background-color: #ddd; +} + .current-note { font-family: var(--editor-font); margin-left: 10px;