diff --git a/apps/client/src/widgets/sidebar/HighlightsList.tsx b/apps/client/src/widgets/sidebar/HighlightsList.tsx index c18f1770b..1755230f8 100644 --- a/apps/client/src/widgets/sidebar/HighlightsList.tsx +++ b/apps/client/src/widgets/sidebar/HighlightsList.tsx @@ -1,7 +1,16 @@ +import { CKTextEditor, ModelTextProxy } from "@triliumnext/ckeditor5"; +import { useEffect, useState } from "preact/hooks"; + import { t } from "../../services/i18n"; -import { useActiveNoteContext, useIsNoteReadOnly, useNoteProperty } from "../react/hooks"; +import { useActiveNoteContext, useIsNoteReadOnly, useNoteProperty, useTextEditor } from "../react/hooks"; import RightPanelWidget from "./RightPanelWidget"; +interface RawHighlight { + id: string; + text: string; + attrs: Record; +} + export default function HighlightsList() { const { note, noteContext } = useActiveNoteContext(); const noteType = useNoteProperty(note, "type"); @@ -15,9 +24,73 @@ export default function HighlightsList() { ); } +function AbstractHighlightsList({ highlights }: { + highlights: RawHighlight[] +}) { + return ( + +
    + {highlights.map(highlight => ( +
  1. + {highlight.text} +
  2. + ))} +
+
+ ); +} + //#region Editable text (CKEditor) +interface CKHighlight extends RawHighlight { + element: ModelTextProxy; +} + function EditableTextHighlightsList() { - return "Editable"; + const { note, noteContext } = useActiveNoteContext(); + const textEditor = useTextEditor(noteContext); + const [ highlights, setHighlights ] = useState([]); + + useEffect(() => { + if (!textEditor) return; + + const highlights = extractHighlightsFromTextEditor(textEditor); + setHighlights(highlights); + }, [ textEditor, note ]); + + return ; +} + +function extractHighlightsFromTextEditor(editor: CKTextEditor) { + const result: CKHighlight[] = []; + const root = editor.model.document.getRoot(); + if (!root) return []; + + for (const { item } of editor.model.createRangeIn(root).getWalker({ ignoreElementEnd: true })) { + if (!item.is('$textProxy')) continue; + console.log("Got ", item); + + const attrs = { + bold: item.hasAttribute('bold'), + italic: item.hasAttribute('italic'), + underline: item.hasAttribute('underline'), + color: item.getAttribute('fontColor'), + background: item.getAttribute('fontBackgroundColor') + }; + console.log("Got ", attrs); + + if (Object.values(attrs).some(Boolean)) { + result.push({ + id: crypto.randomUUID(), + text: item.data, + attrs, + element: item + }); + } + } + + return result; } //#endregion diff --git a/apps/client/src/widgets/sidebar/TableOfContents.tsx b/apps/client/src/widgets/sidebar/TableOfContents.tsx index b6f7553e5..d60d4e8dc 100644 --- a/apps/client/src/widgets/sidebar/TableOfContents.tsx +++ b/apps/client/src/widgets/sidebar/TableOfContents.tsx @@ -114,6 +114,7 @@ function EditableTextTableOfContents() { useEffect(() => { if (!textEditor) return; const headings = extractTocFromTextEditor(textEditor); + setHeadings(headings); // React to changes. const changeCallback = () => { @@ -130,7 +131,6 @@ function EditableTextTableOfContents() { }; textEditor.model.document.on("change:data", changeCallback); - setHeadings(headings); return () => textEditor.model.document.off("change:data", changeCallback); }, [ textEditor, note ]); diff --git a/packages/ckeditor5/src/index.ts b/packages/ckeditor5/src/index.ts index a6b193477..745c428cf 100644 --- a/packages/ckeditor5/src/index.ts +++ b/packages/ckeditor5/src/index.ts @@ -6,7 +6,7 @@ import { BalloonEditor, DecoupledEditor, FindAndReplaceEditing, FindCommand } fr import "./translation_overrides.js"; export { default as EditorWatchdog } from "./custom_watchdog"; export { PREMIUM_PLUGINS } from "./plugins.js"; -export type { EditorConfig, MentionFeed, MentionFeedObjectItem, ModelNode, ModelPosition, ModelElement, WatchdogConfig, WatchdogState } from "ckeditor5"; +export type { EditorConfig, MentionFeed, MentionFeedObjectItem, ModelNode, ModelPosition, ModelElement, ModelTextProxy, WatchdogConfig, WatchdogState } from "ckeditor5"; export type { TemplateDefinition } from "ckeditor5-premium-features"; export { default as buildExtraCommands } from "./extra_slash_commands.js"; export { default as getCkLocale } from "./i18n.js";