menu.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import { Menu, MenuItem, PredefinedMenuItem, Submenu } from "@tauri-apps/api/menu"
  2. import { type as ostype } from "@tauri-apps/plugin-os"
  3. import { relaunch } from "@tauri-apps/plugin-process"
  4. import { openUrl } from "@tauri-apps/plugin-opener"
  5. import { runUpdater, UPDATER_ENABLED } from "./updater"
  6. import { installCli } from "./cli"
  7. import { initI18n, t } from "./i18n"
  8. import { commands } from "./bindings"
  9. export async function createMenu(trigger: (id: string) => void) {
  10. if (ostype() !== "macos") return
  11. await initI18n()
  12. const menu = await Menu.new({
  13. items: [
  14. await Submenu.new({
  15. text: "OpenCode",
  16. items: [
  17. await PredefinedMenuItem.new({
  18. item: { About: null },
  19. }),
  20. await MenuItem.new({
  21. enabled: UPDATER_ENABLED,
  22. action: () => runUpdater({ alertOnFail: true }),
  23. text: t("desktop.menu.checkForUpdates"),
  24. }),
  25. await MenuItem.new({
  26. action: () => installCli(),
  27. text: t("desktop.menu.installCli"),
  28. }),
  29. await MenuItem.new({
  30. action: async () => window.location.reload(),
  31. text: t("desktop.menu.reloadWebview"),
  32. }),
  33. await MenuItem.new({
  34. action: async () => {
  35. await commands.killSidecar().catch(() => undefined)
  36. await relaunch().catch(() => undefined)
  37. },
  38. text: t("desktop.menu.restart"),
  39. }),
  40. await PredefinedMenuItem.new({
  41. item: "Separator",
  42. }),
  43. await PredefinedMenuItem.new({
  44. item: "Hide",
  45. }),
  46. await PredefinedMenuItem.new({
  47. item: "HideOthers",
  48. }),
  49. await PredefinedMenuItem.new({
  50. item: "ShowAll",
  51. }),
  52. await PredefinedMenuItem.new({
  53. item: "Separator",
  54. }),
  55. await PredefinedMenuItem.new({
  56. item: "Quit",
  57. }),
  58. ].filter(Boolean),
  59. }),
  60. await Submenu.new({
  61. text: "File",
  62. items: [
  63. await MenuItem.new({
  64. text: "New Session",
  65. accelerator: "Shift+Cmd+S",
  66. action: () => trigger("session.new"),
  67. }),
  68. await MenuItem.new({
  69. text: "Open Project...",
  70. accelerator: "Cmd+O",
  71. action: () => trigger("project.open"),
  72. }),
  73. await PredefinedMenuItem.new({
  74. item: "Separator",
  75. }),
  76. await PredefinedMenuItem.new({
  77. item: "CloseWindow",
  78. }),
  79. ],
  80. }),
  81. await Submenu.new({
  82. text: "Edit",
  83. items: [
  84. await PredefinedMenuItem.new({
  85. item: "Undo",
  86. }),
  87. await PredefinedMenuItem.new({
  88. item: "Redo",
  89. }),
  90. await PredefinedMenuItem.new({
  91. item: "Separator",
  92. }),
  93. await PredefinedMenuItem.new({
  94. item: "Cut",
  95. }),
  96. await PredefinedMenuItem.new({
  97. item: "Copy",
  98. }),
  99. await PredefinedMenuItem.new({
  100. item: "Paste",
  101. }),
  102. await PredefinedMenuItem.new({
  103. item: "SelectAll",
  104. }),
  105. ],
  106. }),
  107. await Submenu.new({
  108. text: "View",
  109. items: [
  110. await MenuItem.new({
  111. action: () => trigger("sidebar.toggle"),
  112. text: "Toggle Sidebar",
  113. accelerator: "Cmd+B",
  114. }),
  115. await MenuItem.new({
  116. action: () => trigger("terminal.toggle"),
  117. text: "Toggle Terminal",
  118. accelerator: "Ctrl+`",
  119. }),
  120. await MenuItem.new({
  121. action: () => trigger("fileTree.toggle"),
  122. text: "Toggle File Tree",
  123. }),
  124. await PredefinedMenuItem.new({
  125. item: "Separator",
  126. }),
  127. await MenuItem.new({
  128. action: () => trigger("common.goBack"),
  129. text: "Back",
  130. }),
  131. await MenuItem.new({
  132. action: () => trigger("common.goForward"),
  133. text: "Forward",
  134. }),
  135. await PredefinedMenuItem.new({
  136. item: "Separator",
  137. }),
  138. await MenuItem.new({
  139. action: () => trigger("session.previous"),
  140. text: "Previous Session",
  141. accelerator: "Option+ArrowUp",
  142. }),
  143. await MenuItem.new({
  144. action: () => trigger("session.next"),
  145. text: "Next Session",
  146. accelerator: "Option+ArrowDown",
  147. }),
  148. await PredefinedMenuItem.new({
  149. item: "Separator",
  150. }),
  151. ],
  152. }),
  153. await Submenu.new({
  154. text: "Help",
  155. items: [
  156. // missing native macos search
  157. await MenuItem.new({
  158. action: () => openUrl("https://opencode.ai/docs"),
  159. text: "OpenCode Documentation",
  160. }),
  161. await MenuItem.new({
  162. action: () => openUrl("https://discord.com/invite/opencode"),
  163. text: "Support Forum",
  164. }),
  165. await PredefinedMenuItem.new({
  166. item: "Separator",
  167. }),
  168. // await MenuItem.new({
  169. // text: "Release Notes",
  170. // }),
  171. await PredefinedMenuItem.new({
  172. item: "Separator",
  173. }),
  174. await MenuItem.new({
  175. action: () => openUrl("https://github.com/anomalyco/opencode/issues/new?template=feature_request.yml"),
  176. text: "Share Feedback",
  177. }),
  178. await MenuItem.new({
  179. action: () => openUrl("https://github.com/anomalyco/opencode/issues/new?template=bug_report.yml"),
  180. text: "Report a Bug",
  181. }),
  182. ],
  183. }),
  184. ],
  185. })
  186. menu.setAsAppMenu()
  187. }