From bf5c56a61ad3c4da03ece2e9c0ed53a12ecb7c83 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 18 Dec 2025 12:04:42 +0200 Subject: [PATCH] chore(toc): reintroduce navigation in editable text notes --- .../src/widgets/sidebar/TableOfContents.tsx | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/apps/client/src/widgets/sidebar/TableOfContents.tsx b/apps/client/src/widgets/sidebar/TableOfContents.tsx index 696e37e56..b84a138bf 100644 --- a/apps/client/src/widgets/sidebar/TableOfContents.tsx +++ b/apps/client/src/widgets/sidebar/TableOfContents.tsx @@ -2,7 +2,7 @@ import "./TableOfContents.css"; import { CKTextEditor, ModelElement } from "@triliumnext/ckeditor5"; import clsx from "clsx"; -import { useEffect, useState } from "preact/hooks"; +import { useCallback, useEffect, useState } from "preact/hooks"; import { t } from "../../services/i18n"; import { useActiveNoteContext, useContentElement, useIsNoteReadOnly, useNoteProperty, useTextEditor } from "../react/hooks"; @@ -33,20 +33,25 @@ export default function TableOfContents() { ); } -function AbstractTableOfContents({ headings }: { +function AbstractTableOfContents({ headings, scrollToHeading }: { headings: RawHeading[]; + scrollToHeading(heading: RawHeading): void; }) { const nestedHeadings = buildHeadingTree(headings); return (
    - {nestedHeadings.map(heading => )} + {nestedHeadings.map(heading => )}
); } -function TableOfContentsHeading({ heading }: { heading: HeadingsWithNesting }) { +function TableOfContentsHeading({ heading, scrollToHeading }: { + heading: HeadingsWithNesting; + scrollToHeading(heading: RawHeading): void; +}) { + console.log("Got ", scrollToHeading); const [ collapsed, setCollapsed ] = useState(false); return ( <> @@ -58,11 +63,14 @@ function TableOfContentsHeading({ heading }: { heading: HeadingsWithNesting }) { onClick={() => setCollapsed(!collapsed)} /> )} - {heading.text} + scrollToHeading(heading)} + >{heading.text} {heading.children && (
    - {heading.children.map(heading => )} + {heading.children.map(heading => )}
)} @@ -128,7 +136,20 @@ function EditableTextTableOfContents() { return () => textEditor.model.document.off("change:data", changeCallback); }, [ textEditor, note ]); - return ; + const scrollToHeading = useCallback((heading: CKHeading) => { + if (!textEditor) return; + + const viewEl = textEditor.editing.mapper.toViewElement(heading.element); + if (!viewEl) return; + + const domEl = textEditor.editing.view.domConverter.mapViewToDom(viewEl); + domEl?.scrollIntoView(); + }, [ textEditor ]); + + return ; } function extractTocFromTextEditor(editor: CKTextEditor) {