From f1bb786a4969b3dfec20dd48b69d87d3a904ef5b Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 14 Dec 2025 23:22:59 +0200 Subject: [PATCH] chore(layout): support for similar notes in the status bar --- .../src/translations/en/translation.json | 3 +- apps/client/src/widgets/layout/StatusBar.css | 4 ++- apps/client/src/widgets/layout/StatusBar.tsx | 33 +++++++++++++++++-- .../src/widgets/ribbon/SimilarNotesTab.tsx | 21 ++++++------ 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 3d9676f72..9ecdcd640 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -826,7 +826,8 @@ "note_size_info": "Note size provides rough estimate of storage requirements for this note. It takes into account note's content and content of its note revisions.", "calculate": "calculate", "subtree_size": "(subtree size: {{size}} in {{count}} notes)", - "title": "Note Info" + "title": "Note Info", + "show_similar_notes": "Show similar notes" }, "note_map": { "open_full": "Expand to full", diff --git a/apps/client/src/widgets/layout/StatusBar.css b/apps/client/src/widgets/layout/StatusBar.css index 650b4bdd3..431ca62a9 100644 --- a/apps/client/src/widgets/layout/StatusBar.css +++ b/apps/client/src/widgets/layout/StatusBar.css @@ -57,9 +57,11 @@ } .dropdown-note-info { + padding: 1em !important; + ul { list-style-type: none; - padding: 0.5em; + padding: 0; margin: 0; display: table; diff --git a/apps/client/src/widgets/layout/StatusBar.tsx b/apps/client/src/widgets/layout/StatusBar.tsx index 3f136a9a0..6a154730a 100644 --- a/apps/client/src/widgets/layout/StatusBar.tsx +++ b/apps/client/src/widgets/layout/StatusBar.tsx @@ -1,6 +1,7 @@ import "./StatusBar.css"; import { Locale } from "@triliumnext/commons"; +import { Dropdown as BootstrapDropdown } from "bootstrap"; import clsx from "clsx"; import { type ComponentChildren } from "preact"; import { createPortal } from "preact/compat"; @@ -16,16 +17,19 @@ import server from "../../services/server"; import { openInAppHelpFromUrl } from "../../services/utils"; import { formatDateTime } from "../../utils/formatters"; import { BacklinksList, useBacklinkCount } from "../FloatingButtonsDefinitions"; +import Collapsible from "../react/Collapsible"; import Dropdown, { DropdownProps } from "../react/Dropdown"; import { FormDropdownDivider, FormListItem } from "../react/FormList"; import { useActiveNoteContext, useLegacyImperativeHandlers, useNoteLabel, useNoteProperty, useStaticTooltip, useTriliumEvent, useTriliumEvents } from "../react/hooks"; import Icon from "../react/Icon"; +import LinkButton from "../react/LinkButton"; import { ParentComponent } from "../react/react_utils"; import { ContentLanguagesModal, NoteTypeCodeNoteList, NoteTypeOptionsModal, useLanguageSwitcher, useMimeTypes } from "../ribbon/BasicPropertiesTab"; import AttributeEditor, { AttributeEditorImperativeHandlers } from "../ribbon/components/AttributeEditor"; import InheritedAttributesTab from "../ribbon/InheritedAttributesTab"; import { NoteSizeWidget, useNoteMetadata } from "../ribbon/NoteInfoTab"; import { NotePathsWidget, useSortedNotePaths } from "../ribbon/NotePathsTab"; +import SimilarNotesTab from "../ribbon/SimilarNotesTab"; import { useAttachments } from "../type_widgets/Attachment"; import { useProcessedLocales } from "../type_widgets/options/components/LocaleSelector"; import Breadcrumb from "./Breadcrumb"; @@ -41,6 +45,7 @@ interface StatusBarContext { export default function StatusBar() { const { note, notePath, noteContext, viewScope, hoistedNoteId } = useActiveNoteContext(); const [ attributesShown, setAttributesShown ] = useState(false); + const [ similarNotesShown, setSimilarNotesShown ] = useState(false); const context: StatusBarContext | undefined | null = note && noteContext && { note, notePath, noteContext, viewScope, hoistedNoteId }; const attributesContext: AttributesProps | undefined | null = context && { ...context, attributesShown, setAttributesShown }; const isHiddenNote = note?.isInHiddenSubtree(); @@ -48,6 +53,7 @@ export default function StatusBar() { return (
{attributesContext && } + {context && }
{context && attributesContext && <> @@ -60,7 +66,7 @@ export default function StatusBar() { - + setSimilarNotesShown(true)} />
}
@@ -197,7 +203,10 @@ export function getLocaleName(locale: Locale | null | undefined) { //#endregion //#region Note info -export function NoteInfoBadge({ note }: { note: FNote | null | undefined }) { +export function NoteInfoBadge({ note, showSimilarNotes }: StatusBarContext & { + showSimilarNotes: () => void +}) { + const dropdownRef = useRef(null); const { metadata, ...sizeProps } = useNoteMetadata(note); const [ originalFileName ] = useNoteLabel(note, "originalFileName"); @@ -205,6 +214,7 @@ export function NoteInfoBadge({ note }: { note: FNote | null | undefined }) { @@ -216,6 +226,14 @@ export function NoteInfoBadge({ note }: { note: FNote | null | undefined }) { {note.noteId}} /> } /> + + { + dropdownRef.current?.hide(); + showSimilarNotes(); + }} + /> ); } @@ -228,6 +246,17 @@ function NoteInfoValue({ text, title, value }: { text: string; title?: string, v ); } + +function SimilarNotesPane({ note, shown }: StatusBarContext & { + shown: boolean; + setShown: (value: boolean) => void; +}) { + return (shown && +
+ +
+ ); +} //#endregion //#region Backlinks diff --git a/apps/client/src/widgets/ribbon/SimilarNotesTab.tsx b/apps/client/src/widgets/ribbon/SimilarNotesTab.tsx index e324c5d1d..c8dc1337f 100644 --- a/apps/client/src/widgets/ribbon/SimilarNotesTab.tsx +++ b/apps/client/src/widgets/ribbon/SimilarNotesTab.tsx @@ -1,12 +1,13 @@ -import { useEffect, useState } from "preact/hooks"; -import { TabContext } from "./ribbon-interface"; import { SimilarNoteResponse } from "@triliumnext/commons"; -import server from "../../services/server"; -import { t } from "../../services/i18n"; -import froca from "../../services/froca"; -import NoteLink from "../react/NoteLink"; +import { useEffect, useState } from "preact/hooks"; -export default function SimilarNotesTab({ note }: TabContext) { +import froca from "../../services/froca"; +import { t } from "../../services/i18n"; +import server from "../../services/server"; +import NoteLink from "../react/NoteLink"; +import { TabContext } from "./ribbon-interface"; + +export default function SimilarNotesTab({ note }: Pick) { const [ similarNotes, setSimilarNotes ] = useState(); useEffect(() => { @@ -17,7 +18,7 @@ export default function SimilarNotesTab({ note }: TabContext) { await froca.getNotes(noteIds, true); // preload all at once } setSimilarNotes(similarNotes); - }); + }); } }, [ note?.noteId ]); @@ -42,5 +43,5 @@ export default function SimilarNotesTab({ note }: TabContext) { )} - ) -} \ No newline at end of file + ); +}