From 3a500a682fcf60248cb5230efbc527a751729080 Mon Sep 17 00:00:00 2001 From: Pandipipas <62224708+Pandipipas@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:47:30 +0100 Subject: [PATCH] Add app customization options for title, icons, and Windows metadata (#16) --- README.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main/main.ts | 19 ++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5abfce8..db933d5 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,56 @@ scoreko-electron-dev/ - `NODECG_BUNDLE_NAME` (default: `scoreko-dev`) - `SCOREKO_DASHBOARD_ROUTE` (default: `dashboard/example/main.html?standalone=true`) - `SCOREKO_LOADING_ROUTE` (default: `dashboard/loading/main.html?standalone=true`) +- `SCOREKO_APP_TITLE` (default: `Scoreko`) + +## Personalización (Windows / Electron) + +### 1) Título de la app + +- **Durante ejecución**: cambia `SCOREKO_APP_TITLE` para sobreescribir el título de ventana. +- **En instalador y ejecutable**: cambia `build.productName` en `package.json`. + +### 2) Ícono en barra de tareas y esquina superior de la ventana + +Coloca tu icono en uno de estos paths (prioridad de arriba hacia abajo): + +- `static/icons/icon.ico` +- `static/icons/icon.png` +- `static/icon.ico` +- `static/icon.png` + +Electron tomará automáticamente el primero que exista. + +### 3) Ícono del `.exe` (instalador/app empaquetada) + +En `package.json` dentro de `build.win` agrega: + +```json +"icon": "static/icons/icon.ico" +``` + +> Recomendado: `.ico` multi-resolución (16/24/32/48/64/128/256). + +### 4) Texto y autor que muestra el popup del Firewall de Windows + +Ese diálogo toma datos del ejecutable final: + +- **Nombre de app**: suele venir de `productName` y metadatos del ejecutable. +- **Publisher/Autor**: viene de la **firma de código** (certificado). Sin firma, suele salir `Unknown publisher`. + +Para personalizarlo correctamente en builds de distribución: + +1. Ajusta en `package.json`: + - `description` + - `author` + - `build.productName` +2. Firma el `.exe` con un certificado de tu empresa/persona (`CSC_LINK`/`CSC_KEY_PASSWORD` en `electron-builder`). + +> Nota: en desarrollo (`npm run start` / `npm run dev`) puedes ver `GitHub, Inc.` porque estás ejecutando el binario de Electron oficial. + +### 5) Otros campos personalizables que te conviene revisar + +- `build.appId` (identificador único de la app). +- `build.win.executableName` (nombre del ejecutable sin extensión). +- `build.nsis` (nombre del instalador, iconos de instalador/desinstalador, etc.). +- `build.artifactName` (patrón de nombre del archivo de salida). diff --git a/src/main/main.ts b/src/main/main.ts index 9b6c9cc..990a255 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -3,7 +3,7 @@ import { ChildProcess, spawn } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; -const APP_TITLE = "Scoreko"; +const APP_TITLE = process.env.SCOREKO_APP_TITLE ?? "Scoreko"; const DEFAULT_NODECG_PORT = process.env.NODECG_PORT ?? "9090"; const DEFAULT_BUNDLE_NAME = process.env.NODECG_BUNDLE_NAME ?? "scoreko-dev"; const DEFAULT_DASHBOARD_ROUTE = process.env.SCOREKO_DASHBOARD_ROUTE ?? "dashboard/example/main.html?standalone=true"; @@ -28,9 +28,12 @@ let stopNodeCGPromise: Promise | null = null; let isQuitting = false; function createMainWindow(): BrowserWindow { + const iconPath = resolveAppIconPath(); + const win = new BrowserWindow({ show: false, title: APP_TITLE, + ...(iconPath ? { icon: iconPath } : {}), width: 1280, height: 800, minWidth: 800, @@ -66,10 +69,13 @@ function createMainWindow(): BrowserWindow { } function createLoadingWindow(): BrowserWindow { + const iconPath = resolveAppIconPath(); + const win = new BrowserWindow({ show: false, frame: false, title: APP_TITLE, + ...(iconPath ? { icon: iconPath } : {}), width: 300, height: 300, resizable: false, @@ -90,6 +96,17 @@ function createLoadingWindow(): BrowserWindow { return win; } +function resolveAppIconPath(): string | undefined { + const candidates = [ + path.join(rootPath, "static", "icons", "icon.ico"), + path.join(rootPath, "static", "icons", "icon.png"), + path.join(rootPath, "static", "icon.ico"), + path.join(rootPath, "static", "icon.png"), + ]; + + return candidates.find((candidate) => fs.existsSync(candidate)); +} + function validateNodeCGInstall(): void { const indexPath = path.join(nodecgPath, "index.js"); const nodecgBootstrapPath = path.join(nodecgPath, "node_modules", "nodecg", "dist", "server", "bootstrap.js");