fix: macosx UI cleanup

This commit is contained in:
2026-02-19 22:50:21 +01:00
parent 7e593b587b
commit 0d66939eb7
8 changed files with 333 additions and 176 deletions

View File

@@ -83,6 +83,33 @@ function runWebContentsMenuAction(sender: any, action: AppMenuAction): boolean {
case 'toggleDevTools':
sender.toggleDevTools?.();
return true;
case 'reload':
sender.reload?.();
return true;
case 'forceReload':
sender.reloadIgnoringCache?.();
return true;
case 'resetZoom':
sender.setZoomLevel?.(0);
return true;
case 'zoomIn': {
const currentZoomLevel = sender.getZoomLevel?.() ?? 0;
sender.setZoomLevel?.(currentZoomLevel + 0.5);
return true;
}
case 'zoomOut': {
const currentZoomLevel = sender.getZoomLevel?.() ?? 0;
sender.setZoomLevel?.(currentZoomLevel - 0.5);
return true;
}
case 'toggleFullScreen': {
const ownerWindow = BrowserWindow.fromWebContents(sender);
if (!ownerWindow) {
return false;
}
ownerWindow.setFullScreen(!ownerWindow.isFullScreen());
return true;
}
default:
return false;
}
@@ -748,6 +775,17 @@ export function registerIpcHandlers(): void {
return;
}
if (typedAction === 'openInBrowser') {
await shell.openExternal('http://localhost:4123/');
return;
}
if (typedAction === 'openDataFolder') {
const paths = getDatabase().getDataPaths();
await shell.openPath(path.dirname(paths.database));
return;
}
if (typedAction === 'reportIssue') {
await shell.openExternal('https://github.com/rfc1437/bDS/issues');
return;

View File

@@ -8,13 +8,13 @@ import { eq } from 'drizzle-orm';
import { getMediaEngine } from './engine/MediaEngine';
import { getPostEngine } from './engine/PostEngine';
import { PreviewServer } from './engine/PreviewServer';
import { APP_MENU_ACTION_EVENT_MAP, APP_MENU_GROUPS, type AppMenuAction, type AppMenuItemDefinition } from './shared/menuCommands';
import { APP_MENU_ACTION_EVENT_MAP, APP_MENU_GROUPS, APP_MENU_ITEM_IDS, type AppMenuAction, type AppMenuItemDefinition } from './shared/menuCommands';
let mainWindow: BrowserWindow | null = null;
let previewServer: PreviewServer | null = null;
let activePreviewPostId: string | null = null;
const PREVIEW_SERVER_PORT = 4123;
const BLOG_PREVIEW_POST_MENU_ID = 'blog.previewPost';
const BLOG_PREVIEW_POST_MENU_ID = APP_MENU_ITEM_IDS.previewPost;
// Check if dev server is likely running (only in development)
const isDev = process.env.NODE_ENV === 'development';
@@ -178,12 +178,70 @@ function createApplicationMenu(): Menu {
return acc;
}, {});
const triggerMenuAction = (action: AppMenuAction): void => {
const triggerMenuAction = async (action: AppMenuAction): Promise<void> => {
if (action === 'quit') {
app.quit();
return;
}
if (action === 'openInBrowser') {
await openPreviewInBrowser().catch((error) => {
console.error('Failed to open preview in browser:', error);
});
return;
}
if (action === 'openDataFolder') {
const paths = getDatabase().getDataPaths();
void shell.openPath(path.dirname(paths.database));
return;
}
if (action === 'previewPost') {
await openActivePostPreviewInBrowser().catch((error) => {
console.error('Failed to preview active post in browser:', error);
});
return;
}
if (action === 'reload') {
mainWindow?.webContents.reload();
return;
}
if (action === 'forceReload') {
mainWindow?.webContents.reloadIgnoringCache();
return;
}
if (action === 'resetZoom') {
mainWindow?.webContents.setZoomLevel(0);
return;
}
if (action === 'zoomIn') {
if (mainWindow) {
const zoomLevel = mainWindow.webContents.getZoomLevel();
mainWindow.webContents.setZoomLevel(zoomLevel + 0.5);
}
return;
}
if (action === 'zoomOut') {
if (mainWindow) {
const zoomLevel = mainWindow.webContents.getZoomLevel();
mainWindow.webContents.setZoomLevel(zoomLevel - 0.5);
}
return;
}
if (action === 'toggleFullScreen') {
if (mainWindow) {
mainWindow.setFullScreen(!mainWindow.isFullScreen());
}
return;
}
if (action === 'viewOnGitHub') {
void shell.openExternal('https://github.com/rfc1437/bDS');
return;
@@ -217,8 +275,10 @@ function createApplicationMenu(): Menu {
return {
label: definition.label,
accelerator: definition.accelerator,
click: () => {
triggerMenuAction(action);
id: definition.id,
enabled: definition.enabled,
click: async () => {
await triggerMenuAction(action);
},
};
};
@@ -229,7 +289,9 @@ function createApplicationMenu(): Menu {
return [];
}
return group.items.map((item) => {
const filteredItems = group.items.filter(item => isDev || item.action !== 'toggleDevTools');
return filteredItems.map((item) => {
if (item.separator) {
return { type: 'separator' };
}
@@ -241,33 +303,7 @@ function createApplicationMenu(): Menu {
const template: MenuItemConstructorOptions[] = [
{
label: 'File',
submenu: [
buildSharedMenuItem('newPost'),
buildSharedMenuItem('importMedia'),
{ type: 'separator' },
buildSharedMenuItem('save'),
{ type: 'separator' },
{
label: 'Open in Browser',
click: async () => {
try {
await openPreviewInBrowser();
} catch (error) {
console.error('Failed to open preview in browser:', error);
}
},
},
{ type: 'separator' },
{
label: 'Open Data Folder',
click: async () => {
const paths = getDatabase().getDataPaths();
shell.openPath(path.dirname(paths.database));
},
},
{ type: 'separator' },
buildSharedMenuItem('quit'),
],
submenu: buildSharedGroupMenuItems('File'),
},
{
label: 'Edit',
@@ -275,51 +311,11 @@ function createApplicationMenu(): Menu {
},
{
label: 'View',
submenu: [
...buildSharedGroupMenuItems('View'),
{ type: 'separator' },
{ role: 'reload' },
{ role: 'forceReload' },
{
label: 'Toggle Developer Tools',
accelerator: process.platform === 'darwin' ? 'Cmd+Option+I' : 'Ctrl+Shift+I',
click: () => {
mainWindow?.webContents.toggleDevTools();
},
},
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ type: 'separator' },
{ role: 'togglefullscreen' },
],
submenu: buildSharedGroupMenuItems('View'),
},
{
label: 'Blog',
submenu: [
buildSharedMenuItem('publishSelected'),
{ type: 'separator' },
{
label: 'Preview Post',
id: BLOG_PREVIEW_POST_MENU_ID,
enabled: false,
accelerator: 'CmdOrCtrl+Shift+V',
click: async () => {
try {
await openActivePostPreviewInBrowser();
} catch (error) {
console.error('Failed to preview active post in browser:', error);
}
},
},
{ type: 'separator' },
buildSharedMenuItem('rebuildDatabase'),
buildSharedMenuItem('reindexText'),
{ type: 'separator' },
buildSharedMenuItem('metadataDiff'),
buildSharedMenuItem('generateSitemap'),
],
submenu: buildSharedGroupMenuItems('Blog'),
},
{
label: 'Help',

View File

@@ -2,6 +2,8 @@ export type AppMenuAction =
| 'newPost'
| 'importMedia'
| 'save'
| 'openInBrowser'
| 'openDataFolder'
| 'quit'
| 'undo'
| 'redo'
@@ -17,7 +19,14 @@ export type AppMenuAction =
| 'toggleSidebar'
| 'togglePanel'
| 'toggleDevTools'
| 'reload'
| 'forceReload'
| 'resetZoom'
| 'zoomIn'
| 'zoomOut'
| 'toggleFullScreen'
| 'publishSelected'
| 'previewPost'
| 'rebuildDatabase'
| 'reindexText'
| 'metadataDiff'
@@ -35,6 +44,8 @@ export interface AppMenuItemDefinition {
accelerator?: string;
separator?: boolean;
role?: AppMenuRole;
id?: string;
enabled?: boolean;
}
export interface AppMenuGroupDefinition {
@@ -42,14 +53,23 @@ export interface AppMenuGroupDefinition {
items: AppMenuItemDefinition[];
}
export const APP_MENU_ITEM_IDS = {
previewPost: 'blog.previewPost',
} as const;
export const APP_MENU_GROUPS: AppMenuGroupDefinition[] = [
{
label: 'File',
items: [
{ label: 'New Post', action: 'newPost', accelerator: 'CmdOrCtrl+N' },
{ label: 'Import Media...', action: 'importMedia', accelerator: 'CmdOrCtrl+I' },
{ label: '', action: 'file-separator-0', separator: true },
{ label: 'Save', action: 'save', accelerator: 'CmdOrCtrl+S' },
{ label: '', action: 'file-separator-1', separator: true },
{ label: 'Open in Browser', action: 'openInBrowser' },
{ label: '', action: 'file-separator-2', separator: true },
{ label: 'Open Data Folder', action: 'openDataFolder' },
{ label: '', action: 'file-separator-3', separator: true },
{ label: 'Quit', action: 'quit', accelerator: 'CmdOrCtrl+Q' },
],
},
@@ -78,14 +98,27 @@ export const APP_MENU_GROUPS: AppMenuGroupDefinition[] = [
{ label: 'Toggle Sidebar', action: 'toggleSidebar', accelerator: 'CmdOrCtrl+B' },
{ label: 'Toggle Panel', action: 'togglePanel', accelerator: 'CmdOrCtrl+J' },
{ label: 'Toggle Developer Tools', action: 'toggleDevTools', accelerator: 'CmdOrCtrl+Shift+I' },
{ label: '', action: 'view-separator-1', separator: true },
{ label: 'Reload', action: 'reload' },
{ label: 'Force Reload', action: 'forceReload' },
{ label: '', action: 'view-separator-2', separator: true },
{ label: 'Actual Size', action: 'resetZoom' },
{ label: 'Zoom In', action: 'zoomIn' },
{ label: 'Zoom Out', action: 'zoomOut' },
{ label: '', action: 'view-separator-3', separator: true },
{ label: 'Toggle Full Screen', action: 'toggleFullScreen' },
],
},
{
label: 'Blog',
items: [
{ label: 'Publish Selected', action: 'publishSelected', accelerator: 'CmdOrCtrl+Shift+P' },
{ label: '', action: 'blog-separator-1', separator: true },
{ label: 'Preview Post', action: 'previewPost', id: APP_MENU_ITEM_IDS.previewPost, enabled: false, accelerator: 'CmdOrCtrl+Shift+V' },
{ label: '', action: 'blog-separator-2', separator: true },
{ label: 'Rebuild Database from Files', action: 'rebuildDatabase' },
{ label: 'Reindex Search Text', action: 'reindexText' },
{ label: '', action: 'blog-separator-3', separator: true },
{ label: 'Metadata Diff Tool', action: 'metadataDiff' },
{ label: 'Generate Sitemap', action: 'generateSitemap' },
],
@@ -113,6 +146,7 @@ export const APP_MENU_ACTION_EVENT_MAP: Partial<Record<AppMenuAction, string>> =
toggleSidebar: 'menu:toggleSidebar',
togglePanel: 'menu:togglePanel',
toggleDevTools: 'menu:toggleDevTools',
previewPost: 'menu:previewPost',
publishSelected: 'menu:publishSelected',
rebuildDatabase: 'menu:rebuildDatabase',
reindexText: 'menu:reindexText',
@@ -131,4 +165,10 @@ export const APP_MENU_WEB_CONTENTS_ACTIONS: ReadonlySet<AppMenuAction> = new Set
'delete',
'selectAll',
'toggleDevTools',
'reload',
'forceReload',
'resetZoom',
'zoomIn',
'zoomOut',
'toggleFullScreen',
]);