Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 49 additions & 11 deletions electron-app/renderer/mode-selector/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@
<style>
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@500&display=swap');

* {
box-sizing: border-box;
}

html,
body {
min-height: 100vh;
height: 100%;
margin: 0;
overflow: hidden;
background: transparent;
}

body {
Expand All @@ -21,7 +26,7 @@
display: flex;
align-items: center;
justify-content: center;
background: #111;
box-sizing: border-box;
color: #fff;
padding: 16px;
}
Expand All @@ -31,13 +36,39 @@
background: #20274c;
padding: clamp(22px, 3.5vw, 32px);
border-radius: 24px;
width: min(660px, 100%);
max-width: 660px;
max-height: calc(100vh - 48px);
width: min(726px, 100%);
max-height: calc(100vh - 32px);
text-align: center;
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.25);
border: 1px solid rgba(237, 238, 240, 0.08);
overflow: hidden;
overflow-x: hidden;
overflow-y: auto;
}

.close-button {
position: absolute;
top: 12px;
right: 12px;
z-index: 3;
display: grid;
place-items: center;
width: 36px;
height: 36px;
min-height: 0;
padding: 0;
border-radius: 50%;
background: transparent;
color: #edeef0;
}

.close-button:hover {
background: rgba(237, 238, 240, 0.15);
transform: none;
}

button:focus-visible {
outline: 2px solid #fff;
outline-offset: 3px;
}

.top-logo {
Expand All @@ -50,7 +81,7 @@
.logo-background {
position: absolute;
left: 50%;
bottom: -14px;
bottom: 0;
width: clamp(260px, 60vw, 380px);
max-width: 90%;
transform: translateX(-50%);
Expand Down Expand Up @@ -217,7 +248,7 @@
}

.logo-background {
bottom: -12px;
bottom: 0;
}

.button-grid {
Expand All @@ -233,6 +264,11 @@

<body>
<div class="card">
<button class="close-button" id="close-selector" type="button" aria-label="Close Control Station" title="Close Control Station">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path d="m6 6 12 12M18 6 6 18" />
</svg>
</button>
<img src="src/Subsystem.png" alt="Departamento" class="logo-background" />
<div class="top-logo">
<img src="src/logo.svg" alt="Logo Hyperloop UPV" class="logo-main" />
Expand All @@ -254,11 +290,13 @@ <h1>Control Station</h1>
</div>
</div>
<script>
document.getElementById('close-selector').addEventListener('click', () => window.close());

const sendMode = (mode) => {
if (window.electronAPI && window.electronAPI.setInitialMode) {
window.electronAPI.setInitialMode(mode).catch(() => { }).finally(() => window.close());
window.electronAPI.setInitialMode(mode).catch(() => { });
} else {
try { window.ipcRenderer && window.ipcRenderer.send('set-initial-mode', mode); window.close(); } catch (e) { }
try { window.ipcRenderer && window.ipcRenderer.send('mode-selected', mode); } catch (e) { }
}
};

Expand Down Expand Up @@ -330,4 +368,4 @@ <h1>Control Station</h1>
</script>
</body>

</html>
</html>
53 changes: 41 additions & 12 deletions electron-app/src/app/modeSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @description Mode selector window and logic for initial app mode selection.
*/

import { BrowserWindow, ipcMain } from "electron";
import { app, BrowserWindow, ipcMain, screen } from "electron";
import fs from "fs";
import path from "path";
import { startBackend } from "../processes/backend.js";
Expand Down Expand Up @@ -32,15 +32,26 @@ const VALID_MODES = {
async function showModeSelector(screenWidth, screenHeight) {
return new Promise(async (resolve, reject) => {
let mainWindow = null;
let modeSelected = false;
const { x, y, width, height } = screen.getPrimaryDisplay().bounds;

const selectorWindow = new BrowserWindow({
width: 920,
height: 680,
useContentSize: true,
resizable: true,
modal: true,
parent: mainWindow,
show: true,
// Cover the desktop without native fullscreen, which can make transparent
// windows opaque or move them to a separate desktop space. A 1px inset also
// prevents the compositor from treating a screen-sized window as fullscreen.
x: x + 1,
y: y + 1,
width: width - 2,
height: height - 2,
frame: false,
transparent: true,
backgroundColor: "#00000000",
fullscreen: false,
fullscreenable: false,
maximizable: false,
resizable: false,
hasShadow: false,
show: false,
webPreferences: {
preload: path.join(getAppPath(), "preload.js"),
contextIsolation: true,
Expand All @@ -49,28 +60,46 @@ async function showModeSelector(screenWidth, screenHeight) {
title: "Select Mode",
});

selectorWindow.on("closed", () => {
ipcMain.removeListener("mode-selected", onModeSelected);
// Closing the selector cancels startup, including return-to-selector flows
// where the previous application's windows are still hidden.
if (!modeSelected) app.quit();
});

const selectorPath = path.join(getAppPath(), "renderer", "mode-selector", "index.html");

if (!fs.existsSync(selectorPath)) {
logger.electron.warning("Mode selector UI not found, using default testing-view");
modeSelected = true;
selectorWindow.close();
resolve({ mode: "default", view: VALID_MODES.default, mainWindow: null });
return;
}

logger.electron.info(`Mode selector found: ${selectorPath}`);

ipcMain.on("mode-selected", onModeSelected);

try {
await selectorWindow.loadFile(selectorPath);
selectorWindow.show();
selectorWindow.focus();
if (!selectorWindow.isDestroyed()) {
selectorWindow.show();
selectorWindow.focus();
}
} catch (err) {
logger.electron.error("Failed to load selector UI:", err);
modeSelected = true;
selectorWindow.close();
resolve({ mode: "default", view: VALID_MODES.default, mainWindow: null });
return;
}

// Listen for mode selection from renderer
ipcMain.once("mode-selected", async (_event, mode) => {
async function onModeSelected(event, mode) {
if (event.sender !== selectorWindow.webContents || modeSelected) return;
modeSelected = true;
ipcMain.removeListener("mode-selected", onModeSelected);
try {
const view = VALID_MODES[mode] || VALID_MODES.default;

Expand Down Expand Up @@ -103,7 +132,7 @@ async function showModeSelector(screenWidth, screenHeight) {
selectorWindow.close();
} catch (e) {}
}
});
}
});
}

Expand Down
Loading