From 30891c1bcedcfdb94e25d09792a20120118ed5a1 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 13 Sep 2026 14:24:23 +0200 Subject: [PATCH] WebUI: Hellmodus, Supervisor-Verlauf leeren, API-Status beschriftet Umsetzung von #566. Hell-/Dunkelmodus Das WebUI hatte nur eine dunkle Palette. Jetzt gibt es "System", "Hell" und "Dunkel" als Umschalter in der Kopfleiste. Die Wahl gilt je Browser; ohne gespeicherte Wahl folgt das WebUI dem Betriebssystem. data-theme auf ueberstimmt prefers-color-scheme in beide Richtungen. Ein kleines Skript im setzt die Wahl vor dem ersten Zeichnen, sonst blitzte beim Laden kurz das falsche Schema auf; die Login-Seite macht es genauso. Kontrast der hellen Palette auf Weiss: - Text 8:1 - gedaempfter Text 6,3:1 - Akzent, Gewinn, Verlust und Warnung je mindestens 4,5:1 Fuenf feste Farben haetten im Hellmodus gebrochen und sind jetzt Tokens: - #11111b als Schrift auf Akzentfarbe (Primaerknopf, Profil-Hover, aktive Waehrung): im Hellmodus dunkel auf dunklem Blau. - rgba(255,255,255,0.02 bis 0.08) fuer Zeilen-Hover und Trennlinien: auf Weiss unsichtbar. Das Terminal bleibt in beiden Modi dunkel und bringt seine Palette lokal mit. Es hatte einen festen dunklen Hintergrund, erbte aber var(--text), und das waere im Hellmodus dunkle Schrift auf Schwarz geworden. Die uebrigen festen Farben sind halbtransparente Toenungen und Schatten, die auf beiden Gruenden funktionieren. Supervisor "Verlauf leeren" wie im Desktop. Geleert wird nur die Unterhaltung im Browser, die Begruessung kommt zurueck, gespeicherte Berichte bleiben erhalten. Statusanzeige Der WSS-Punkt ist jetzt beschriftet, "WSS aktiv" oder "Polling", wie "API: ..." in der Statusleiste des Desktops. Dazu kommt "Module x/y". Reine Oberflaeche, keine Aenderung am Server. Die Pruefung erfolgt im Browser auf der VM. Co-Authored-By: Claude Opus 5 --- src/PolyTrader.Web/wwwroot/css/app.css | 78 ++++++++++++++++++++++++-- src/PolyTrader.Web/wwwroot/index.html | 16 +++++- src/PolyTrader.Web/wwwroot/js/app.js | 58 +++++++++++++++++++ src/PolyTrader.Web/wwwroot/login.html | 7 +++ 4 files changed, 152 insertions(+), 7 deletions(-) diff --git a/src/PolyTrader.Web/wwwroot/css/app.css b/src/PolyTrader.Web/wwwroot/css/app.css index 77b94f3..3588649 100644 --- a/src/PolyTrader.Web/wwwroot/css/app.css +++ b/src/PolyTrader.Web/wwwroot/css/app.css @@ -13,6 +13,59 @@ --negative: #f38ba8; --warning: #f9e2af; --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; + /* #566: Tokens fuer Stellen, die bisher feste Farben hatten und im Hellmodus brechen wuerden. */ + --on-accent: #11111b; + --row-hover: rgba(255, 255, 255, 0.02); + --hairline: rgba(255, 255, 255, 0.08); + --hairline-weak: rgba(255, 255, 255, 0.04); + color-scheme: dark; +} + +/* Hellmodus (#566). Die Palette folgt dem Betriebssystem, solange im Browser nichts gewaehlt ist; + data-theme="light"/"dark" auf ueberstimmt das in beide Richtungen. + Kontrast auf Weiss: Text 8:1, gedaempfter Text 6,3:1, Akzent, Gewinn, Verlust und Warnung je >= 4,5:1. */ +@media (prefers-color-scheme: light) { + :root:not([data-theme="dark"]) { + --bg: #eff1f5; + --surface: #ffffff; + --surface-alt: #e6e9ef; + --card: #ffffff; + --border: #ccd0da; + --divider: #bcc0cc; + --text: #4c4f69; + --muted: #5c5f77; + --accent: #1e66f5; + --accent-soft: rgba(30, 102, 245, 0.12); + --positive: #2e7d32; + --negative: #c11c3c; + --warning: #9a5b00; + --on-accent: #ffffff; + --row-hover: rgba(0, 0, 0, 0.035); + --hairline: rgba(0, 0, 0, 0.08); + --hairline-weak: rgba(0, 0, 0, 0.05); + color-scheme: light; + } +} + +:root[data-theme="light"] { + --bg: #eff1f5; + --surface: #ffffff; + --surface-alt: #e6e9ef; + --card: #ffffff; + --border: #ccd0da; + --divider: #bcc0cc; + --text: #4c4f69; + --muted: #5c5f77; + --accent: #1e66f5; + --accent-soft: rgba(30, 102, 245, 0.12); + --positive: #2e7d32; + --negative: #c11c3c; + --warning: #9a5b00; + --on-accent: #ffffff; + --row-hover: rgba(0, 0, 0, 0.035); + --hairline: rgba(0, 0, 0, 0.08); + --hairline-weak: rgba(0, 0, 0, 0.05); + color-scheme: light; } * { @@ -378,7 +431,7 @@ body { .btn-primary { background: var(--accent); - color: #11111b; + color: var(--on-accent); } .btn-primary:hover { opacity: 0.9; } @@ -431,11 +484,24 @@ tr:last-child td { } tr:hover td { - background: rgba(255, 255, 255, 0.02); + background: var(--row-hover); } /* Terminal / Log Viewer */ +/* Das Terminal bleibt in beiden Modi dunkel (#566): Die Level-Farben sind fuer dunklen Grund gewaehlt, + und ein helles Terminal liesse sich zwischen den farbigen Leveln schlechter lesen. Die Palette steht + deshalb hier lokal - sonst erbte es im Hellmodus dunkle Schrift auf seinem dunklen Hintergrund. */ .terminal-window { + --text: #cdd6f4; + --muted: #a6adc8; + --accent: #89b4fa; + --positive: #a6e3a1; + --negative: #f38ba8; + --warning: #f9e2af; + --border: #313244; + --surface-alt: #252538; + --card: #2a2b3f; + color-scheme: dark; background: #11111b; border: 1px solid var(--border); border-radius: 10px; @@ -631,7 +697,7 @@ tr:hover td { display: flex; gap: 6px; padding: 4px 0; - border-bottom: 1px solid rgba(255, 255, 255, 0.04); + border-bottom: 1px solid var(--hairline-weak); } .widget-alert-entry .time { @@ -701,7 +767,7 @@ tr:hover td { .btn-profile:hover { background: var(--accent); - color: #11111b; + color: var(--on-accent); } .badge-active { @@ -1053,7 +1119,7 @@ tr:hover td { gap: 12px; margin-bottom: 8px; padding-bottom: 4px; - border-bottom: 1px solid rgba(255, 255, 255, 0.08); + border-bottom: 1px solid var(--hairline); font-size: 11px; color: var(--muted); } @@ -1125,7 +1191,7 @@ tr:hover td { .currency-pill.active { background: var(--accent); - color: #11111b; + color: var(--on-accent); } .markdown-pre { diff --git a/src/PolyTrader.Web/wwwroot/index.html b/src/PolyTrader.Web/wwwroot/index.html index 5048152..efeaebb 100644 --- a/src/PolyTrader.Web/wwwroot/index.html +++ b/src/PolyTrader.Web/wwwroot/index.html @@ -5,6 +5,13 @@ PolyTrader Web +
@@ -66,7 +73,7 @@
- WSS + WSS
@@ -76,6 +83,11 @@ Watchdog
+ +
+ Module – +
+
@@ -792,6 +804,8 @@ + +
diff --git a/src/PolyTrader.Web/wwwroot/js/app.js b/src/PolyTrader.Web/wwwroot/js/app.js index 43e6b1f..dc8610a 100644 --- a/src/PolyTrader.Web/wwwroot/js/app.js +++ b/src/PolyTrader.Web/wwwroot/js/app.js @@ -6,6 +6,8 @@ let allLogs = []; // Init on DOM ready document.addEventListener('DOMContentLoaded', () => { + applyThemeChoice(currentThemeChoice()); + supChatWelcome = document.getElementById('supChatMessages')?.innerHTML ?? ''; loadUpdateStatus(false); // #565: Banner im Dashboard; der Server haelt das Ergebnis vor document.addEventListener('keydown', e => { if (e.key === 'Escape' && document.getElementById('modalStopTrading')?.style.display === 'flex') closeStopTradingModal(); @@ -53,6 +55,51 @@ function switchView(viewName) { } } +// ==================== Farbschema und Supervisor-Verlauf (#566) ==================== + +const THEME_KEY = 'polytrader-theme'; +const THEME_ORDER = ['system', 'light', 'dark']; +const THEME_LABELS = { system: '◐ System', light: '☀ Hell', dark: '☾ Dunkel' }; + +/** Die Wahl gilt je Browser. Ohne gespeicherte Wahl folgt das WebUI dem Betriebssystem. */ +function currentThemeChoice() { + try { + const t = localStorage.getItem(THEME_KEY); + return t === 'light' || t === 'dark' ? t : 'system'; + } catch (e) { + return 'system'; + } +} + +function applyThemeChoice(choice) { + if (choice === 'system') document.documentElement.removeAttribute('data-theme'); + else document.documentElement.setAttribute('data-theme', choice); + + try { + if (choice === 'system') localStorage.removeItem(THEME_KEY); + else localStorage.setItem(THEME_KEY, choice); + } catch (e) { /* ohne Speicher gilt die Wahl bis zum Neuladen */ } + + const btn = document.getElementById('btnTheme'); + if (btn) { + btn.textContent = THEME_LABELS[choice]; + btn.title = `Farbschema: ${THEME_LABELS[choice].slice(2)} – klicken zum Wechseln`; + } +} + +function cycleTheme() { + const next = THEME_ORDER[(THEME_ORDER.indexOf(currentThemeChoice()) + 1) % THEME_ORDER.length]; + applyThemeChoice(next); +} + +let supChatWelcome = ''; + +/** Leert nur die Unterhaltung im Browser. Gespeicherte Berichte (sup_reports) bleiben unberührt. */ +function clearSupChat() { + const area = document.getElementById('supChatMessages'); + if (area) area.innerHTML = supChatWelcome; +} + // ==================== Kopfleiste: Aufklappmenues (#541) ==================== /** @@ -159,6 +206,9 @@ async function refreshNavModules(modules) { const isActive = new Map(modules.map(m => [m.name.toLowerCase(), m.isActive])); + const lblModules = document.getElementById('lblModules'); + if (lblModules) lblModules.textContent = `Module ${modules.filter(m => m.isActive).length}/${modules.length}`; + document.querySelectorAll('.header-nav [data-module]').forEach(item => { const off = isActive.get(item.dataset.module.toLowerCase()) === false; item.disabled = off; @@ -204,6 +254,14 @@ async function refreshDashboard() { // Status indicators document.getElementById('dotAlchemy').className = data.alchemyHealthy ? 'dot online' : 'dot offline'; + // #566: beschriftet wie "API: WSS aktiv / Polling" in der Statusleiste des Desktops. + const lblAlchemy = document.getElementById('lblAlchemy'); + if (lblAlchemy) { + lblAlchemy.textContent = data.alchemyHealthy ? 'WSS aktiv' : 'Polling'; + lblAlchemy.parentElement.title = data.alchemyHealthy + ? 'Signale kommen live über den Alchemy-WebSocket' + : 'Kein WebSocket – Signale werden abgefragt (langsamer)'; + } document.getElementById('dotVpn').className = data.vpnConnected ? 'dot online' : 'dot offline'; document.getElementById('dotWatchdog').className = data.watchdogActive ? 'dot online' : 'dot offline'; diff --git a/src/PolyTrader.Web/wwwroot/login.html b/src/PolyTrader.Web/wwwroot/login.html index 58834af..daa3898 100644 --- a/src/PolyTrader.Web/wwwroot/login.html +++ b/src/PolyTrader.Web/wwwroot/login.html @@ -5,6 +5,13 @@ PolyTrader — WebUI Login +