feat(v5): eigenes Fenster ohne Windows-Rahmen + Layout skaliert mit
Ampel / ampel (push) Successful in 1m34s

Zwei Befunde des Commanders (01.09.2026):

1. "Momentan ist alles nach links gerueckt, nichts skaliert mit der
   fenstergroesse und es ist alles gequetscht."

   Ursache gefunden: <main> hatte WEDER Zentrierung NOCH Maximalbreite,
   die Karten darin aber einen harten Deckel von max-w-2xl (672 px). In
   einem 1280er Fenster klebte damit alles am linken Rand und rechts
   stand nichts. Behoben:
   * <main> und Kopfzeile teilen sich mx-auto max-w-[1600px] mit
     mitwachsendem Innenabstand — der Inhalt ist mittig und nutzt die
     Breite.
   * Der 672-px-Deckel der Einstellungs-Spalte ist weg. Drei
     Encoder-Felder stehen jetzt nebeneinander statt untereinander.
   * Die Sektionswahl der Einstellungen wird im schmalen Fenster zur
     Zeile ueber den Karten (lg:flex-row), statt eine 176-px-Spalte vom
     ohnehin knappen Platz abzuziehen.
   * Info-Kacheln der Laufwerks-Karte: zwei Spalten schmal, vier breit.
   * Startgroesse 1000x700 -> 1280x820, Mindestmass 720x480 -> 860x560.

2. "waere sogar richtig cool wenn du den rahmen wegbekommst"

   frame:false, und die Kopfzeile IST jetzt die Titelleiste:
   Minimieren / Maximieren / Schliessen sitzen oben rechts in
   Windows-Massen (46x32), gezogen wird an der Kopfzeile, Doppelklick
   maximiert. Groesse aendern bleibt moeglich — Electron setzt fuer
   rahmenlose Fenster unter Windows weiter WS_THICKFRAME (thickFrame,
   Standard true), die Kanten ziehen also wie gewohnt.

   Schliessen nimmt GENAU den Weg des alten Fensterkreuzes
   (fenster.close() -> der bestehende close-Horcher versteckt nur):
   Rippy lebt im Tray weiter, ein laufender Rip merkt davon nichts
   (Paragraph 4.1 Punkt 3).

   Die Ziehflaeche ist .ziehbar in stil.css; alles Bedienbare darin
   traegt .nicht-ziehbar, sonst verschluckt der Griff den Klick.
   fensterMaximiert im HauptStatus entscheidet ueber das Knopf-Symbol
   und wird auch bei Doppelklick/Tastenkuerzel nachgefuehrt (maximize-
   und unmaximize-Horcher).

Nachgemessen mit dem Smoke-Beweis: beweise/ui-513-uebersicht.png (kein
Rahmen, eigene Knoepfe, Inhalt ueber die volle Breite) und
beweise/ui-513-einstellungen.png (drei Encoder nebeneinander).

230 Tests gruen, Typpruefung sauber. Version 5.1.3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-09-01 18:07:45 +02:00
co-authored by Claude Opus 5
parent 0c38754c09
commit 827910fd63
12 changed files with 182 additions and 32 deletions
+13 -4
View File
@@ -7,12 +7,21 @@ import { join } from 'node:path'
export function fensterErstellen(): BrowserWindow {
const fenster = new BrowserWindow({
width: 1000,
height: 700,
minWidth: 720,
minHeight: 480,
width: 1280,
height: 820,
minWidth: 860,
minHeight: 560,
show: true,
autoHideMenuBar: true,
// Eigene Titelleiste (Commander-Wunsch 01.09.2026): Der Windows-Rahmen
// ist weg, Minimieren/Maximieren/Schließen sitzen im UI und gezogen
// wird an der Kopfzeile (.ziehbar in fenster/stil.css).
//
// Wichtig: GRÖSSE ÄNDERN bleibt möglich. Electron setzt für rahmenlose
// Fenster unter Windows weiterhin WS_THICKFRAME (Option `thickFrame`,
// Standard true) — die Kanten lassen sich also weiter ziehen, und
// Doppelklick auf die Ziehfläche maximiert wie gewohnt.
frame: false,
// Dunkler Grund SOFORT — sonst blitzt beim Start ein weißes Rechteck,
// bevor React lädt. Das warme Bühnen-Schwarz des Kino-Mixes
// (oklch(0.13 0.012 60), siehe fenster/stil.css).
+28
View File
@@ -176,6 +176,9 @@ function start(): void {
kern: kernVerwaltung.zustand(),
autostart: autostartAktiv(),
update: updateStand(),
// Für die eigene Titelleiste: Das Knopf-Symbol muss wissen, ob das
// Fenster gerade maximiert ist.
fensterMaximiert: fenster !== null && !fenster.isDestroyed() && fenster.isMaximized(),
}
fenster.webContents.send('haupt-status', status)
}
@@ -189,6 +192,11 @@ function start(): void {
statusSenden()
smokePruefen()
})
// Die eigene Titelleiste zeichnet ihr Maximieren-Symbol nach diesem
// Zustand — auch wenn per Doppelklick oder Windows-Tastenkürzel
// maximiert wird, nicht nur über unseren Knopf.
fenster.on('maximize', () => statusSenden())
fenster.on('unmaximize', () => statusSenden())
// § 4.1 Punkt 3: Fenster zu, Rip läuft weiter — Rippy lebt im Tray.
fenster.on('close', (ereignis) => {
if (beendenGewollt) return
@@ -223,6 +231,26 @@ function start(): void {
}
})
// Eigene Titelleiste (§ 4.2): Das Fenster hat keinen Windows-Rahmen
// mehr, die drei Knöpfe sitzen im UI und melden sich hier.
ipcMain.handle('fenster-steuern', (_ereignis, was: unknown) => {
if (fenster === null || fenster.isDestroyed()) return false
if (was === 'minimieren') {
fenster.minimize()
} else if (was === 'maximieren') {
if (fenster.isMaximized()) fenster.unmaximize()
else fenster.maximize()
} else if (was === 'schliessen') {
// Genau der Weg des alten Fensterkreuzes: Der close-Horcher weiter
// unten versteckt nur — Rippy lebt im Tray weiter (§ 4.1 Punkt 3),
// ein laufender Rip darf davon nichts merken.
fenster.close()
} else {
return false
}
return fenster.isDestroyed() ? false : fenster.isMaximized()
})
// Der Knopf „Jetzt prüfen" (§ 6.8). Der Stand meldet sich über
// beiAenderung von selbst ans Fenster — hier gibt es nichts zurück.
ipcMain.handle('update-pruefen', () => {