diff --git a/apps/client/src/widgets/TabHistoryNavigationButtons.tsx b/apps/client/src/widgets/TabHistoryNavigationButtons.tsx
index e3972f0df..d0e6afced 100644
--- a/apps/client/src/widgets/TabHistoryNavigationButtons.tsx
+++ b/apps/client/src/widgets/TabHistoryNavigationButtons.tsx
@@ -2,19 +2,27 @@ import "./TabHistoryNavigationButtons.css";
import { t } from "../services/i18n";
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() {
+ const webContents = useMemo(() => dynamicRequire("@electron/remote").getCurrentWebContents(), []);
+ const onContextMenu = handleHistoryContextMenu(webContents);
+
return (
);
diff --git a/apps/client/src/widgets/launch_bar/HistoryNavigation.tsx b/apps/client/src/widgets/launch_bar/HistoryNavigation.tsx
index f9ea51c57..e861e3358 100644
--- a/apps/client/src/widgets/launch_bar/HistoryNavigation.tsx
+++ b/apps/client/src/widgets/launch_bar/HistoryNavigation.tsx
@@ -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 { useCallback, useMemo } from "preact/hooks";
+
+import FNote from "../../entities/fnote";
import contextMenu, { MenuCommandItem } from "../../menus/context_menu";
-import tree from "../../services/tree";
import link from "../../services/link";
+import tree from "../../services/tree";
+import { dynamicRequire } from "../../services/utils";
+import { LaunchBarActionButton, useLauncherIconAndTitle } from "./launch_bar_widgets";
interface HistoryNavigationProps {
launcherNote: FNote;
@@ -16,71 +17,65 @@ const HISTORY_LIMIT = 20;
export default function HistoryNavigationButton({ launcherNote, command }: HistoryNavigationProps) {
const { icon, title } = useLauncherIconAndTitle(launcherNote);
- const webContentsRef = useRef(null);
-
- useEffect(() => {
- if (isElectron()) {
- const webContents = dynamicRequire("@electron/remote").getCurrentWebContents();
- // without this, the history is preserved across frontend reloads
- webContents?.clearHistory();
- webContentsRef.current = webContents;
- }
- }, []);
+ const webContents = useMemo(() => dynamicRequire("@electron/remote").getCurrentWebContents(), []);
return (
{
- e.preventDefault();
-
- const webContents = webContentsRef.current;
- if (!webContents || webContents.navigationHistory.length() < 2) {
- return;
- }
-
- let items: MenuCommandItem[] = [];
-
- 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) => {
- if (item && item.command && webContents) {
- const idx = parseInt(item.command, 10);
- webContents.navigationHistory.goToIndex(idx);
- }
- }
- });
- }}
+ onContextMenu={handleHistoryContextMenu(webContents)}
/>
- )
+ );
+}
+
+export function handleHistoryContextMenu(webContents: WebContents) {
+ return async (e: MouseEvent) => {
+ e.preventDefault();
+
+ if (!webContents || webContents.navigationHistory.length() < 2) {
+ return;
+ }
+
+ let items: MenuCommandItem[] = [];
+
+ 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) => {
+ if (item && item.command && webContents) {
+ const idx = parseInt(item.command, 10);
+ webContents.navigationHistory.goToIndex(idx);
+ }
+ }
+ });
+ };
}