feat(menu): reorganize native menu bar with discoverable actions

Move Check for Updates into the macOS app menu and add Settings (Cmd+,),
Save (Cmd+S), Find (Cmd+F), chapter navigation, and a Help > Report an
Issue link. Route new menu actions through menu-action events and trim
duplicate editor keybindings.
This commit is contained in:
pj committed 2026-07-15 09:31:57 +05:30
1 parent 866a971729
commit acf78dfe29
5 files changed
+122 -26

No files matched your search

+3
View File
@@ -1,5 +1,6 @@
import { useEffect } from "react";
import { listen } from "@tauri-apps/api/event";
import { openUrl } from "@tauri-apps/plugin-opener";
import { getCurrentWindow } from "@tauri-apps/api/window";
import { Library } from "./components/Library";
import { EditorView } from "./components/EditorView";
@@ -29,6 +30,8 @@ function App() {
}
else if (event.payload === "export-epub") runExport("epub");
else if (event.payload === "check-updates") checkForUpdates(false);
else if (event.payload === "report-issue")
openUrl("https://github.com/priyanshujain/margin/issues").catch(() => {});
});
const unlistenWarn = listen<string>("pdf-warnings", (event) => {
useBook.getState().setNotice(`PDF exported with warnings:\n${event.payload}`);
+25 -8
View File
@@ -1,4 +1,5 @@
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
import { listen } from "@tauri-apps/api/event";
import type { Editor as TiptapEditor } from "@tiptap/react";
import { Sidebar } from "./Sidebar";
import { Dock } from "./Dock";
@@ -129,17 +130,14 @@ export function EditorView() {
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "s") {
if (e.metaKey && e.altKey && e.key.toLowerCase() === "f") {
e.preventDefault();
saveNow();
} else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "f") {
e.preventDefault();
openFind(e.altKey);
} else if (e.metaKey && e.altKey && (e.key === "ArrowDown" || e.key === "ArrowRight")) {
openFind(true);
} else if (e.metaKey && e.altKey && e.key === "ArrowRight") {
e.preventDefault();
e.stopPropagation();
switchChapter(1);
} else if (e.metaKey && e.altKey && (e.key === "ArrowUp" || e.key === "ArrowLeft")) {
} else if (e.metaKey && e.altKey && e.key === "ArrowLeft") {
e.preventDefault();
e.stopPropagation();
switchChapter(-1);
@@ -151,7 +149,26 @@ export function EditorView() {
};
window.addEventListener("keydown", onKey, true);
return () => window.removeEventListener("keydown", onKey, true);
}, [saveNow, openFind, switchChapter]);
}, [openFind, switchChapter]);
const menuCommands = useRef({ saveNow, openFind, setSettingsOpen, toggleSidebar, switchChapter });
menuCommands.current = { saveNow, openFind, setSettingsOpen, toggleSidebar, switchChapter };
useEffect(() => {
if (!isDesktop) return;
const unlisten = listen<string>("menu-action", (e) => {
const cmd = menuCommands.current;
if (e.payload === "save") cmd.saveNow();
else if (e.payload === "find") cmd.openFind(false);
else if (e.payload === "settings") cmd.setSettingsOpen(true);
else if (e.payload === "toggle-chapters") cmd.toggleSidebar();
else if (e.payload === "next-chapter") cmd.switchChapter(1);
else if (e.payload === "prev-chapter") cmd.switchChapter(-1);
});
return () => {
unlisten.then((stop) => stop());
};
}, []);
useEffect(() => {
if (!widthOpen && !exportOpen && !moreOpen) return;
+1 -1
View File
@@ -20,7 +20,7 @@ const TRIM: Record<TrimSize, { w: string; h: string }> = {
a5: { w: "148mm", h: "210mm" },
};
const INLINE_SPECIAL = /[\\#$*_`<>@~[\]]/g;
const INLINE_SPECIAL = /[\\#$*_`<>@~()[\]]/g;
const LINE_SEPARATORS = /[\n\r\v\f\u2028\u2029]+/g;
function esc(text: string): string {