mirror of
https://github.com/TriliumNext/Trilium.git
synced 2025-12-11 19:44:00 -06:00
feat(tab_navigation): functional context menu
This commit is contained in:
parent
e3f5b3535a
commit
9e099444b6
@ -2,19 +2,27 @@ import "./TabHistoryNavigationButtons.css";
|
|||||||
|
|
||||||
import { t } from "../services/i18n";
|
import { t } from "../services/i18n";
|
||||||
import ActionButton from "./react/ActionButton";
|
import ActionButton from "./react/ActionButton";
|
||||||
|
import { useCallback, useMemo } from "preact/hooks";
|
||||||
|
import { handleHistoryContextMenu } from "./launch_bar/HistoryNavigation";
|
||||||
|
import { dynamicRequire } from "../services/utils";
|
||||||
|
|
||||||
export default function TabHistoryNavigationButtons() {
|
export default function TabHistoryNavigationButtons() {
|
||||||
|
const webContents = useMemo(() => dynamicRequire("@electron/remote").getCurrentWebContents(), []);
|
||||||
|
const onContextMenu = handleHistoryContextMenu(webContents);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="tab-history-navigation-buttons">
|
<div className="tab-history-navigation-buttons">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon="bx bx-left-arrow-alt"
|
icon="bx bx-left-arrow-alt"
|
||||||
text={t("tab_history_navigation_buttons.go-back")}
|
text={t("tab_history_navigation_buttons.go-back")}
|
||||||
triggerCommand="backInNoteHistory"
|
triggerCommand="backInNoteHistory"
|
||||||
|
onContextMenu={onContextMenu}
|
||||||
/>
|
/>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon="bx bx-right-arrow-alt"
|
icon="bx bx-right-arrow-alt"
|
||||||
text={t("tab_history_navigation_buttons.go-forward")}
|
text={t("tab_history_navigation_buttons.go-forward")}
|
||||||
triggerCommand="forwardInNoteHistory"
|
triggerCommand="forwardInNoteHistory"
|
||||||
|
onContextMenu={onContextMenu}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { useEffect, useRef } from "preact/hooks";
|
|
||||||
import FNote from "../../entities/fnote";
|
|
||||||
import { dynamicRequire, isElectron } from "../../services/utils";
|
|
||||||
import { LaunchBarActionButton, useLauncherIconAndTitle } from "./launch_bar_widgets";
|
|
||||||
import type { WebContents } from "electron";
|
import type { WebContents } from "electron";
|
||||||
|
import { useCallback, useMemo } from "preact/hooks";
|
||||||
|
|
||||||
|
import FNote from "../../entities/fnote";
|
||||||
import contextMenu, { MenuCommandItem } from "../../menus/context_menu";
|
import contextMenu, { MenuCommandItem } from "../../menus/context_menu";
|
||||||
import tree from "../../services/tree";
|
|
||||||
import link from "../../services/link";
|
import link from "../../services/link";
|
||||||
|
import tree from "../../services/tree";
|
||||||
|
import { dynamicRequire } from "../../services/utils";
|
||||||
|
import { LaunchBarActionButton, useLauncherIconAndTitle } from "./launch_bar_widgets";
|
||||||
|
|
||||||
interface HistoryNavigationProps {
|
interface HistoryNavigationProps {
|
||||||
launcherNote: FNote;
|
launcherNote: FNote;
|
||||||
@ -16,71 +17,65 @@ const HISTORY_LIMIT = 20;
|
|||||||
|
|
||||||
export default function HistoryNavigationButton({ launcherNote, command }: HistoryNavigationProps) {
|
export default function HistoryNavigationButton({ launcherNote, command }: HistoryNavigationProps) {
|
||||||
const { icon, title } = useLauncherIconAndTitle(launcherNote);
|
const { icon, title } = useLauncherIconAndTitle(launcherNote);
|
||||||
const webContentsRef = useRef<WebContents>(null);
|
const webContents = useMemo(() => dynamicRequire("@electron/remote").getCurrentWebContents(), []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isElectron()) {
|
|
||||||
const webContents = dynamicRequire("@electron/remote").getCurrentWebContents();
|
|
||||||
// without this, the history is preserved across frontend reloads
|
|
||||||
webContents?.clearHistory();
|
|
||||||
webContentsRef.current = webContents;
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LaunchBarActionButton
|
<LaunchBarActionButton
|
||||||
icon={icon}
|
icon={icon}
|
||||||
text={title}
|
text={title}
|
||||||
triggerCommand={command}
|
triggerCommand={command}
|
||||||
onContextMenu={async (e) => {
|
onContextMenu={handleHistoryContextMenu(webContents)}
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const webContents = webContentsRef.current;
|
|
||||||
if (!webContents || webContents.navigationHistory.length() < 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let items: MenuCommandItem<string>[] = [];
|
|
||||||
|
|
||||||
const history = webContents.navigationHistory.getAllEntries();
|
|
||||||
const activeIndex = webContents.navigationHistory.getActiveIndex();
|
|
||||||
|
|
||||||
for (const idx in history) {
|
|
||||||
const { notePath } = link.parseNavigationStateFromUrl(history[idx].url);
|
|
||||||
if (!notePath) continue;
|
|
||||||
|
|
||||||
const title = await tree.getNotePathTitle(notePath);
|
|
||||||
|
|
||||||
items.push({
|
|
||||||
title,
|
|
||||||
command: idx,
|
|
||||||
uiIcon:
|
|
||||||
parseInt(idx) === activeIndex
|
|
||||||
? "bx bx-radio-circle-marked" // compare with type coercion!
|
|
||||||
: parseInt(idx) < activeIndex
|
|
||||||
? "bx bx-left-arrow-alt"
|
|
||||||
: "bx bx-right-arrow-alt"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
items.reverse();
|
|
||||||
|
|
||||||
if (items.length > HISTORY_LIMIT) {
|
|
||||||
items = items.slice(0, HISTORY_LIMIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
contextMenu.show({
|
|
||||||
x: e.pageX,
|
|
||||||
y: e.pageY,
|
|
||||||
items,
|
|
||||||
selectMenuItemHandler: (item: MenuCommandItem<string>) => {
|
|
||||||
if (item && item.command && webContents) {
|
|
||||||
const idx = parseInt(item.command, 10);
|
|
||||||
webContents.navigationHistory.goToIndex(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleHistoryContextMenu(webContents: WebContents) {
|
||||||
|
return async (e: MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!webContents || webContents.navigationHistory.length() < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let items: MenuCommandItem<string>[] = [];
|
||||||
|
|
||||||
|
const history = webContents.navigationHistory.getAllEntries();
|
||||||
|
const activeIndex = webContents.navigationHistory.getActiveIndex();
|
||||||
|
|
||||||
|
for (const idx in history) {
|
||||||
|
const { notePath } = link.parseNavigationStateFromUrl(history[idx].url);
|
||||||
|
if (!notePath) continue;
|
||||||
|
|
||||||
|
const title = await tree.getNotePathTitle(notePath);
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
title,
|
||||||
|
command: idx,
|
||||||
|
uiIcon:
|
||||||
|
parseInt(idx, 10) === activeIndex
|
||||||
|
? "bx bx-radio-circle-marked" // compare with type coercion!
|
||||||
|
: parseInt(idx, 10) < activeIndex
|
||||||
|
? "bx bx-left-arrow-alt"
|
||||||
|
: "bx bx-right-arrow-alt"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
items.reverse();
|
||||||
|
|
||||||
|
if (items.length > HISTORY_LIMIT) {
|
||||||
|
items = items.slice(0, HISTORY_LIMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
contextMenu.show({
|
||||||
|
x: e.pageX,
|
||||||
|
y: e.pageY,
|
||||||
|
items,
|
||||||
|
selectMenuItemHandler: (item: MenuCommandItem<string>) => {
|
||||||
|
if (item && item.command && webContents) {
|
||||||
|
const idx = parseInt(item.command, 10);
|
||||||
|
webContents.navigationHistory.goToIndex(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user