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
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.",
"attributes_one": "{{count}} attribute",
"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 { useProcessedLocales } from "../type_widgets/options/components/LocaleSelector";
import Breadcrumb from "./Breadcrumb";
import NotePathsTab, { useSortedNotePaths } from "../ribbon/NotePathsTab";
interface StatusBarContext {
note: FNote;
noteContext: NoteContext;
viewScope?: ViewScope;
hoistedNoteId?: string;
}
export default function StatusBar() {
const { note, noteContext, viewScope } = useActiveNoteContext();
const { note, noteContext, viewScope, hoistedNoteId } = useActiveNoteContext();
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 };
return (
@@ -49,6 +51,7 @@ export default function StatusBar() {
<Breadcrumb {...context} />
<div className="actions-row">
<NotePaths {...context} />
<AttributesButton {...attributesContext} />
<AttachmentCount {...context} />
<BacklinksBadge {...context} />
@@ -307,3 +310,19 @@ function AttributesPane({ note, noteContext, attributesShown, setAttributesShown
);
}
//#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 { useTriliumEvent } from "../react/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 { joinElements } from "../react/react_utils";
import { NOTE_PATH_TITLE_SEPARATOR } from "../../services/tree";
export default function NotePathsTab({ note, hoistedNoteId, notePath }: TabContext) {
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();
}
});
const sortedNotePaths = useSortedNotePaths(note, hoistedNoteId);
return (
<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 }) {
const notePath = notePathRecord?.notePath ?? [];
const notePathString = useMemo(() => notePath.join("/"), [ notePath ]);