feat(desktop): add tray behavior and packaging config

This commit is contained in:
nav
2026-05-13 06:57:27 +00:00
parent 5843d3f8ca
commit 54f4b46755
5 changed files with 3397 additions and 10 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
node_modules/ node_modules/
dist/

View File

@@ -26,3 +26,39 @@ npm run start:dev
```bash ```bash
npm start npm start
``` ```
## Build / Release
先安装依赖(包含 `electron-builder`
```bash
npm install
```
仅打包目录(不生成安装包):
```bash
npm run pack
```
跨平台构建入口:
```bash
npm run dist
```
按平台构建:
```bash
npm run dist:linux
npm run dist:mac
npm run dist:win
```
构建产物输出到:
- `dist/`
产物命名规范:
- `Fabric-Desktop-${version}-${os}-${arch}.${ext}`

78
main.js
View File

@@ -1,4 +1,4 @@
const { app, BrowserWindow, Menu, ipcMain, Notification, shell } = require('electron') const { app, BrowserWindow, Menu, Tray, ipcMain, Notification, nativeImage, shell } = require('electron')
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
@@ -6,6 +6,10 @@ const isDev = !!process.env.FABRIC_DESKTOP_URL
const DEFAULT_DEV_URL = 'http://localhost:5173' const DEFAULT_DEV_URL = 'http://localhost:5173'
const DEFAULT_PROD_ENTRY = path.join(__dirname, 'offline.html') const DEFAULT_PROD_ENTRY = path.join(__dirname, 'offline.html')
let mainWindow = null
let tray = null
let isQuitting = false
function configPath() { function configPath() {
return path.join(app.getPath('userData'), 'fabric-desktop.config.json') return path.join(app.getPath('userData'), 'fabric-desktop.config.json')
} }
@@ -81,11 +85,72 @@ function createWindow() {
} else { } else {
win.loadFile(DEFAULT_PROD_ENTRY) win.loadFile(DEFAULT_PROD_ENTRY)
} }
win.on('close', (event) => {
if (!isQuitting) {
event.preventDefault()
win.hide()
}
})
return win
}
function createTrayIcon() {
if (tray) return tray
const iconDataUrl =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAfElEQVR4AWNw4PjPwMDA8J+BgYHhP4MDA8N/BgYGhv8MDAwM/2dgYGB4R2JgYGB4w8DAwPCfgYGB4R8DAwPDf4aGhob/BgwMDAz/Z2BgYHhHYmBgYHjDwMDA8J+BgYHhHwMDA8N/hoYGhv8GDAwMDP9nYGBgeEdiYGAAAB7RImfVq6X8AAAAAElFTkSuQmCC'
const icon = nativeImage.createFromDataURL(iconDataUrl)
tray = new Tray(icon)
tray.setToolTip('Fabric Desktop')
const buildTrayMenu = () =>
Menu.buildFromTemplate([
{
label: mainWindow?.isVisible() ? '隐藏窗口' : '显示窗口',
click: () => {
if (!mainWindow) {
mainWindow = createWindow()
return
}
if (mainWindow.isVisible()) mainWindow.hide()
else {
mainWindow.show()
mainWindow.focus()
}
tray.setContextMenu(buildTrayMenu())
},
},
{
label: '退出',
click: () => {
isQuitting = true
app.quit()
},
},
])
tray.setContextMenu(buildTrayMenu())
tray.on('double-click', () => {
if (!mainWindow) {
mainWindow = createWindow()
return
}
mainWindow.show()
mainWindow.focus()
tray.setContextMenu(buildTrayMenu())
})
return tray
} }
app.whenReady().then(() => { app.whenReady().then(() => {
createMenu() createMenu()
createWindow() mainWindow = createWindow()
createTrayIcon()
ipcMain.handle('fabric:config:get', () => readConfig()) ipcMain.handle('fabric:config:get', () => readConfig())
ipcMain.handle('fabric:config:set', (_evt, next) => writeConfig(next || {})) ipcMain.handle('fabric:config:set', (_evt, next) => writeConfig(next || {}))
@@ -100,10 +165,15 @@ app.whenReady().then(() => {
}) })
app.on('activate', () => { app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow() if (BrowserWindow.getAllWindows().length === 0) mainWindow = createWindow()
else if (mainWindow && !mainWindow.isVisible()) mainWindow.show()
})
app.on('before-quit', () => {
isQuitting = true
}) })
}) })
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit() // 保持后台驻留,由托盘控制退出
}) })

3239
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,12 +2,61 @@
"name": "fabric-desktop", "name": "fabric-desktop",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"description": "Electron desktop shell for Fabric frontend.",
"homepage": "https://github.com/hangman0414/Fabric",
"author": {
"name": "Hangman",
"email": "hangman@example.com"
},
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
"start": "electron .", "start": "electron .",
"start:dev": "FABRIC_DESKTOP_URL=http://localhost:5173 electron ." "start:dev": "FABRIC_DESKTOP_URL=http://localhost:5173 electron .",
"pack": "electron-builder --dir",
"dist": "electron-builder",
"dist:linux": "electron-builder --linux AppImage deb tar.gz",
"dist:mac": "electron-builder --mac dmg zip",
"dist:win": "electron-builder --win nsis zip"
}, },
"devDependencies": { "devDependencies": {
"electron": "^37.2.1" "electron": "^37.2.1",
"electron-builder": "^24.13.3"
},
"build": {
"appId": "ai.hangman.fabric.desktop",
"productName": "Fabric Desktop",
"artifactName": "Fabric-Desktop-${version}-${os}-${arch}.${ext}",
"directories": {
"output": "dist"
},
"files": [
"main.js",
"preload.js",
"offline.html",
"package.json"
],
"asar": true,
"linux": {
"target": [
"AppImage",
"deb",
"tar.gz"
],
"category": "Utility",
"maintainer": "Hangman <hangman@example.com>"
},
"mac": {
"target": [
"dmg",
"zip"
],
"category": "public.app-category.productivity"
},
"win": {
"target": [
"nsis",
"zip"
]
}
} }
} }