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 <html> ueberstimmt prefers-color-scheme in beide Richtungen. Ein kleines Skript im <head> 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 <noreply@anthropic.com>
This commit is contained in:
@@ -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 <html> 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 {
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PolyTrader Web</title>
|
||||
<link rel="stylesheet" href="/css/app.css">
|
||||
<script>
|
||||
// #566: Farbschema vor dem ersten Zeichnen setzen - sonst blitzt beim Laden kurz das falsche auf.
|
||||
try {
|
||||
var t = localStorage.getItem('polytrader-theme');
|
||||
if (t === 'light' || t === 'dark') document.documentElement.setAttribute('data-theme', t);
|
||||
} catch (e) { /* ohne Speicher: dem Betriebssystem folgen */ }
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
@@ -66,7 +73,7 @@
|
||||
<div class="header-actions">
|
||||
<div class="status-indicator" title="Polymarket / Alchemy Connection">
|
||||
<span class="dot" id="dotAlchemy"></span>
|
||||
<span>WSS</span>
|
||||
<span id="lblAlchemy">WSS</span>
|
||||
</div>
|
||||
<div class="status-indicator" title="Mullvad VPN Status">
|
||||
<span class="dot" id="dotVpn"></span>
|
||||
@@ -76,6 +83,11 @@
|
||||
<span class="dot" id="dotWatchdog"></span>
|
||||
<span>Watchdog</span>
|
||||
</div>
|
||||
<!-- #566: wie die Statusleiste des Desktops - wie viele Module laufen. -->
|
||||
<div class="status-indicator" title="Geladene Module">
|
||||
<span id="lblModules">Module –</span>
|
||||
</div>
|
||||
<button class="btn btn-secondary" id="btnTheme" style="padding: 4px 10px; font-size: 12px;" onclick="cycleTheme()" title="Farbschema">◐ System</button>
|
||||
<button class="btn btn-secondary" style="padding: 4px 10px; font-size: 12px;" onclick="logout()">Abmelden</button>
|
||||
</div>
|
||||
</header>
|
||||
@@ -792,6 +804,8 @@
|
||||
<button class="chat-preset-btn" onclick="applySupPreset('Analysiere die verlorenen Trades der letzten 24 Stunden. Was waren die Hauptursachen?')">🔍 Verlust-Analyse</button>
|
||||
<button class="chat-preset-btn" onclick="applySupPreset('Bewerte die Performance der aktiven Master-Trader und markiere auffällige Drift.')">👥 Master-Trader Audit</button>
|
||||
<button class="chat-preset-btn" onclick="applySupPreset('Prüfe die abgelehnten Signale: Hätten wir profitabel getradet (Counterfactuals)?')">💡 Counterfactuals</button>
|
||||
<!-- #566: wie "Verlauf leeren" im Desktop. Gespeicherte Berichte bleiben erhalten. -->
|
||||
<button class="chat-preset-btn" style="margin-left: auto;" onclick="clearSupChat()" title="Leert nur die Unterhaltung hier – das Berichte-Archiv bleibt">🧹 Verlauf leeren</button>
|
||||
</div>
|
||||
<div class="chat-messages-area" id="supChatMessages">
|
||||
<div class="chat-bubble assistant">
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PolyTrader — WebUI Login</title>
|
||||
<link rel="stylesheet" href="/css/app.css">
|
||||
<script>
|
||||
// #566: Farbschema vor dem ersten Zeichnen setzen - sonst blitzt beim Laden kurz das falsche auf.
|
||||
try {
|
||||
var t = localStorage.getItem('polytrader-theme');
|
||||
if (t === 'light' || t === 'dark') document.documentElement.setAttribute('data-theme', t);
|
||||
} catch (e) { /* ohne Speicher: dem Betriebssystem folgen */ }
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user