Task lists

pull/3/head
Zef Hemel 2022-02-22 17:36:24 +01:00
parent 84fcd0aeed
commit 5e3bdca3ee
6 changed files with 54 additions and 6 deletions

View File

@ -1,3 +1,4 @@
Home page Home page
[[Great Parenting]] [[Great Parenting]]
[[1:1s]]

View File

@ -28,6 +28,7 @@ import { Action, AppViewState } from "./types";
import { syntaxTree } from "@codemirror/language"; import { syntaxTree } from "@codemirror/language";
import * as util from "./util"; import * as util from "./util";
import { NoteMeta } from "./types";
const fs = new HttpFileSystem("http://localhost:2222/fs"); const fs = new HttpFileSystem("http://localhost:2222/fs");
@ -39,10 +40,13 @@ const initialViewState: AppViewState = {
allNotes: [], allNotes: [],
}; };
import { CompletionContext, CompletionResult } from "@codemirror/autocomplete";
class Editor { class Editor {
view: EditorView; view: EditorView;
currentNote: string; currentNote: string;
dispatch: React.Dispatch<Action>; dispatch: React.Dispatch<Action>;
allNotes: NoteMeta[];
constructor( constructor(
parent: Element, parent: Element,
@ -56,6 +60,7 @@ class Editor {
}); });
this.currentNote = currentNote; this.currentNote = currentNote;
this.dispatch = dispatch; this.dispatch = dispatch;
this.allNotes = [];
} }
createEditorState(text: string): EditorState { createEditorState(text: string): EditorState {
@ -71,7 +76,9 @@ class Editor {
customMarkdownStyle, customMarkdownStyle,
bracketMatching(), bracketMatching(),
closeBrackets(), closeBrackets(),
autocompletion(), autocompletion({
override: [this.noteCompleter.bind(this)],
}),
EditorView.lineWrapping, EditorView.lineWrapping,
lineWrapper([ lineWrapper([
{ selector: "ATXHeading1", class: "line-h1" }, { 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 { update(value: null, transaction: Transaction): null {
if (transaction.docChanged) { if (transaction.docChanged) {
this.dispatch({ this.dispatch({
@ -184,6 +207,18 @@ class Editor {
let noteName = view.state.sliceDoc(node.from, node.to); let noteName = view.state.sliceDoc(node.from, node.to);
this.navigate(noteName); 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; return false;
} }
} }
@ -202,6 +237,7 @@ class Editor {
async loadNoteList() { async loadNoteList() {
let notesMeta = await fs.listNotes(); let notesMeta = await fs.listNotes();
this.allNotes = notesMeta;
this.dispatch({ this.dispatch({
type: "notes-listed", type: "notes-listed",
notes: notesMeta, notes: notesMeta,

View File

@ -4,3 +4,5 @@ export const WikiLinkTag = Tag.define();
export const WikiLinkPageTag = Tag.define(); export const WikiLinkPageTag = Tag.define();
export const TagTag = Tag.define(); export const TagTag = Tag.define();
export const MentionTag = Tag.define(); export const MentionTag = Tag.define();
export const TaskTag = Tag.define();
export const TaskMarkerTag = Tag.define();

View File

@ -1,5 +1,5 @@
import { styleTags } from "@codemirror/highlight"; import { styleTags } from "@codemirror/highlight";
import { MarkdownConfig } from "@lezer/markdown"; import { MarkdownConfig, TaskList } from "@lezer/markdown";
import { commonmark, mkLang } from "./markdown/markdown"; import { commonmark, mkLang } from "./markdown/markdown";
import * as ct from "./customtags"; import * as ct from "./customtags";
@ -49,7 +49,7 @@ const AtMention: MarkdownConfig = {
], ],
}; };
const TagLink: MarkdownConfig = { const TagLink: MarkdownConfig = {
defineNodes: ["TagLink"], defineNodes: ["Checkbox"],
parseInline: [ parseInline: [
{ {
name: "TagLink", name: "TagLink",
@ -71,6 +71,7 @@ const WikiMarkdown = commonmark.configure([
WikiLink, WikiLink,
AtMention, AtMention,
TagLink, TagLink,
TaskList,
{ {
props: [ props: [
styleTags({ styleTags({
@ -78,6 +79,8 @@ const WikiMarkdown = commonmark.configure([
WikiLinkPage: ct.WikiLinkPageTag, WikiLinkPage: ct.WikiLinkPageTag,
AtMention: ct.MentionTag, AtMention: ct.MentionTag,
TagLink: ct.TagTag, TagLink: ct.TagTag,
Task: ct.TaskTag,
TaskMarker: ct.TaskMarkerTag,
}), }),
], ],
}, },

View File

@ -13,6 +13,8 @@ export default HighlightStyle.define([
{ tag: ct.WikiLinkPageTag, class: "wiki-link-page" }, { tag: ct.WikiLinkPageTag, class: "wiki-link-page" },
{ tag: ct.TagTag, class: "tag" }, { tag: ct.TagTag, class: "tag" },
{ tag: ct.MentionTag, class: "mention" }, { tag: ct.MentionTag, class: "mention" },
{ tag: ct.TaskTag, class: "task" },
{ tag: ct.TaskMarkerTag, class: "task-marker" },
{ tag: t.emphasis, class: "emphasis" }, { tag: t.emphasis, class: "emphasis" },
{ tag: t.strong, class: "strong" }, { tag: t.strong, class: "strong" },
{ tag: t.atom, class: "atom" }, { tag: t.atom, class: "atom" },

View File

@ -1,8 +1,8 @@
:root { :root {
--ident: 18px; --ident: 18px;
--editor-font: "Avenir"; /* --editor-font: "Avenir"; */
--editor-font: "Menlo";
--top-bar-bg: rgb(41, 41, 41); --top-bar-bg: rgb(41, 41, 41);
/* --editor-font: "Menlo"; */
} }
html, html,
@ -148,6 +148,10 @@ body {
margin-left: var(--ident); margin-left: var(--ident);
} }
.cm-editor .task-marker {
background-color: #ddd;
}
.current-note { .current-note {
font-family: var(--editor-font); font-family: var(--editor-font);
margin-left: 10px; margin-left: 10px;