Task lists
parent
84fcd0aeed
commit
5e3bdca3ee
|
@ -1,3 +1,4 @@
|
||||||
Home page
|
Home page
|
||||||
|
|
||||||
[[Great Parenting]]
|
[[Great Parenting]]
|
||||||
|
[[1:1s]]
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -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" },
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue