From ef73b13262ccc4c995378bce7571fd994d7273c4 Mon Sep 17 00:00:00 2001 From: OpenClaw Bot Date: Sat, 14 Mar 2026 17:17:47 +0000 Subject: [PATCH] Expand electron-tests into full modular app source with tray+window and production-ready structure --- .gitignore | 4 ++ README.md | 28 +++++++++++++ index.html | 20 ---------- main.js | 70 -------------------------------- package.json | 5 +-- src/main/index.js | 86 ++++++++++++++++++++++++++++++++++++++++ src/preload/index.js | 6 +++ src/renderer/index.html | 28 +++++++++++++ src/renderer/renderer.js | 6 +++ src/renderer/styles.css | 22 ++++++++++ 10 files changed, 182 insertions(+), 93 deletions(-) create mode 100644 .gitignore create mode 100644 README.md delete mode 100644 index.html delete mode 100644 main.js create mode 100644 src/main/index.js create mode 100644 src/preload/index.js create mode 100644 src/renderer/index.html create mode 100644 src/renderer/renderer.js create mode 100644 src/renderer/styles.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dd6e803 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +dist/ +*.log +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..b1cfa44 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# electron-tests + +Electron tray/window test app for CI/CD validation. + +## Features + +- Tray icon + context menu +- Main desktop window +- Simple status UI showing runtime versions + +## Run locally + +```bash +npm ci +npm start +``` + +## Build AppImage + +```bash +npm run build:linux:amd64 +npm run build:linux:arm64 +``` + +Artifacts are produced via CI workflows: + +- `electron-linux-amd64` +- `electron-linux-arm64` diff --git a/index.html b/index.html deleted file mode 100644 index 154b9de..0000000 --- a/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - Electron Tray Demo - - - -

Electron Tray Demo

-
-

This is a test desktop window for the Electron tray application.

-

Close window to hide to tray, use tray menu to show it again.

