Add Obsidian-like full-featured editor toolbar

This commit is contained in:
avi 2026-08-17 14:34:36 -05:00
commit 11dd692ec4
10 changed files with 1211 additions and 28 deletions

View file

@ -158,10 +158,55 @@ const BOOK_DIR = __BOOKDIR_VALUE__;
changes: { from: 0, to: 0, insert: "line one\nline two\n" },
selection: { anchor: 0, head: 16 },
});
document.querySelector('[data-cmd="code"]').click();
document.querySelector('[data-cmd="codeblock"]').click();
await new Promise((r) => setTimeout(r, 50));
out.fencedCodeOk = cm.state.doc.toString().startsWith("```\nline one\nline two\n```");
// underline shortcut (Ctrl+U)
cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: "" } });
cm.dispatch({ changes: { from: 0, to: 0, insert: "Under me" }, selection: { anchor: 0, head: 5 } });
cm.contentDOM.dispatchEvent(
new KeyboardEvent("keydown", { key: "u", ctrlKey: true, bubbles: true, cancelable: true })
);
await new Promise((r) => setTimeout(r, 50));
out.underlineOk = cm.state.doc.toString().startsWith("<u>Under</u>");
// task list via toolbar
cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: "" } });
cm.dispatch({ changes: { from: 0, to: 0, insert: "task one\ntask two" }, selection: { anchor: 0, head: 8 } });
document.querySelector('[data-cmd="checklist"]').click();
await new Promise((r) => setTimeout(r, 50));
out.checklistOk = cm.state.doc.toString().startsWith("- [ ] task one");
// highlight via toolbar
cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: "" } });
cm.dispatch({ changes: { from: 0, to: 0, insert: "cell text" }, selection: { anchor: 0, head: 4 } });
document.querySelector('[data-cmd="highlight"]').click();
await new Promise((r) => setTimeout(r, 50));
out.highlightOk = cm.state.doc.toString().startsWith("==cell==");
// table via toolbar dropdown config
cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: "" } });
document.getElementById("tableRows").value = "3";
document.getElementById("tableCols").value = "2";
document.querySelector('[data-action="table"]').click();
await new Promise((r) => setTimeout(r, 50));
out.tableOk = cm.state.doc.toString().startsWith("| Col 1 | Col 2 |\n| --- | --- |");
// format painter
cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: "" } });
cm.dispatch({ changes: { from: 0, to: 0, insert: "**src** dst" }, selection: { anchor: 3, head: 3 } });
document.querySelector('[data-cmd="painter"]').click();
cm.dispatch({ selection: { anchor: 8, head: 11 } });
document.querySelector('[data-cmd="painter"]').click();
await new Promise((r) => setTimeout(r, 50));
out.painterOk = cm.state.doc.toString() === "**src** **dst**";
// leave some formatted content on disk for the autosave check
cm.dispatch({
changes: { from: 0, to: cm.state.doc.length, insert: "**Hello** World" },
selection: { anchor: 0 },
});
await new Promise((r) => setTimeout(r, 1200)); // wait for autosave debounce
out.formattingAutosaved =
(await window.folio.getChapterContent(typedId)).includes("**Hello**");
@ -182,6 +227,11 @@ const BOOK_DIR = __BOOKDIR_VALUE__;
"redoOk",
"strikeShortcutOk",
"fencedCodeOk",
"underlineOk",
"checklistOk",
"highlightOk",
"tableOk",
"painterOk",
"formattingAutosaved",
];
out.all = okFlags.every((f) => out[f] === true);