From 587ea42700c5c2abe81fe0b82cb9f5e7a1849449 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Tue, 16 Dec 2025 09:27:40 +0200 Subject: [PATCH] chore(breadcrumb): get a menu to render on note link --- apps/client/src/widgets/layout/Breadcrumb.tsx | 18 +++++++++++++++++- apps/client/src/widgets/react/NoteLink.tsx | 11 ++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/client/src/widgets/layout/Breadcrumb.tsx b/apps/client/src/widgets/layout/Breadcrumb.tsx index a814fb13a..7358fa93e 100644 --- a/apps/client/src/widgets/layout/Breadcrumb.tsx +++ b/apps/client/src/widgets/layout/Breadcrumb.tsx @@ -6,6 +6,7 @@ import { Fragment } from "preact/jsx-runtime"; import appContext from "../../components/app_context"; import NoteContext from "../../components/note_context"; import FNote from "../../entities/fnote"; +import contextMenu from "../../menus/context_menu"; import link_context_menu from "../../menus/link_context_menu"; import { getReadableTextColor } from "../../services/css_class_manager"; import froca from "../../services/froca"; @@ -150,7 +151,22 @@ function BreadcrumbItem({ index, notePath, noteContext, notePathLength }: { inde ; } - return ; + return { + e.preventDefault(); + contextMenu.show({ + items: [ + { + title: "Foo" + } + ], + x: e.pageX, + y: e.pageY + }); + }} + />; } function BreadcrumbSeparator({ notePath, noteContext, activeNotePath }: { notePath: string, activeNotePath: string, noteContext: NoteContext | undefined }) { diff --git a/apps/client/src/widgets/react/NoteLink.tsx b/apps/client/src/widgets/react/NoteLink.tsx index 7c3578db7..3f7fbbdc0 100644 --- a/apps/client/src/widgets/react/NoteLink.tsx +++ b/apps/client/src/widgets/react/NoteLink.tsx @@ -1,4 +1,5 @@ import { useEffect, useRef, useState } from "preact/hooks"; + import link, { ViewScope } from "../../services/link"; import { useImperativeSearchHighlighlighting, useTriliumEvent } from "./hooks"; @@ -16,9 +17,10 @@ interface NoteLinkOpts { title?: string; viewScope?: ViewScope; noContextMenu?: boolean; + onContextMenu?: (e: MouseEvent) => void; } -export default function NoteLink({ className, containerClassName, notePath, showNotePath, showNoteIcon, style, noPreview, noTnLink, highlightedTokens, title, viewScope, noContextMenu }: NoteLinkOpts) { +export default function NoteLink({ className, containerClassName, notePath, showNotePath, showNoteIcon, style, noPreview, noTnLink, highlightedTokens, title, viewScope, noContextMenu, onContextMenu }: NoteLinkOpts) { const stringifiedNotePath = Array.isArray(notePath) ? notePath.join("/") : notePath; const noteId = stringifiedNotePath.split("/").at(-1); const ref = useRef(null); @@ -35,6 +37,13 @@ export default function NoteLink({ className, containerClassName, notePath, show }).then(setJqueryEl); }, [ stringifiedNotePath, showNotePath, title, viewScope, noteTitle ]); + useEffect(() => { + const el = jqueryEl?.[0]; + if (!el || !onContextMenu) return; + el.addEventListener("contextmenu", onContextMenu); + return () => el.removeEventListener("contextmenu", onContextMenu); + }, [ jqueryEl, onContextMenu ]); + useEffect(() => { if (!ref.current || !jqueryEl) return; ref.current.replaceChildren(jqueryEl[0]);