2025-12-22 09:18:21 +08:00
import {
app ,
BrowserWindow ,
dialog ,
Menu ,
type MenuItemConstructorOptions ,
shell ,
} from "electron"
import {
applyPresetToEnv ,
getAllPresets ,
getCurrentPresetId ,
setCurrentPreset ,
} from "./config-manager"
2026-01-17 23:10:57 +05:30
import { getMenuTranslations , getPreferredLocale } from "./menu-i18n"
2025-12-22 09:18:21 +08:00
import { restartNextServer } from "./next-server"
import { showSettingsWindow } from "./settings-window"
/ * *
2026-01-16 18:04:26 +05:30
* Build and set the application menu with i18n support
2025-12-22 09:18:21 +08:00
* /
export function buildAppMenu ( ) : void {
const template = getMenuTemplate ( )
const menu = Menu . buildFromTemplate ( template )
Menu . setApplicationMenu ( menu )
}
/ * *
2026-01-16 18:04:26 +05:30
* Rebuild the menu ( call this when presets change or language changes )
2025-12-22 09:18:21 +08:00
* /
export function rebuildAppMenu ( ) : void {
buildAppMenu ( )
}
/ * *
2026-01-16 18:04:26 +05:30
* Get the menu template with translations
2025-12-22 09:18:21 +08:00
* /
function getMenuTemplate ( ) : MenuItemConstructorOptions [ ] {
const isMac = process . platform === "darwin"
2026-01-17 23:10:57 +05:30
// Get translations for preferred locale (saved preference or system default)
const locale = getPreferredLocale ( app . getLocale ( ) )
2026-01-16 18:04:26 +05:30
const t = getMenuTranslations ( locale )
2025-12-22 09:18:21 +08:00
const template : MenuItemConstructorOptions [ ] = [ ]
// macOS app menu
if ( isMac ) {
template . push ( {
label : app.name ,
submenu : [
2026-01-16 18:04:26 +05:30
{ role : "about" } , // System-translated
2025-12-22 09:18:21 +08:00
{ type : "separator" } ,
{
2026-01-16 18:04:26 +05:30
label : t.settings ,
2025-12-22 09:18:21 +08:00
accelerator : "CmdOrCtrl+," ,
click : ( ) = > {
const win = BrowserWindow . getFocusedWindow ( )
showSettingsWindow ( win || undefined )
} ,
} ,
{ type : "separator" } ,
2026-01-16 18:04:26 +05:30
{ role : "services" } , // System-translated
2025-12-22 09:18:21 +08:00
{ type : "separator" } ,
2026-01-16 18:04:26 +05:30
{ role : "hide" } , // System-translated
{ role : "hideOthers" } , // System-translated
{ role : "unhide" } , // System-translated
2025-12-22 09:18:21 +08:00
{ type : "separator" } ,
2026-01-16 18:04:26 +05:30
{ role : "quit" } , // System-translated
2025-12-22 09:18:21 +08:00
] ,
} )
}
// File menu
template . push ( {
2026-01-16 18:04:26 +05:30
label : t.file ,
2025-12-22 09:18:21 +08:00
submenu : [
. . . ( isMac
? [ ]
: [
{
2026-01-16 18:04:26 +05:30
label : t.settings ,
2025-12-22 09:18:21 +08:00
accelerator : "CmdOrCtrl+," ,
click : ( ) = > {
const win = BrowserWindow . getFocusedWindow ( )
showSettingsWindow ( win || undefined )
} ,
} ,
{ type : "separator" } as MenuItemConstructorOptions ,
] ) ,
2026-01-16 18:04:26 +05:30
isMac ? { role : "close" } : { role : "quit" } , // System-translated
2025-12-22 09:18:21 +08:00
] ,
} )
// Edit menu
template . push ( {
2026-01-16 18:04:26 +05:30
label : t.edit ,
2025-12-22 09:18:21 +08:00
submenu : [
2026-01-16 18:04:26 +05:30
{ role : "undo" } , // System-translated
{ role : "redo" } , // System-translated
2025-12-22 09:18:21 +08:00
{ type : "separator" } ,
2026-01-16 18:04:26 +05:30
{ role : "cut" } , // System-translated
{ role : "copy" } , // System-translated
{ role : "paste" } , // System-translated
2025-12-22 09:18:21 +08:00
. . . ( isMac
? [
{
role : "pasteAndMatchStyle" ,
2026-01-16 18:04:26 +05:30
} as MenuItemConstructorOptions , // System-translated
{ role : "delete" } as MenuItemConstructorOptions , // System-translated
{ role : "selectAll" } as MenuItemConstructorOptions , // System-translated
2025-12-22 09:18:21 +08:00
]
: [
2026-01-16 18:04:26 +05:30
{ role : "delete" } as MenuItemConstructorOptions , // System-translated
2025-12-22 09:18:21 +08:00
{ type : "separator" } as MenuItemConstructorOptions ,
2026-01-16 18:04:26 +05:30
{ role : "selectAll" } as MenuItemConstructorOptions , // System-translated
2025-12-22 09:18:21 +08:00
] ) ,
] ,
} )
// View menu
template . push ( {
2026-01-16 18:04:26 +05:30
label : t.view ,
2025-12-22 09:18:21 +08:00
submenu : [
2026-01-16 18:04:26 +05:30
{ role : "reload" } , // System-translated
{ role : "forceReload" } , // System-translated
{ role : "toggleDevTools" } , // System-translated
2025-12-22 09:18:21 +08:00
{ type : "separator" } ,
2026-01-16 18:04:26 +05:30
{ role : "resetZoom" } , // System-translated
{ role : "zoomIn" } , // System-translated
{ role : "zoomOut" } , // System-translated
2025-12-22 09:18:21 +08:00
{ type : "separator" } ,
2026-01-16 18:04:26 +05:30
{ role : "togglefullscreen" } , // System-translated
2025-12-22 09:18:21 +08:00
] ,
} )
// Configuration menu with presets
2026-01-16 18:04:26 +05:30
template . push ( buildConfigMenu ( t ) )
2025-12-22 09:18:21 +08:00
// Window menu
template . push ( {
2026-01-16 18:04:26 +05:30
label : t.window ,
2025-12-22 09:18:21 +08:00
submenu : [
2026-01-16 18:04:26 +05:30
{ role : "minimize" } , // System-translated
{ role : "zoom" } , // System-translated
2025-12-22 09:18:21 +08:00
. . . ( isMac
? [
{ type : "separator" } as MenuItemConstructorOptions ,
2026-01-16 18:04:26 +05:30
{ role : "front" } as MenuItemConstructorOptions , // System-translated
2025-12-22 09:18:21 +08:00
]
2026-01-16 18:04:26 +05:30
: [ { role : "close" } as MenuItemConstructorOptions ] ) , // System-translated
2025-12-22 09:18:21 +08:00
] ,
} )
// Help menu
template . push ( {
2026-01-16 18:04:26 +05:30
label : t.help ,
2025-12-22 09:18:21 +08:00
submenu : [
{
2026-01-16 18:04:26 +05:30
label : t.documentation ,
2025-12-22 09:18:21 +08:00
click : async ( ) = > {
await shell . openExternal (
"https://github.com/dayuanjiang/next-ai-draw-io" ,
)
} ,
} ,
{
2026-01-16 18:04:26 +05:30
label : t.reportIssue ,
2025-12-22 09:18:21 +08:00
click : async ( ) = > {
await shell . openExternal (
"https://github.com/dayuanjiang/next-ai-draw-io/issues" ,
)
} ,
} ,
] ,
} )
return template
}
/ * *
* Build the Configuration menu with presets
* /
2026-01-16 18:04:26 +05:30
function buildConfigMenu (
t : ReturnType < typeof getMenuTranslations > ,
) : MenuItemConstructorOptions {
2025-12-22 09:18:21 +08:00
const presets = getAllPresets ( )
const currentPresetId = getCurrentPresetId ( )
const presetItems : MenuItemConstructorOptions [ ] = presets . map ( ( preset ) = > ( {
label : preset.name ,
type : "radio" ,
checked : preset.id === currentPresetId ,
click : async ( ) = > {
const previousPresetId = getCurrentPresetId ( )
const env = applyPresetToEnv ( preset . id )
if ( env ) {
try {
await restartNextServer ( )
rebuildAppMenu ( ) // Rebuild menu to update checkmarks
} catch ( error ) {
console . error ( "Failed to restart server:" , error )
// Revert to previous preset on failure
if ( previousPresetId ) {
applyPresetToEnv ( previousPresetId )
} else {
setCurrentPreset ( null )
}
// Rebuild menu to restore previous checkmark state
rebuildAppMenu ( )
// Show error dialog to notify user
dialog . showErrorBox (
"Configuration Error" ,
` Failed to apply preset " ${ preset . name } ". The server could not be restarted. \ n \ nThe previous configuration has been restored. \ n \ nError: ${ error instanceof Error ? error.message : String ( error ) } ` ,
)
}
}
} ,
} ) )
return {
2026-01-16 18:04:26 +05:30
label : t.configuration ,
2025-12-22 09:18:21 +08:00
submenu : [
. . . ( presetItems . length > 0
? [
2026-01-16 18:04:26 +05:30
{ label : t.switchPreset , enabled : false } ,
2025-12-22 09:18:21 +08:00
{ type : "separator" } as MenuItemConstructorOptions ,
. . . presetItems ,
{ type : "separator" } as MenuItemConstructorOptions ,
]
: [ ] ) ,
{
label :
presetItems . length > 0
2026-01-16 18:04:26 +05:30
? t . managePresets
: t . addConfigurationPreset ,
2025-12-22 09:18:21 +08:00
click : ( ) = > {
const win = BrowserWindow . getFocusedWindow ( )
showSettingsWindow ( win || undefined )
} ,
} ,
] ,
}
}