menu.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import { BrowserWindow, Menu, shell } from "electron"
  2. import type { MenuItemConstructorOptions } from "electron"
  3. import {
  4. DESKTOP_MENU,
  5. desktopMenuVisible,
  6. type DesktopMenuEntry,
  7. type DesktopMenuRole,
  8. } from "@opencode-ai/app/desktop-menu"
  9. import { UPDATER_ENABLED } from "./constants"
  10. import { runDesktopMenuAction } from "./desktop-menu-actions"
  11. type Deps = {
  12. trigger: (id: string) => void
  13. checkForUpdates: () => void
  14. relaunch: () => void
  15. }
  16. export function createMenu(deps: Deps) {
  17. if (process.platform !== "darwin") return
  18. const template = DESKTOP_MENU.filter((menu) => desktopMenuVisible(menu, "macos")).map((menu) => {
  19. if (menu.role) return { role: nativeRole(menu.role) }
  20. return {
  21. label: menu.label,
  22. submenu: menu.items
  23. ?.filter((entry) => desktopMenuVisible(entry, "macos"))
  24. .map((entry) => nativeItem(entry, deps)),
  25. }
  26. })
  27. Menu.setApplicationMenu(Menu.buildFromTemplate(template))
  28. }
  29. function nativeItem(entry: DesktopMenuEntry, deps: Deps): MenuItemConstructorOptions {
  30. if (entry.type === "separator") return { type: "separator" }
  31. if (entry.role) return { role: nativeRole(entry.role) }
  32. const item: MenuItemConstructorOptions = {
  33. label: entry.label,
  34. accelerator: entry.accelerator?.macos,
  35. enabled: entry.enabled === "updater" ? UPDATER_ENABLED : undefined,
  36. }
  37. if (entry.command) {
  38. const command = entry.command
  39. item.click = () => deps.trigger(command)
  40. }
  41. if (entry.action) {
  42. const action = entry.action
  43. item.click = () =>
  44. runDesktopMenuAction(BrowserWindow.getFocusedWindow(), action, {
  45. checkForUpdates: deps.checkForUpdates,
  46. relaunch: deps.relaunch,
  47. })
  48. }
  49. if (entry.href) {
  50. const href = entry.href
  51. item.click = () => shell.openExternal(href)
  52. }
  53. return item
  54. }
  55. function nativeRole(role: DesktopMenuRole) {
  56. return role as NonNullable<MenuItemConstructorOptions["role"]>
  57. }