-
- - diff --git a/main.js b/main.js deleted file mode 100644 index 625a499..0000000 --- a/main.js +++ /dev/null @@ -1,70 +0,0 @@ -const { app, BrowserWindow, Menu, Tray } = require('electron'); -const path = require('path'); - -let tray = null; -let mainWindow = null; - -function createWindow() { - mainWindow = new BrowserWindow({ - width: 700, - height: 420, - title: 'Electron Tray Demo', - webPreferences: { - contextIsolation: true, - nodeIntegration: false, - }, - }); - mainWindow.loadFile(path.join(__dirname, 'index.html')); - mainWindow.on('close', (event) => { - if (!app.isQuiting) { - event.preventDefault(); - mainWindow.hide(); - } - }); -} - -function createTray() { - const iconPath = path.join(__dirname, 'assets', 'trayTemplate.png'); - tray = new Tray(iconPath); - tray.setToolTip('Electron Tray Demo'); - - const contextMenu = Menu.buildFromTemplate([ - { - label: 'Show Window', - click: () => { - if (mainWindow) { - mainWindow.show(); - mainWindow.focus(); - } - }, - }, - { - label: 'Quit', - click: () => { - app.isQuiting = true; - app.quit(); - }, - }, - ]); - - tray.setContextMenu(contextMenu); - tray.on('double-click', () => { - if (mainWindow) { - mainWindow.show(); - mainWindow.focus(); - } - }); -} - -app.whenReady().then(() => { - createWindow(); - createTray(); - - app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) createWindow(); - }); -}); - -app.on('window-all-closed', () => { - // keep tray app alive on Linux/macOS -}); diff --git a/package.json b/package.json index 85ae48a..8cd6bb3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "electron-tray-demo", "version": "1.0.0", "description": "Electron tray demo app", - "main": "main.js", + "main": "src/main/index.js", "author": "marksaitis", "license": "MIT", "scripts": { @@ -18,8 +18,7 @@ "appId": "io.swissline.electrontraydemo", "productName": "electron_tray_demo", "files": [ - "main.js", - "index.html", + "src/**/*", "assets/**/*", "package.json" ], diff --git a/src/main/index.js b/src/main/index.js new file mode 100644 index 0000000..f7e7a9d --- /dev/null +++ b/src/main/index.js @@ -0,0 +1,86 @@ +const { app, BrowserWindow, Menu, Tray, nativeImage } = require('electron'); +const path = require('path'); + +let tray = null; +let mainWindow = null; + +function createMainWindow() { + mainWindow = new BrowserWindow({ + width: 900, + height: 560, + minWidth: 720, + minHeight: 420, + title: 'Electron Test App', + backgroundColor: '#0f172a', + webPreferences: { + preload: path.join(__dirname, '..', 'preload', 'index.js'), + contextIsolation: true, + nodeIntegration: false, + sandbox: true, + }, + }); + + mainWindow.loadFile(path.join(__dirname, '..', 'renderer', 'index.html')); + + mainWindow.on('close', (event) => { + if (!app.isQuiting) { + event.preventDefault(); + mainWindow.hide(); + } + }); +} + +function buildTrayMenu() { + return Menu.buildFromTemplate([ + { + label: 'Show window', + click: () => { + if (mainWindow) { + mainWindow.show(); + mainWindow.focus(); + } + }, + }, + { + type: 'separator', + }, + { + label: 'Quit', + click: () => { + app.isQuiting = true; + app.quit(); + }, + }, + ]); +} + +function createTray() { + const iconPath = path.join(__dirname, '..', '..', 'assets', 'trayTemplate.png'); + const icon = nativeImage.createFromPath(iconPath); + tray = new Tray(icon); + tray.setToolTip('Electron Test'); + tray.setContextMenu(buildTrayMenu()); + tray.on('double-click', () => { + if (mainWindow) { + mainWindow.show(); + mainWindow.focus(); + } + }); +} + +app.whenReady().then(() => { + createMainWindow(); + createTray(); + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createMainWindow(); + } else if (mainWindow) { + mainWindow.show(); + } + }); +}); + +app.on('window-all-closed', () => { + // keep tray app alive by default +}); diff --git a/src/preload/index.js b/src/preload/index.js new file mode 100644 index 0000000..c1c3cbb --- /dev/null +++ b/src/preload/index.js @@ -0,0 +1,6 @@ +const { contextBridge } = require('electron'); + +contextBridge.exposeInMainWorld('electronTest', { + appName: 'Electron Test', + runtime: process.versions, +}); diff --git a/src/renderer/index.html b/src/renderer/index.html new file mode 100644 index 0000000..4ea3a15 --- /dev/null +++ b/src/renderer/index.html @@ -0,0 +1,28 @@ + + + + + + Electron Test + + + +
+

Electron Test App

+

Tray + Window demo used for CI/CD validation.

+ +
+

Status

+
    +
  • Window launched ✅
  • +
  • Tray icon active ✅
  • +
  • Platform: ...
  • +
  • Electron: ...
  • +
  • Node: ...
  • +
  • Chrome: ...
  • +
+
+
+ + + diff --git a/src/renderer/renderer.js b/src/renderer/renderer.js new file mode 100644 index 0000000..accf9a9 --- /dev/null +++ b/src/renderer/renderer.js @@ -0,0 +1,6 @@ +const versions = (window.electronTest && window.electronTest.runtime) || {}; + +document.getElementById('platform').textContent = navigator.userAgentData?.platform || navigator.platform || 'unknown'; +document.getElementById('electron').textContent = versions.electron || 'unknown'; +document.getElementById('node').textContent = versions.node || 'unknown'; +document.getElementById('chrome').textContent = versions.chrome || 'unknown'; diff --git a/src/renderer/styles.css b/src/renderer/styles.css new file mode 100644 index 0000000..dfd3203 --- /dev/null +++ b/src/renderer/styles.css @@ -0,0 +1,22 @@ +* { box-sizing: border-box; } +body { + margin: 0; + font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; + color: #e2e8f0; + background: radial-gradient(circle at top left, #1e293b, #0f172a 55%); +} +.page { + max-width: 980px; + margin: 0 auto; + padding: 24px; +} +h1 { margin: 0 0 8px; font-size: 32px; } +.muted { opacity: .8; margin: 0 0 16px; } +.card { + border: 1px solid #334155; + border-radius: 16px; + padding: 16px; + background: rgba(30, 41, 59, 0.5); +} +ul { margin: 0; padding-left: 20px; } +li { margin: 8px 0; }