diff --git a/desktop/build/icon.icns b/desktop/build/icon.icns new file mode 100644 index 0000000..729c756 Binary files /dev/null and b/desktop/build/icon.icns differ diff --git a/desktop/build/icon.ico b/desktop/build/icon.ico new file mode 100644 index 0000000..02685a8 Binary files /dev/null and b/desktop/build/icon.ico differ diff --git a/desktop/build/icon.png b/desktop/build/icon.png new file mode 100644 index 0000000..d4c9ed3 Binary files /dev/null and b/desktop/build/icon.png differ diff --git a/desktop/build/icon.svg b/desktop/build/icon.svg new file mode 100644 index 0000000..1fe83cf --- /dev/null +++ b/desktop/build/icon.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VB + diff --git a/desktop/package.json b/desktop/package.json index ce18616..8191d0d 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -3,14 +3,22 @@ "version": "1.0.0", "type": "module", "description": "VoiceBridge Desktop — Real-time voice translation with OS-level virtual microphone", - "author": "AlleyBo55", - "main": "dist/main/main.js", + "homepage": "https://github.com/AlleyBo55/VoiceBridge", + "repository": { + "type": "git", + "url": "https://github.com/AlleyBo55/VoiceBridge.git" + }, + "author": { + "name": "AlleyBo55", + "email": "alleybo55@users.noreply.github.com" + }, + "main": "dist/main/main.cjs", "scripts": { "dev": "node scripts/dev.mjs", "build": "npm run typecheck && node scripts/build.mjs && vite build", "build:main": "node scripts/build.mjs", "build:renderer": "vite build", - "start": "electron dist/main/main.js", + "start": "electron dist/main/main.cjs", "test": "vitest run", "typecheck": "tsc -p tsconfig.main.json --noEmit && tsc -p tsconfig.renderer.json --noEmit", "dist:mac": "electron-builder --mac --publish never", @@ -28,6 +36,7 @@ "dist/**/*", "!node_modules/**/*" ], + "publish": null, "extraResources": [], "mac": { "category": "public.app-category.productivity", diff --git a/desktop/scripts/build.mjs b/desktop/scripts/build.mjs index b92a3dd..24e3fc0 100644 --- a/desktop/scripts/build.mjs +++ b/desktop/scripts/build.mjs @@ -25,12 +25,12 @@ async function buildMain() { await build({ ...commonOptions, entryPoints: [resolve(root, 'src/main/main.ts')], - outfile: resolve(root, 'dist/main/main.js'), + outfile: resolve(root, 'dist/main/main.cjs'), define: { 'process.env.NODE_ENV': '"production"', }, }); - console.log('[build] Main process → dist/main/main.js'); + console.log('[build] Main process → dist/main/main.cjs'); } async function buildPreload() { diff --git a/desktop/scripts/generate-icons.mjs b/desktop/scripts/generate-icons.mjs new file mode 100644 index 0000000..154da7d --- /dev/null +++ b/desktop/scripts/generate-icons.mjs @@ -0,0 +1,72 @@ +#!/usr/bin/env node +/** + * Generate app icons from icon.svg for all platforms. + * Requires: macOS with sips, iconutil, and ImageMagick (convert). + */ + +import { execSync } from 'child_process'; +import { mkdirSync, rmSync, existsSync } from 'fs'; +import { resolve, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const buildDir = resolve(__dirname, '..', 'build'); +const svgPath = resolve(buildDir, 'icon.svg'); +const iconsetDir = resolve(buildDir, 'icon.iconset'); + +if (!existsSync(svgPath)) { + console.error('icon.svg not found in build/'); + process.exit(1); +} + +// Sizes needed for macOS .iconset +const sizes = [16, 32, 64, 128, 256, 512, 1024]; + +console.log('[icons] Generating PNGs from SVG...'); + +// Create iconset directory +if (existsSync(iconsetDir)) rmSync(iconsetDir, { recursive: true }); +mkdirSync(iconsetDir, { recursive: true }); + +// Generate base 1024px PNG first +const basePng = resolve(buildDir, 'icon-1024.png'); +execSync(`convert -background none -density 300 "${svgPath}" -resize 1024x1024 "${basePng}"`, { stdio: 'inherit' }); + +// Generate iconset PNGs for macOS +for (const size of sizes) { + const name1x = `icon_${size}x${size}.png`; + const name2x = `icon_${size / 2}x${size / 2}@2x.png`; + + execSync(`sips -z ${size} ${size} "${basePng}" --out "${resolve(iconsetDir, name1x)}" 2>/dev/null`, { stdio: 'inherit' }); + + if (size >= 32) { + execSync(`sips -z ${size} ${size} "${basePng}" --out "${resolve(iconsetDir, name2x)}" 2>/dev/null`, { stdio: 'inherit' }); + } +} + +// Generate .icns for macOS +console.log('[icons] Building icon.icns...'); +execSync(`iconutil -c icns "${iconsetDir}" -o "${resolve(buildDir, 'icon.icns')}"`, { stdio: 'inherit' }); + +// Generate 256px PNG for Linux and electron-builder fallback +console.log('[icons] Building icon.png (256px)...'); +execSync(`sips -z 256 256 "${basePng}" --out "${resolve(buildDir, 'icon.png')}" 2>/dev/null`, { stdio: 'inherit' }); + +// Generate .ico for Windows (multi-size) +console.log('[icons] Building icon.ico...'); +const icoSizes = [16, 32, 48, 64, 128, 256]; +const icoInputs = icoSizes.map(s => { + const tmp = resolve(buildDir, `icon-${s}.png`); + execSync(`sips -z ${s} ${s} "${basePng}" --out "${tmp}" 2>/dev/null`, { stdio: 'inherit' }); + return `"${tmp}"`; +}); +execSync(`convert ${icoInputs.join(' ')} "${resolve(buildDir, 'icon.ico')}"`, { stdio: 'inherit' }); + +// Cleanup temp files +rmSync(iconsetDir, { recursive: true }); +for (const s of [...sizes, ...icoSizes, 1024]) { + const tmp = resolve(buildDir, `icon-${s}.png`); + if (existsSync(tmp)) rmSync(tmp); +} + +console.log('[icons] Done. Generated: icon.icns, icon.ico, icon.png'); diff --git a/desktop/src/main/main.ts b/desktop/src/main/main.ts index 3df87e4..61016c4 100644 --- a/desktop/src/main/main.ts +++ b/desktop/src/main/main.ts @@ -45,14 +45,17 @@ function createMainWindow(): BrowserWindow { const isDev = process.env['NODE_ENV'] === 'development'; const win = new BrowserWindow({ - width: isDev ? 900 : 360, - height: isDev ? 750 : 480, + width: isDev ? 900 : 420, + height: isDev ? 750 : 680, + minWidth: 380, + minHeight: 520, show: false, - frame: isDev, - resizable: isDev, - skipTaskbar: !isDev, + frame: true, + resizable: true, + skipTaskbar: false, transparent: false, backgroundColor: '#000000', + titleBarStyle: isDev ? 'default' : 'hiddenInset', webPreferences: { contextIsolation: true, nodeIntegration: false, @@ -67,7 +70,7 @@ function createMainWindow(): BrowserWindow { // Open DevTools in dev mode win.webContents.openDevTools({ mode: 'detach' }); } else { - void win.loadFile(join(__dirname, '..', 'renderer', 'src', 'renderer', 'index.html')); + void win.loadFile(join(__dirname, '..', 'renderer', 'index.html')); } // Hide on blur (click outside) — disabled in dev for DevTools usability diff --git a/desktop/vite.config.ts b/desktop/vite.config.ts index 9f6cd4f..d75616f 100644 --- a/desktop/vite.config.ts +++ b/desktop/vite.config.ts @@ -7,6 +7,7 @@ export default defineConfig(({ mode }) => { return { root: resolve(__dirname, 'src/renderer'), + base: './', plugins: [preact()], build: { outDir: resolve(__dirname, 'dist/renderer'),