feat(highlights): render highlighted equations in new layout

This commit is contained in:
Elian Doran
2026-04-10 23:03:30 +03:00
parent 3d2fa57873
commit d3c596aaa0

View File

@@ -1,11 +1,13 @@
import { CKTextEditor, ModelText } from "@triliumnext/ckeditor5";
import { createPortal } from "preact/compat";
import { useCallback, useEffect, useState } from "preact/hooks";
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
import { t } from "../../services/i18n";
import math from "../../services/math";
import { randomString } from "../../services/utils";
import { useActiveNoteContext, useContentElement, useIsNoteReadOnly, useNoteProperty, useTextEditor, useTriliumOptionJson } from "../react/hooks";
import Modal from "../react/Modal";
import RawHtml from "../react/RawHtml";
import { HighlightsListOptions } from "../type_widgets/options/text_notes";
import RightPanelWidget from "./RightPanelWidget";
@@ -84,20 +86,11 @@ function AbstractHighlightsList<T extends RawHighlight>({ highlights, scrollToHi
{filteredHighlights.length > 0 ? (
<ol>
{filteredHighlights.map(highlight => (
<li
<HighlightItem
key={highlight.id}
highlight={highlight}
onClick={() => scrollToHighlight(highlight)}
>
<span
style={{
fontWeight: highlight.attrs.bold ? "700" : undefined,
fontStyle: highlight.attrs.italic ? "italic" : undefined,
textDecoration: highlight.attrs.underline ? "underline" : undefined,
color: highlight.attrs.color,
backgroundColor: highlight.attrs.background
}}
>{highlight.text}</span>
</li>
/>
))}
</ol>
) : (
@@ -112,6 +105,43 @@ function AbstractHighlightsList<T extends RawHighlight>({ highlights, scrollToHi
);
}
function HighlightItem<T extends RawHighlight>({ highlight, onClick }: {
highlight: T;
onClick(): void;
}) {
const contentRef = useRef<HTMLElement>(null);
// Render math equations after component mounts/updates
useEffect(() => {
if (!contentRef.current) return;
const mathElements = contentRef.current.querySelectorAll(".math-tex");
for (const mathEl of mathElements ?? []) {
try {
math.render(mathEl.textContent || "", mathEl as HTMLElement);
} catch (e) {
console.warn("Failed to render math in highlights:", e);
}
}
}, [highlight.text]);
return (
<li onClick={onClick}>
<RawHtml
containerRef={contentRef}
style={{
fontWeight: highlight.attrs.bold ? "700" : undefined,
fontStyle: highlight.attrs.italic ? "italic" : undefined,
textDecoration: highlight.attrs.underline ? "underline" : undefined,
color: highlight.attrs.color,
backgroundColor: highlight.attrs.background
}}
html={highlight.text}
/>
</li>
);
}
//#region Editable text (CKEditor)
interface CKHighlight extends RawHighlight {
textNode: ModelText;
@@ -201,9 +231,23 @@ function extractHighlightsFromTextEditor(editor: CKTextEditor) {
};
if (Object.values(attrs).some(Boolean)) {
// Get HTML content from DOM (includes nested elements like math)
let html = item.data;
const modelPos = editor.model.createPositionAt(item.textNode, "before");
const viewPos = editor.editing.mapper.toViewPosition(modelPos);
const domPos = editor.editing.view.domConverter.viewPositionToDom(viewPos);
if (domPos?.parent instanceof HTMLElement) {
// Get the formatting span's innerHTML (includes math elements)
html = domPos.parent.innerHTML;
}
// Skip if we already have this exact content (same parent element)
const prev = result[result.length - 1];
if (prev?.text === html) continue;
result.push({
id: randomString(),
text: item.data,
text: html,
attrs,
textNode: item.textNode,
offset: item.startOffset