feat(right_pane): render title bar

This commit is contained in:
Elian Doran 2025-12-20 10:33:28 +02:00
parent 8f1614f603
commit aac4316fb8
No known key found for this signature in database
3 changed files with 51 additions and 16 deletions

View File

@ -605,10 +605,11 @@ export function useNoteBlob(note: FNote | null | undefined, componentId?: string
return blob; return blob;
} }
export function useLegacyWidget<T extends BasicWidget>(widgetFactory: () => T, { noteContext, containerClassName, containerStyle }: { export function useLegacyWidget<T extends BasicWidget>(widgetFactory: () => T, { noteContext, containerClassName, containerStyle, noAttach }: {
noteContext?: NoteContext; noteContext?: NoteContext;
containerClassName?: string; containerClassName?: string;
containerStyle?: CSSProperties; containerStyle?: CSSProperties;
noAttach?: boolean;
} = {}): [VNode, T] { } = {}): [VNode, T] {
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
const parentComponent = useContext(ParentComponent); const parentComponent = useContext(ParentComponent);
@ -627,22 +628,24 @@ export function useLegacyWidget<T extends BasicWidget>(widgetFactory: () => T, {
const renderedWidget = widget.render(); const renderedWidget = widget.render();
return [ widget, renderedWidget ]; return [ widget, renderedWidget ];
}, []); }, [ noteContext, parentComponent, widgetFactory]);
// Attach the widget to the parent. // Attach the widget to the parent.
useEffect(() => { useEffect(() => {
if (ref.current) { if (noAttach) return;
ref.current.innerHTML = ""; const parentContainer = ref.current;
renderedWidget.appendTo(ref.current); if (parentContainer) {
parentContainer.replaceChildren();
renderedWidget.appendTo(parentContainer);
} }
}, [ renderedWidget ]); }, [ renderedWidget, noAttach ]);
// Inject the note context. // Inject the note context.
useEffect(() => { useEffect(() => {
if (noteContext && widget instanceof NoteContextAwareWidget) { if (noteContext && widget instanceof NoteContextAwareWidget) {
widget.activeContextChangedEvent({ noteContext }); widget.activeContextChangedEvent({ noteContext });
} }
}, [ noteContext ]); }, [ noteContext, widget ]);
useDebugValue(widget); useDebugValue(widget);

View File

@ -2,7 +2,7 @@
import "./RightPanelContainer.css"; import "./RightPanelContainer.css";
import Split from "@triliumnext/split.js"; import Split from "@triliumnext/split.js";
import { useEffect } from "preact/hooks"; import { useEffect, useRef } from "preact/hooks";
import { t } from "../../services/i18n"; import { t } from "../../services/i18n";
import options from "../../services/options"; import options from "../../services/options";
@ -11,7 +11,9 @@ import BasicWidget from "../basic_widget";
import Button from "../react/Button"; import Button from "../react/Button";
import { useActiveNoteContext, useLegacyWidget, useNoteProperty, useTriliumOptionBool, useTriliumOptionJson } from "../react/hooks"; import { useActiveNoteContext, useLegacyWidget, useNoteProperty, useTriliumOptionBool, useTriliumOptionJson } from "../react/hooks";
import Icon from "../react/Icon"; import Icon from "../react/Icon";
import LegacyRightPanelWidget from "../right_panel_widget";
import HighlightsList from "./HighlightsList"; import HighlightsList from "./HighlightsList";
import RightPanelWidget from "./RightPanelWidget";
import TableOfContents from "./TableOfContents"; import TableOfContents from "./TableOfContents";
const MIN_WIDTH_PERCENT = 5; const MIN_WIDTH_PERCENT = 5;
@ -67,7 +69,36 @@ function useSplit(visible: boolean) {
}, [ visible ]); }, [ visible ]);
} }
function CustomWidget({ originalWidget }: { originalWidget: BasicWidget }) { function CustomWidget({ originalWidget }: { originalWidget: LegacyRightPanelWidget }) {
const [ el ] = useLegacyWidget(() => originalWidget); const containerRef = useRef<HTMLDivElement>(null);
return <>{el}</>; const [ el ] = useLegacyWidget(() => {
// Monkey-patch the original widget by replacing the default initialization logic.
originalWidget.doRender = function doRender(this: LegacyRightPanelWidget) {
if (!containerRef.current) {
this.$widget = $("<div>");
return;
};
this.$widget = $(containerRef.current);
this.$body = this.$widget.find(".card-body");
const renderResult = this.doRenderBody();
if (typeof renderResult === "object" && "catch" in renderResult) {
this.initialized = renderResult.catch((e) => {
this.logRenderingError(e);
});
} else {
this.initialized = Promise.resolve();
}
};
return originalWidget;
}, {
noAttach: true
});
return (
<RightPanelWidget
id={originalWidget._noteId}
title={originalWidget.widgetTitle}
containerRef={containerRef}
>{el}</RightPanelWidget>
);
} }

View File

@ -1,8 +1,8 @@
import clsx from "clsx"; import clsx from "clsx";
import { ComponentChildren } from "preact"; import { ComponentChildren, RefObject } from "preact";
import { useContext, useRef, useState } from "preact/hooks"; import { useContext, useState } from "preact/hooks";
import { useTriliumOptionJson } from "../react/hooks"; import { useSyncedRef, useTriliumOptionJson } from "../react/hooks";
import Icon from "../react/Icon"; import Icon from "../react/Icon";
import { ParentComponent } from "../react/react_utils"; import { ParentComponent } from "../react/react_utils";
@ -11,12 +11,13 @@ interface RightPanelWidgetProps {
title: string; title: string;
children: ComponentChildren; children: ComponentChildren;
buttons?: ComponentChildren; buttons?: ComponentChildren;
containerRef?: RefObject<HTMLDivElement>;
} }
export default function RightPanelWidget({ id, title, buttons, children }: RightPanelWidgetProps) { export default function RightPanelWidget({ id, title, buttons, children, containerRef: externalContainerRef }: RightPanelWidgetProps) {
const [ rightPaneCollapsedItems, setRightPaneCollapsedItems ] = useTriliumOptionJson<string[]>("rightPaneCollapsedItems"); const [ rightPaneCollapsedItems, setRightPaneCollapsedItems ] = useTriliumOptionJson<string[]>("rightPaneCollapsedItems");
const [ expanded, setExpanded ] = useState(!rightPaneCollapsedItems.includes(id)); const [ expanded, setExpanded ] = useState(!rightPaneCollapsedItems.includes(id));
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useSyncedRef<HTMLDivElement>(externalContainerRef, null);
const parentComponent = useContext(ParentComponent); const parentComponent = useContext(ParentComponent);
if (parentComponent) { if (parentComponent) {