Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/components/windows-titlebar.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
import { __experimentalHStack as HStack } from '@wordpress/components';
import { Icon, menu } from '@wordpress/icons';
import appIcon from '../../assets/titlebar-icon.svg';
import { getAppGlobals } from '../lib/app-globals';
import { cx } from '../lib/cx';
import { getIpcApi } from '../lib/get-ipc-api';
import Button from './button';

export default function WindowsTitlebar( { className }: { className?: string } ) {
return (
<HStack alignment="left" className={ cx( 'bg-chrome text-white pl-4', className ) } spacing="4">
<img src={ appIcon } alt="" className="w-[16px] flex-shrink-0" />
<h1 className="text-xs">{ getAppGlobals().appName }</h1>
<HStack alignment="left" className={ cx( 'bg-chrome text-white', className ) } spacing="2">
<Button
variant="icon"
onClick={ () => {
getIpcApi().popupAppMenu();
} }
className="!px-3 !py-2 app-no-drag-region"
>
<Icon icon={ menu } className="text-white" size={ 18 } />
</Button>

<div className="flex gap-2 app-drag">
<img src={ appIcon } alt="" className="w-[16px] flex-shrink-0" />
<h1 className="text-xs">{ getAppGlobals().appName }</h1>
</div>
</HStack>
);
}
5 changes: 5 additions & 0 deletions src/ipc-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
removeLegacySqliteIntegrationPlugin,
} from './lib/sqlite-versions';
import { writeLogToFile, type LogLevel } from './logging';
import { popupMenu } from './menu';
import { SiteServer, createSiteWorkingDirectory } from './site-server';
import { DEFAULT_SITE_PATH, getServerFilesPath, getSiteThumbnailPath } from './storage/paths';
import { loadUserData, saveUserData } from './storage/user-data';
Expand Down Expand Up @@ -608,3 +609,7 @@ export async function showNotification(
) {
new Notification( options ).show();
}

export function popupAppMenu( _event: IpcMainInvokeEvent ) {
popupMenu();
}
89 changes: 57 additions & 32 deletions src/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,27 @@ export function setupMenu( mainWindow: BrowserWindow | null ) {
Menu.setApplicationMenu( null );
return;
}
const menu = getAppMenu( mainWindow );
if ( process.platform === 'darwin' ) {
Menu.setApplicationMenu( menu );
return;
}
// Make menu accessible in development for non-macOS platforms
if ( process.env.NODE_ENV === 'development' ) {
mainWindow?.setMenu( menu );
return;
}
Menu.setApplicationMenu( null );
}

export function popupMenu() {
withMainWindow( ( window ) => {
const menu = getAppMenu( window );
menu.popup();
} );
}

function getAppMenu( mainWindow: BrowserWindow | null ) {
const crashTestMenuItems: MenuItemConstructorOptions[] = [
{
label: __( 'Test Hard Crash (dev only)' ),
Expand All @@ -40,7 +60,7 @@ export function setupMenu( mainWindow: BrowserWindow | null ) {
{ type: 'separator' },
];

const menu = Menu.buildFromTemplate( [
return Menu.buildFromTemplate( [
{
label: app.name, // macOS ignores this name and uses the name from the .plist
role: 'appMenu',
Expand Down Expand Up @@ -68,9 +88,13 @@ export function setupMenu( mainWindow: BrowserWindow | null ) {
},
},
{ type: 'separator' },
{ role: 'services' },
...( process.platform === 'win32'
? []
: [ { role: 'services' } as MenuItemConstructorOptions ] ),
{ type: 'separator' },
{ role: 'hide' },
...( process.platform === 'win32'
? []
: [ { role: 'hide' } as MenuItemConstructorOptions ] ),
{ type: 'separator' },
...( process.env.NODE_ENV === 'development' ? crashTestMenuItems : [] ),
{ type: 'separator' },
Expand All @@ -89,19 +113,27 @@ export function setupMenu( mainWindow: BrowserWindow | null ) {
} );
},
},
{
label: __( 'Close Window' ),
accelerator: 'CommandOrControl+W',
click: ( _menuItem, browserWindow ) => {
browserWindow?.close();
},
enabled: !! mainWindow && ! mainWindow.isDestroyed(),
},
...( process.platform === 'win32'
? []
: [
{
label: __( 'Close Window' ),
accelerator: 'CommandOrControl+W',
click: ( _menuItem, browserWindow ) => {
browserWindow?.close();
},
enabled: !! mainWindow && ! mainWindow.isDestroyed(),
} as MenuItemConstructorOptions,
] ),
],
},
{
role: 'editMenu',
},
...( process.platform === 'win32'
? []
: [
{
role: 'editMenu',
} as MenuItemConstructorOptions,
] ),
{
role: 'viewMenu',
submenu: [
Expand All @@ -113,13 +145,17 @@ export function setupMenu( mainWindow: BrowserWindow | null ) {
{ role: 'togglefullscreen' },
],
},
{
role: 'windowMenu',
// We can't remove all of the items which aren't relevant to us (anything for
// managing multiple window instances), but this seems to remove as many of
// them as we can.
submenu: [ { role: 'minimize' }, { role: 'zoom' } ],
},
...( process.platform === 'win32'
? []
: [
{
role: 'windowMenu',
// We can't remove all of the items which aren't relevant to us (anything for
// managing multiple window instances), but this seems to remove as many of
// them as we can.
submenu: [ { role: 'minimize' }, { role: 'zoom' } ],
} as MenuItemConstructorOptions,
] ),
{
role: 'help',
submenu: [
Expand All @@ -132,15 +168,4 @@ export function setupMenu( mainWindow: BrowserWindow | null ) {
],
},
] );

if ( process.platform === 'darwin' ) {
Menu.setApplicationMenu( menu );
return;
}
// Make menu accessible in development for non-macOS platforms
if ( process.env.NODE_ENV === 'development' ) {
mainWindow?.setMenu( menu );
return;
}
Menu.setApplicationMenu( null );
}
1 change: 1 addition & 0 deletions src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const api: IpcApi = {
// Use .send instead of .invoke because logging is fire-and-forget
logRendererMessage: ( level: LogLevel, ...args: any[] ) =>
ipcRenderer.send( 'logRendererMessage', level, ...args ),
popupAppMenu: () => ipcRenderer.invoke( 'popupAppMenu' ),
};

contextBridge.exposeInMainWorld( 'ipcApi', api );
Expand Down