feat: implement custom window controls and replace header bar with title bar

- Add window handlers for minimize, maximize, close, and check if maximized in ipcMain.
- Update preload script to use new window control IPC events.
- Refactor window service to remove old IPC event handlers and use new handlers.
- Remove old HeaderBar and DragRegion components, replacing them with a new TitleBar component.
- Update Layout component to use TitleBar instead of HeaderBar.
- Remove useWinManager hook as its functionality is now integrated into TitleBar.
- Update login page to remove HeaderBar and adjust layout accordingly.
- Update constants to remove old window IPC events.
- Update package dependencies to replace @iconify/vue with @lucide/vue.
This commit is contained in:
duanshuwen
2026-04-14 23:38:42 +08:00
parent 6fd51d04dd
commit b5a67ff650
20 changed files with 642 additions and 340 deletions

View File

@@ -2,7 +2,6 @@ import type { WindowNames } from '@lib/types'
import { CONFIG_KEYS, IPC_EVENTS, WINDOW_NAMES } from '@lib/constants'
import { BrowserWindow, BrowserWindowConstructorOptions, ipcMain, IpcMainInvokeEvent, type IpcMainEvent } from 'electron'
import { debounce } from '@lib/utils'
import { createLogo } from '@electron/utils'
import logManager from '@electron/service/logger'
@@ -26,10 +25,14 @@ interface SizeOptions {
minHeight?: number; // 窗口最小高度,可选
}
const isMac = process.platform === 'darwin';
const isWindows = process.platform === 'win32';
const useCustomTitleBar = isWindows;
const SHARED_WINDOW_OPTIONS = {
frame: false,
titleBarStyle: 'hidden',
trafficLightPosition: { x: -100, y: -100 },
frame: isMac || !useCustomTitleBar,
titleBarStyle: isMac ? 'hiddenInset' : useCustomTitleBar ? 'hidden' : 'default',
trafficLightPosition: isMac ? { x: 16, y: 16 } : undefined,
show: false,
title: 'NIANXX',
darkTheme: themeManager.isDark,
@@ -71,29 +74,6 @@ class WindowService {
}
private _setupIpcEvents() {
const handleCloseWindow = (e: IpcMainEvent) => {
const target = BrowserWindow.fromWebContents(e.sender);
const winName = this.getName(target);
this.close(target, this._isReallyClose(winName));
}
const handleMinimizeWindow = (e: IpcMainEvent) => {
BrowserWindow.fromWebContents(e.sender)?.minimize();
}
const handleMaximizeWindow = (e: IpcMainEvent) => {
this.toggleMax(BrowserWindow.fromWebContents(e.sender));
}
const handleIsWindowMaximized = (e: IpcMainInvokeEvent) => {
return BrowserWindow.fromWebContents(e.sender)?.isMaximized() ?? false;
}
ipcMain.on(IPC_EVENTS.WINDOW_CLOSE, handleCloseWindow);
ipcMain.on(IPC_EVENTS.WINDOW_MINIMIZE, handleMinimizeWindow);
ipcMain.on(IPC_EVENTS.WINDOW_MAXIMIZE, handleMaximizeWindow);
ipcMain.handle(IPC_EVENTS.IS_WINDOW_MAXIMIZED, handleIsWindowMaximized);
ipcMain.handle(IPC_EVENTS.APP_LOAD_PAGE, (e: IpcMainInvokeEvent, page: string) => {
const win = BrowserWindow.fromWebContents(e.sender);
if (win) this._loadPage(win, page);
@@ -139,17 +119,13 @@ class WindowService {
}
private _setupWinLifecycle(window: BrowserWindow, name: WindowNames) {
const updateWinStatus = debounce(() => !window?.isDestroyed()
&& window?.webContents?.send(IPC_EVENTS.WINDOW_MAXIMIZE + 'back', window?.isMaximized()), 80);
window.once('closed', () => {
this._winStates[name].onClosed.forEach(callback => callback(window));
window?.destroy();
window?.removeListener('resize', updateWinStatus);
this._winStates[name].instance = void 0;
this._winStates[name].isHidden = false;
logManager.info(`Window closed: ${name}`);
});
window.on('resize', updateWinStatus)
return this;
}