feat(status_bar): note paths (no interaction yet)

This commit is contained in:
Elian Doran 2025-12-12 23:47:31 +02:00
parent 9eb9b66398
commit 0c1c7e4f8e
No known key found for this signature in database
3 changed files with 48 additions and 22 deletions

View File

@ -2162,6 +2162,7 @@
"attachments_title_other": "This note has {{count}} attachments. Click to open the list of attachments in a new tab.", "attachments_title_other": "This note has {{count}} attachments. Click to open the list of attachments in a new tab.",
"attributes_one": "{{count}} attribute", "attributes_one": "{{count}} attribute",
"attributes_other": "{{count}} attributes", "attributes_other": "{{count}} attributes",
"attributes_title": "Click to open a dedicated pane to edit this note's owned attributes, as well as to see the list of inherited attributes." "attributes_title": "Click to open a dedicated pane to edit this note's owned attributes, as well as to see the list of inherited attributes.",
"note_paths_title": "Click to see the paths where this note is placed into the tree."
} }
} }

View File

@ -27,17 +27,19 @@ import { NoteSizeWidget, useNoteMetadata } from "../ribbon/NoteInfoTab";
import { useAttachments } from "../type_widgets/Attachment"; import { useAttachments } from "../type_widgets/Attachment";
import { useProcessedLocales } from "../type_widgets/options/components/LocaleSelector"; import { useProcessedLocales } from "../type_widgets/options/components/LocaleSelector";
import Breadcrumb from "./Breadcrumb"; import Breadcrumb from "./Breadcrumb";
import NotePathsTab, { useSortedNotePaths } from "../ribbon/NotePathsTab";
interface StatusBarContext { interface StatusBarContext {
note: FNote; note: FNote;
noteContext: NoteContext; noteContext: NoteContext;
viewScope?: ViewScope; viewScope?: ViewScope;
hoistedNoteId?: string;
} }
export default function StatusBar() { export default function StatusBar() {
const { note, noteContext, viewScope } = useActiveNoteContext(); const { note, noteContext, viewScope, hoistedNoteId } = useActiveNoteContext();
const [ attributesShown, setAttributesShown ] = useState(false); const [ attributesShown, setAttributesShown ] = useState(false);
const context: StatusBarContext | undefined | null = note && noteContext && { note, noteContext, viewScope }; const context: StatusBarContext | undefined | null = note && noteContext && { note, noteContext, viewScope, hoistedNoteId };
const attributesContext: AttributesProps | undefined | null = context && { ...context, attributesShown, setAttributesShown }; const attributesContext: AttributesProps | undefined | null = context && { ...context, attributesShown, setAttributesShown };
return ( return (
@ -49,6 +51,7 @@ export default function StatusBar() {
<Breadcrumb {...context} /> <Breadcrumb {...context} />
<div className="actions-row"> <div className="actions-row">
<NotePaths {...context} />
<AttributesButton {...attributesContext} /> <AttributesButton {...attributesContext} />
<AttachmentCount {...context} /> <AttachmentCount {...context} />
<BacklinksBadge {...context} /> <BacklinksBadge {...context} />
@ -307,3 +310,19 @@ function AttributesPane({ note, noteContext, attributesShown, setAttributesShown
); );
} }
//#endregion //#endregion
//#region Note paths
function NotePaths({ note, hoistedNoteId }: StatusBarContext) {
const sortedNotePaths = useSortedNotePaths(note, hoistedNoteId);
return (
<StatusBarDropdown
title={t("status_bar.note_paths_title")}
icon="bx bx-link-alt"
text={sortedNotePaths?.length}
>
</StatusBarDropdown>
)
}
//#endregion

View File

@ -3,30 +3,13 @@ import { t } from "../../services/i18n";
import Button from "../react/Button"; import Button from "../react/Button";
import { useTriliumEvent } from "../react/hooks"; import { useTriliumEvent } from "../react/hooks";
import { useEffect, useMemo, useState } from "preact/hooks"; import { useEffect, useMemo, useState } from "preact/hooks";
import { NotePathRecord } from "../../entities/fnote"; import FNote, { NotePathRecord } from "../../entities/fnote";
import NoteLink from "../react/NoteLink"; import NoteLink from "../react/NoteLink";
import { joinElements } from "../react/react_utils"; import { joinElements } from "../react/react_utils";
import { NOTE_PATH_TITLE_SEPARATOR } from "../../services/tree"; import { NOTE_PATH_TITLE_SEPARATOR } from "../../services/tree";
export default function NotePathsTab({ note, hoistedNoteId, notePath }: TabContext) { export default function NotePathsTab({ note, hoistedNoteId, notePath }: TabContext) {
const [ sortedNotePaths, setSortedNotePaths ] = useState<NotePathRecord[]>(); const sortedNotePaths = useSortedNotePaths(note, hoistedNoteId);
function refresh() {
if (!note) return;
setSortedNotePaths(note
.getSortedNotePathRecords(hoistedNoteId)
.filter((notePath) => !notePath.isHidden));
}
useEffect(refresh, [ note?.noteId ]);
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
const noteId = note?.noteId;
if (!noteId) return;
if (loadResults.getBranchRows().find((branch) => branch.noteId === noteId)
|| loadResults.isNoteReloaded(noteId)) {
refresh();
}
});
return ( return (
<div class="note-paths-widget"> <div class="note-paths-widget">
@ -53,6 +36,29 @@ export default function NotePathsTab({ note, hoistedNoteId, notePath }: TabConte
) )
} }
export function useSortedNotePaths(note: FNote | null | undefined, hoistedNoteId?: string) {
const [ sortedNotePaths, setSortedNotePaths ] = useState<NotePathRecord[]>();
function refresh() {
if (!note) return;
setSortedNotePaths(note
.getSortedNotePathRecords(hoistedNoteId)
.filter((notePath) => !notePath.isHidden));
}
useEffect(refresh, [ note?.noteId ]);
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
const noteId = note?.noteId;
if (!noteId) return;
if (loadResults.getBranchRows().find((branch) => branch.noteId === noteId)
|| loadResults.isNoteReloaded(noteId)) {
refresh();
}
});
return sortedNotePaths;
}
function NotePath({ currentNotePath, notePathRecord }: { currentNotePath?: string | null, notePathRecord?: NotePathRecord }) { function NotePath({ currentNotePath, notePathRecord }: { currentNotePath?: string | null, notePathRecord?: NotePathRecord }) {
const notePath = notePathRecord?.notePath ?? []; const notePath = notePathRecord?.notePath ?? [];
const notePathString = useMemo(() => notePath.join("/"), [ notePath ]); const notePathString = useMemo(() => notePath.join("/"), [ notePath ]);