opencode/packages/desktop/src/menu.ts

191 lines
6.0 KiB
TypeScript
Raw Normal View History

2025-12-16 18:33:04 +08:00
import { Menu, MenuItem, PredefinedMenuItem, Submenu } from "@tauri-apps/api/menu"
import { openUrl } from "@tauri-apps/plugin-opener"
2025-12-16 18:33:04 +08:00
import { type as ostype } from "@tauri-apps/plugin-os"
import { relaunch } from "@tauri-apps/plugin-process"
import { commands } from "./bindings"
import { installCli } from "./cli"
2026-01-28 05:00:17 +08:00
import { initI18n, t } from "./i18n"
import { runUpdater, UPDATER_ENABLED } from "./updater"
2025-12-16 18:33:04 +08:00
2026-02-06 18:10:48 +08:00
export async function createMenu(trigger: (id: string) => void) {
2025-12-16 18:33:49 +08:00
if (ostype() !== "macos") return
2025-12-16 18:33:04 +08:00
2026-01-28 05:00:17 +08:00
await initI18n()
2025-12-16 18:33:04 +08:00
const menu = await Menu.new({
items: [
await Submenu.new({
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.app"),
2025-12-16 18:33:04 +08:00
items: [
await PredefinedMenuItem.new({
item: { About: null },
}),
await MenuItem.new({
enabled: UPDATER_ENABLED,
action: () => runUpdater({ alertOnFail: true }),
2026-01-28 05:00:17 +08:00
text: t("desktop.menu.checkForUpdates"),
2025-12-16 18:33:04 +08:00
}),
await MenuItem.new({
action: () => installCli(),
2026-01-28 05:00:17 +08:00
text: t("desktop.menu.installCli"),
}),
await MenuItem.new({
action: async () => window.location.reload(),
2026-01-28 05:00:17 +08:00
text: t("desktop.menu.reloadWebview"),
}),
await MenuItem.new({
action: async () => {
await commands.killSidecar().catch(() => undefined)
await relaunch().catch(() => undefined)
},
2026-01-28 05:00:17 +08:00
text: t("desktop.menu.restart"),
}),
2025-12-16 18:33:04 +08:00
await PredefinedMenuItem.new({
item: "Separator",
}),
await PredefinedMenuItem.new({
item: "Hide",
}),
await PredefinedMenuItem.new({
item: "HideOthers",
}),
await PredefinedMenuItem.new({
item: "ShowAll",
}),
await PredefinedMenuItem.new({
item: "Separator",
}),
await PredefinedMenuItem.new({
item: "Quit",
}),
].filter(Boolean),
}),
2026-02-06 18:10:48 +08:00
await Submenu.new({
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.file"),
2026-02-06 18:10:48 +08:00
items: [
await MenuItem.new({
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.file.newSession"),
accelerator: "Shift+Cmd+S",
2026-02-06 18:10:48 +08:00
action: () => trigger("session.new"),
}),
await MenuItem.new({
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.file.openProject"),
accelerator: "Cmd+O",
2026-02-06 18:10:48 +08:00
action: () => trigger("project.open"),
}),
await PredefinedMenuItem.new({
item: "Separator",
}),
await PredefinedMenuItem.new({
item: "CloseWindow",
}),
],
}),
2025-12-16 18:33:04 +08:00
await Submenu.new({
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.edit"),
2025-12-16 18:33:04 +08:00
items: [
await PredefinedMenuItem.new({
item: "Undo",
}),
await PredefinedMenuItem.new({
item: "Redo",
}),
await PredefinedMenuItem.new({
item: "Separator",
}),
await PredefinedMenuItem.new({
item: "Cut",
}),
await PredefinedMenuItem.new({
item: "Copy",
}),
await PredefinedMenuItem.new({
item: "Paste",
}),
await PredefinedMenuItem.new({
item: "SelectAll",
}),
],
}),
2026-02-06 18:10:48 +08:00
await Submenu.new({
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.view"),
2026-02-06 18:10:48 +08:00
items: [
await MenuItem.new({
action: () => trigger("sidebar.toggle"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.view.toggleSidebar"),
2026-02-06 18:20:52 +08:00
accelerator: "Cmd+B",
2026-02-06 18:10:48 +08:00
}),
await MenuItem.new({
action: () => trigger("terminal.toggle"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.view.toggleTerminal"),
2026-02-06 18:20:52 +08:00
accelerator: "Ctrl+`",
2026-02-06 18:10:48 +08:00
}),
await MenuItem.new({
action: () => trigger("fileTree.toggle"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.view.toggleFileTree"),
2026-02-06 18:10:48 +08:00
}),
await PredefinedMenuItem.new({
item: "Separator",
}),
await MenuItem.new({
action: () => trigger("common.goBack"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.view.back"),
2026-02-06 18:10:48 +08:00
}),
await MenuItem.new({
action: () => trigger("common.goForward"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.view.forward"),
2026-02-06 18:10:48 +08:00
}),
await PredefinedMenuItem.new({
item: "Separator",
}),
await MenuItem.new({
action: () => trigger("session.previous"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.view.previousSession"),
2026-02-06 18:20:52 +08:00
accelerator: "Option+ArrowUp",
2026-02-06 18:10:48 +08:00
}),
await MenuItem.new({
action: () => trigger("session.next"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.view.nextSession"),
2026-02-06 18:20:52 +08:00
accelerator: "Option+ArrowDown",
2026-02-06 18:10:48 +08:00
}),
await PredefinedMenuItem.new({
item: "Separator",
}),
],
}),
await Submenu.new({
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.help"),
2026-02-06 18:10:48 +08:00
items: [
// missing native macos search
await MenuItem.new({
action: () => openUrl("https://opencode.ai/docs"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.help.documentation"),
2026-02-06 18:10:48 +08:00
}),
await MenuItem.new({
action: () => openUrl("https://discord.com/invite/opencode"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.help.supportForum"),
2026-02-06 18:10:48 +08:00
}),
await PredefinedMenuItem.new({
item: "Separator",
}),
// await MenuItem.new({
// text: "Release Notes",
// }),
await PredefinedMenuItem.new({
item: "Separator",
}),
await MenuItem.new({
action: () => openUrl("https://github.com/anomalyco/opencode/issues/new?template=feature_request.yml"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.help.shareFeedback"),
2026-02-06 18:10:48 +08:00
}),
await MenuItem.new({
action: () => openUrl("https://github.com/anomalyco/opencode/issues/new?template=bug_report.yml"),
2026-02-27 23:45:00 +08:00
text: t("desktop.menu.help.reportBug"),
2026-02-06 18:10:48 +08:00
}),
],
}),
2025-12-16 18:33:04 +08:00
],
})
void menu.setAsAppMenu()
2025-12-16 18:33:04 +08:00
}