refactor(react/launch_bar): deduplicate launcher icon and title

This commit is contained in:
Elian Doran 2025-12-04 16:22:46 +02:00
parent 1963b5732a
commit 03cdfc259e
No known key found for this signature in database
5 changed files with 42 additions and 34 deletions

View File

@ -1,17 +1,15 @@
import FNote from "../../entities/fnote"; import FNote from "../../entities/fnote";
import { escapeHtml } from "../../services/utils"; import { useTriliumOptionBool } from "../react/hooks";
import { useNoteLabel, useNoteProperty, useTriliumOptionBool } from "../react/hooks"; import { LaunchBarActionButton, useLauncherIconAndTitle } from "./launch_bar_widgets";
import { LaunchBarActionButton } from "./launch_bar_widgets";
export default function AiChatButton({ launcherNote }: { launcherNote: FNote }) { export default function AiChatButton({ launcherNote }: { launcherNote: FNote }) {
const [ aiEnabled ] = useTriliumOptionBool("aiEnabled"); const [ aiEnabled ] = useTriliumOptionBool("aiEnabled");
const [ iconClass ] = useNoteLabel(launcherNote, "iconClass"); const { icon, title } = useLauncherIconAndTitle(launcherNote);
const title = useNoteProperty(launcherNote, "title");
return aiEnabled && iconClass && title && ( return aiEnabled && (
<LaunchBarActionButton <LaunchBarActionButton
icon={iconClass} icon={icon}
text={escapeHtml(title)} text={title}
triggerCommand="createAiChat" triggerCommand="createAiChat"
/> />
) )

View File

@ -1,9 +1,8 @@
import { useMemo } from "preact/hooks"; import { useMemo } from "preact/hooks";
import { LaunchBarDropdownButton, type LaunchBarWidgetProps } from "./launch_bar_widgets"; import { LaunchBarDropdownButton, useLauncherIconAndTitle, type LaunchBarWidgetProps } from "./launch_bar_widgets";
import { CSSProperties } from "preact"; import { CSSProperties } from "preact";
import type FNote from "../../entities/fnote"; import type FNote from "../../entities/fnote";
import { useChildNotes, useNoteLabel, useNoteLabelBoolean, useNoteProperty } from "../react/hooks"; import { useChildNotes, useNoteLabelBoolean } from "../react/hooks";
import { escapeHtml } from "../../services/utils";
import "./BookmarkButtons.css"; import "./BookmarkButtons.css";
import NoteLink from "../react/NoteLink"; import NoteLink from "../react/NoteLink";
import { NoteLauncher } from "./GenericButtons"; import { NoteLauncher } from "./GenericButtons";
@ -33,14 +32,13 @@ function SingleBookmark({ note }: { note: FNote }) {
} }
function BookmarkFolder({ note }: { note: FNote }) { function BookmarkFolder({ note }: { note: FNote }) {
const [ iconClass ] = useNoteLabel(note, "iconClass"); const { icon, title } = useLauncherIconAndTitle(note);
const title = useNoteProperty(note, "title");
const childNotes = useChildNotes(note.noteId); const childNotes = useChildNotes(note.noteId);
return title && iconClass && ( return (
<LaunchBarDropdownButton <LaunchBarDropdownButton
icon={iconClass} icon={icon}
title={escapeHtml(title)} title={title}
> >
<div className="bookmark-folder-widget"> <div className="bookmark-folder-widget">
<div className="parent-note"> <div className="parent-note">

View File

@ -3,25 +3,23 @@ import FNote from "../../entities/fnote";
import link_context_menu from "../../menus/link_context_menu"; import link_context_menu from "../../menus/link_context_menu";
import { escapeHtml, isCtrlKey } from "../../services/utils"; import { escapeHtml, isCtrlKey } from "../../services/utils";
import { useNoteLabel, useNoteProperty } from "../react/hooks"; import { useNoteLabel, useNoteProperty } from "../react/hooks";
import { LaunchBarActionButton } from "./launch_bar_widgets"; import { LaunchBarActionButton, useLauncherIconAndTitle } from "./launch_bar_widgets";
export function CommandButton({ launcherNote }: { launcherNote: FNote }) { export function CommandButton({ launcherNote }: { launcherNote: FNote }) {
const [ iconClass ] = useNoteLabel(launcherNote, "iconClass"); const { icon, title } = useLauncherIconAndTitle(launcherNote);
const [ command ] = useNoteLabel(launcherNote, "command"); const [ command ] = useNoteLabel(launcherNote, "command");
const title = useNoteProperty(launcherNote, "title");
return iconClass && title && command && ( return command && (
<LaunchBarActionButton <LaunchBarActionButton
icon={iconClass} icon={icon}
text={escapeHtml(title)} text={title}
triggerCommand={command as CommandNames} triggerCommand={command as CommandNames}
/> />
) )
} }
export function NoteLauncher({ launcherNote, targetNoteId, hoistedNoteId }: { launcherNote: FNote, targetNoteId: string, hoistedNoteId?: string }) { export function NoteLauncher({ launcherNote, targetNoteId, hoistedNoteId }: { launcherNote: FNote, targetNoteId: string, hoistedNoteId?: string }) {
const [ iconClass ] = useNoteLabel(launcherNote, "iconClass"); const { icon, title } = useLauncherIconAndTitle(launcherNote);
const title = useNoteProperty(launcherNote, "title");
async function launch(evt: MouseEvent) { async function launch(evt: MouseEvent) {
if (evt.which === 3) { if (evt.which === 3) {
@ -38,9 +36,9 @@ export function NoteLauncher({ launcherNote, targetNoteId, hoistedNoteId }: { la
} }
} }
return title && iconClass && ( return (
<LaunchBarActionButton <LaunchBarActionButton
icon={iconClass} icon={icon}
text={escapeHtml(title)} text={escapeHtml(title)}
onClick={launch} onClick={launch}
onAuxClick={launch} onAuxClick={launch}

View File

@ -1,8 +1,7 @@
import { useEffect, useRef } from "preact/hooks"; import { useEffect, useRef } from "preact/hooks";
import FNote from "../../entities/fnote"; import FNote from "../../entities/fnote";
import { dynamicRequire, escapeHtml, isElectron } from "../../services/utils"; import { dynamicRequire, isElectron } from "../../services/utils";
import { useNoteLabel, useNoteProperty } from "../react/hooks"; import { LaunchBarActionButton, useLauncherIconAndTitle } from "./launch_bar_widgets";
import { LaunchBarActionButton } from "./launch_bar_widgets";
import type { WebContents } from "electron"; import type { WebContents } from "electron";
import contextMenu, { MenuCommandItem } from "../../menus/context_menu"; import contextMenu, { MenuCommandItem } from "../../menus/context_menu";
import tree from "../../services/tree"; import tree from "../../services/tree";
@ -14,8 +13,7 @@ interface HistoryNavigationProps {
} }
export default function HistoryNavigationButton({ launcherNote, command }: HistoryNavigationProps) { export default function HistoryNavigationButton({ launcherNote, command }: HistoryNavigationProps) {
const [ iconClass ] = useNoteLabel(launcherNote, "iconClass"); const { icon, title } = useLauncherIconAndTitle(launcherNote);
const title = useNoteProperty(launcherNote, "title");
const webContentsRef = useRef<WebContents>(null); const webContentsRef = useRef<WebContents>(null);
useEffect(() => { useEffect(() => {
@ -27,10 +25,10 @@ export default function HistoryNavigationButton({ launcherNote, command }: Histo
} }
}, []); }, []);
return iconClass && title && ( return (
<LaunchBarActionButton <LaunchBarActionButton
icon={iconClass} icon={icon}
text={escapeHtml(title)} text={title}
triggerCommand={command} triggerCommand={command}
onContextMenu={async (e) => { onContextMenu={async (e) => {
e.preventDefault(); e.preventDefault();

View File

@ -1,5 +1,8 @@
import FNote from "../../entities/fnote";
import { escapeHtml } from "../../services/utils";
import ActionButton, { ActionButtonProps } from "../react/ActionButton"; import ActionButton, { ActionButtonProps } from "../react/ActionButton";
import Dropdown, { DropdownProps } from "../react/Dropdown"; import Dropdown, { DropdownProps } from "../react/Dropdown";
import { useNoteLabel, useNoteProperty } from "../react/hooks";
import Icon from "../react/Icon"; import Icon from "../react/Icon";
export interface LaunchBarWidgetProps { export interface LaunchBarWidgetProps {
@ -28,3 +31,16 @@ export function LaunchBarDropdownButton({ children, icon, ...props }: Pick<Dropd
>{children}</Dropdown> >{children}</Dropdown>
) )
} }
export function useLauncherIconAndTitle(note: FNote) {
const title = useNoteProperty(note, "title");
// React to changes.
useNoteLabel(note, "iconClass");
useNoteLabel(note, "workspaceIconClass");
return {
icon: note.getIcon(),
title: escapeHtml(title ?? "")
};
}