's'
This commit is contained in:
@@ -9,7 +9,8 @@
|
||||
"dev": "electron-vite dev",
|
||||
"build": "electron-vite build",
|
||||
"preview": "electron-vite preview",
|
||||
"dist": "pnpm run build && electron-builder --win --publish never"
|
||||
"gen:icons": "node ./scripts/generate-icons.mjs",
|
||||
"dist": "pnpm run build && pnpm run gen:icons && electron-builder --win --publish never"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3": "^7.9.0",
|
||||
@@ -28,9 +29,11 @@
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@types/three": "^0.183.1",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@resvg/resvg-js": "^2.6.2",
|
||||
"electron": "^33.2.0",
|
||||
"electron-builder": "^25.1.8",
|
||||
"electron-vite": "^2.3.0",
|
||||
"png-to-ico": "^2.1.0",
|
||||
"typescript": "~5.6.2",
|
||||
"vite": "^5.4.11"
|
||||
},
|
||||
@@ -38,7 +41,8 @@
|
||||
"onlyBuiltDependencies": [
|
||||
"electron",
|
||||
"electron-builder",
|
||||
"esbuild"
|
||||
"esbuild",
|
||||
"@resvg/resvg-js"
|
||||
]
|
||||
},
|
||||
"build": {
|
||||
@@ -50,7 +54,8 @@
|
||||
},
|
||||
"files": [
|
||||
"out/**/*",
|
||||
"package.json"
|
||||
"package.json",
|
||||
"build/**/*"
|
||||
],
|
||||
"extraResources": [
|
||||
{
|
||||
@@ -68,9 +73,10 @@
|
||||
}
|
||||
],
|
||||
"win": {
|
||||
"icon": "build/icon.ico",
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
"target": "portable",
|
||||
"arch": [
|
||||
"x64"
|
||||
]
|
||||
|
||||
155
electron/pnpm-lock.yaml
generated
155
electron/pnpm-lock.yaml
generated
@@ -30,6 +30,9 @@ importers:
|
||||
specifier: ^0.183.2
|
||||
version: 0.183.2
|
||||
devDependencies:
|
||||
'@resvg/resvg-js':
|
||||
specifier: ^2.6.2
|
||||
version: 2.6.2
|
||||
'@types/d3':
|
||||
specifier: ^7.4.3
|
||||
version: 7.4.3
|
||||
@@ -60,6 +63,9 @@ importers:
|
||||
electron-vite:
|
||||
specifier: ^2.3.0
|
||||
version: 2.3.0(vite@5.4.21(@types/node@22.19.15))
|
||||
png-to-ico:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.8
|
||||
typescript:
|
||||
specifier: ~5.6.2
|
||||
version: 5.6.3
|
||||
@@ -377,6 +383,82 @@ packages:
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@resvg/resvg-js-android-arm-eabi@2.6.2':
|
||||
resolution: {integrity: sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@resvg/resvg-js-android-arm64@2.6.2':
|
||||
resolution: {integrity: sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@resvg/resvg-js-darwin-arm64@2.6.2':
|
||||
resolution: {integrity: sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@resvg/resvg-js-darwin-x64@2.6.2':
|
||||
resolution: {integrity: sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@resvg/resvg-js-linux-arm-gnueabihf@2.6.2':
|
||||
resolution: {integrity: sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@resvg/resvg-js-linux-arm64-gnu@2.6.2':
|
||||
resolution: {integrity: sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@resvg/resvg-js-linux-arm64-musl@2.6.2':
|
||||
resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@resvg/resvg-js-linux-x64-gnu@2.6.2':
|
||||
resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@resvg/resvg-js-linux-x64-musl@2.6.2':
|
||||
resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@resvg/resvg-js-win32-arm64-msvc@2.6.2':
|
||||
resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@resvg/resvg-js-win32-ia32-msvc@2.6.2':
|
||||
resolution: {integrity: sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@resvg/resvg-js-win32-x64-msvc@2.6.2':
|
||||
resolution: {integrity: sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@resvg/resvg-js@2.6.2':
|
||||
resolution: {integrity: sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.27':
|
||||
resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==}
|
||||
|
||||
@@ -649,6 +731,9 @@ packages:
|
||||
'@types/ms@2.1.0':
|
||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||
|
||||
'@types/node@17.0.45':
|
||||
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
|
||||
|
||||
'@types/node@20.19.37':
|
||||
resolution: {integrity: sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==}
|
||||
|
||||
@@ -1869,10 +1954,19 @@ packages:
|
||||
resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==}
|
||||
engines: {node: '>=10.4.0'}
|
||||
|
||||
png-to-ico@2.1.8:
|
||||
resolution: {integrity: sha512-Nf+IIn/cZ/DIZVdGveJp86NG5uNib1ZXMiDd/8x32HCTeKSvgpyg6D/6tUBn1QO/zybzoMK0/mc3QRgAyXdv9w==}
|
||||
engines: {node: '>=8'}
|
||||
hasBin: true
|
||||
|
||||
pngjs@5.0.0:
|
||||
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
pngjs@6.0.0:
|
||||
resolution: {integrity: sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==}
|
||||
engines: {node: '>=12.13.0'}
|
||||
|
||||
postcss@8.5.8:
|
||||
resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
@@ -2618,6 +2712,57 @@ snapshots:
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-android-arm-eabi@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-android-arm64@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-darwin-arm64@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-darwin-x64@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-linux-arm-gnueabihf@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-linux-arm64-gnu@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-linux-arm64-musl@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-linux-x64-gnu@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-linux-x64-musl@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-win32-arm64-msvc@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-win32-ia32-msvc@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js-win32-x64-msvc@2.6.2':
|
||||
optional: true
|
||||
|
||||
'@resvg/resvg-js@2.6.2':
|
||||
optionalDependencies:
|
||||
'@resvg/resvg-js-android-arm-eabi': 2.6.2
|
||||
'@resvg/resvg-js-android-arm64': 2.6.2
|
||||
'@resvg/resvg-js-darwin-arm64': 2.6.2
|
||||
'@resvg/resvg-js-darwin-x64': 2.6.2
|
||||
'@resvg/resvg-js-linux-arm-gnueabihf': 2.6.2
|
||||
'@resvg/resvg-js-linux-arm64-gnu': 2.6.2
|
||||
'@resvg/resvg-js-linux-arm64-musl': 2.6.2
|
||||
'@resvg/resvg-js-linux-x64-gnu': 2.6.2
|
||||
'@resvg/resvg-js-linux-x64-musl': 2.6.2
|
||||
'@resvg/resvg-js-win32-arm64-msvc': 2.6.2
|
||||
'@resvg/resvg-js-win32-ia32-msvc': 2.6.2
|
||||
'@resvg/resvg-js-win32-x64-msvc': 2.6.2
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.27': {}
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.60.0':
|
||||
@@ -2870,6 +3015,8 @@ snapshots:
|
||||
|
||||
'@types/ms@2.1.0': {}
|
||||
|
||||
'@types/node@17.0.45': {}
|
||||
|
||||
'@types/node@20.19.37':
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
@@ -4300,8 +4447,16 @@ snapshots:
|
||||
base64-js: 1.5.1
|
||||
xmlbuilder: 15.1.1
|
||||
|
||||
png-to-ico@2.1.8:
|
||||
dependencies:
|
||||
'@types/node': 17.0.45
|
||||
minimist: 1.2.8
|
||||
pngjs: 6.0.0
|
||||
|
||||
pngjs@5.0.0: {}
|
||||
|
||||
pngjs@6.0.0: {}
|
||||
|
||||
postcss@8.5.8:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
|
||||
46
electron/scripts/generate-icons.mjs
Normal file
46
electron/scripts/generate-icons.mjs
Normal file
@@ -0,0 +1,46 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import pngToIco from 'png-to-ico'
|
||||
import { Resvg } from '@resvg/resvg-js'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
const root = path.resolve(__dirname, '..')
|
||||
const buildDir = path.join(root, 'build')
|
||||
const srcSvg = path.join(buildDir, 'app-icon.svg')
|
||||
const outPng = path.join(buildDir, 'icon.png')
|
||||
const outIco = path.join(buildDir, 'icon.ico')
|
||||
|
||||
if (!fs.existsSync(srcSvg)) {
|
||||
console.error(`[gen:icons] missing ${srcSvg}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
fs.mkdirSync(buildDir, { recursive: true })
|
||||
|
||||
const svgBuf = fs.readFileSync(srcSvg)
|
||||
const svg = svgBuf.toString('utf8')
|
||||
|
||||
function renderSvgToPngBuffer(svgInputUtf8, size) {
|
||||
const resvg = new Resvg(svgInputUtf8, {
|
||||
fitTo: { mode: 'width', value: size },
|
||||
background: 'rgba(0,0,0,0)',
|
||||
})
|
||||
const img = resvg.render()
|
||||
return img.asPng()
|
||||
}
|
||||
|
||||
// 生成一张 256x256 的 PNG(也可供托盘/文档等使用)
|
||||
fs.writeFileSync(outPng, renderSvgToPngBuffer(svg, 256))
|
||||
|
||||
// Windows .ico:包含多尺寸位图更稳(任务栏/快捷方式/高 DPI)
|
||||
const sizes = [16, 24, 32, 48, 64, 128, 256]
|
||||
const pngBuffers = sizes.map((s) => renderSvgToPngBuffer(svg, s))
|
||||
|
||||
const ico = await pngToIco(pngBuffers)
|
||||
fs.writeFileSync(outIco, ico)
|
||||
|
||||
console.log(`[gen:icons] wrote ${path.relative(root, outIco)} and ${path.relative(root, outPng)}`)
|
||||
|
||||
@@ -51,6 +51,15 @@ let pendingNav: string | null = null
|
||||
let tray: Tray | null = null
|
||||
let isQuitting = false
|
||||
|
||||
function resolveAppIconPath(): string | null {
|
||||
// 构建后 app.asar 内也会包含 build/icon.ico(见 package.json build.files)
|
||||
const devCandidate = path.resolve(__dirname, '../../build/icon.ico')
|
||||
const packagedCandidate = path.join(app.getAppPath(), 'build', 'icon.ico')
|
||||
|
||||
const pick = (p: string): string | null => (p && fs.existsSync(p) ? p : null)
|
||||
return pick(packagedCandidate) ?? pick(devCandidate)
|
||||
}
|
||||
|
||||
function showMainWindow(): void {
|
||||
if (!mainWindow || mainWindow.isDestroyed()) return
|
||||
if (!mainWindow.isVisible()) mainWindow.show()
|
||||
@@ -60,8 +69,8 @@ function showMainWindow(): void {
|
||||
|
||||
function ensureTray(): void {
|
||||
if (tray) return
|
||||
// 项目内未找到托盘图标资源:先用空图标兜底(Windows 会显示默认占位/可点击区域)
|
||||
const img = nativeImage.createEmpty()
|
||||
const p = resolveAppIconPath()
|
||||
const img = p ? nativeImage.createFromPath(p) : nativeImage.createEmpty()
|
||||
tray = new Tray(img)
|
||||
tray.setToolTip('无人直播助手')
|
||||
tray.on('click', () => showMainWindow())
|
||||
@@ -389,6 +398,7 @@ function resolvePreload(): string {
|
||||
}
|
||||
|
||||
async function createWindow(): Promise<void> {
|
||||
const iconPath = resolveAppIconPath() ?? undefined
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 1020,
|
||||
height: 720,
|
||||
@@ -398,6 +408,7 @@ async function createWindow(): Promise<void> {
|
||||
backgroundColor: '#14161c',
|
||||
title: '无人直播助手',
|
||||
autoHideMenuBar: true,
|
||||
...(iconPath ? { icon: iconPath } : {}),
|
||||
webPreferences: {
|
||||
preload: resolvePreload(),
|
||||
contextIsolation: true,
|
||||
|
||||
Reference in New Issue
Block a user