feat(phase1): architecture skeleton

- Electron 33 main process with frameless window, IPC, win-state persistence
- Preload with contextBridge typed API (window, theme, dialog)
- Vue 3 + Pinia + Element Plus + Vue Router renderer
- Dark/light dual theme via CSS custom properties
- TitleBar with window controls + theme toggle
- StatusBar placeholder
- Design spec document
This commit is contained in:
2026-07-04 17:21:00 +08:00
parent 3e06def637
commit 7e5d61c099
20 changed files with 8338 additions and 2 deletions
+35
View File
@@ -0,0 +1,35 @@
// src/main/ipc-handlers.ts
import { ipcMain, BrowserWindow, nativeTheme, dialog } from 'electron'
export function registerIpcHandlers(): void {
ipcMain.on('window:minimize', () => {
BrowserWindow.getFocusedWindow()?.minimize()
})
ipcMain.on('window:maximize', () => {
const win = BrowserWindow.getFocusedWindow()
if (win) win.isMaximized() ? win.unmaximize() : win.maximize()
})
ipcMain.on('window:close', () => {
BrowserWindow.getFocusedWindow()?.close()
})
ipcMain.handle('theme:get', () => nativeTheme.shouldUseDarkColors)
ipcMain.on('theme:set', (_event, theme: 'system' | 'dark' | 'light') => {
nativeTheme.themeSource = theme
})
ipcMain.handle('dialog:openFile', async (_event, options: Electron.OpenDialogOptions) => {
const win = BrowserWindow.getFocusedWindow()
if (!win) return null
const result = await dialog.showOpenDialog(win, options)
if (result.canceled || result.filePaths.length === 0) return null
const fs = await import('fs')
try {
const content = fs.readFileSync(result.filePaths[0], 'utf-8')
return { path: result.filePaths[0], content }
} catch { return null }
})
}