From 0486e198291985c2999b149b35db8d60f6c975e5 Mon Sep 17 00:00:00 2001 From: AdrianoDev Date: Mon, 11 May 2026 22:39:59 +0200 Subject: [PATCH] style(dashboard): redesign moderno con palette Modern Fintech Dark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sostituita palette Inter FC con design language fintech moderno tipo Linear/Tremor/Plane: Palette: - BG #0A0E1A deep blue-black con radial gradient sottile - Surface #131829 / surface-2 #1A2138 per hover/active - Primary cyan #06B6D4 (highlight performance) - Secondary purple #A78BFA (median curves) - Accent amber #F59E0B (warnings, p90) - Success #10B981, danger #EF4444 Typography: - Inter da Google Fonts (peso 400-700) - JetBrains Mono per code/numeri tabulari - letter-spacing negativo + tnum font-feature Component refinement: - Card: border sottile rgba + hover cyan glow, no gradient pesante - Header: backdrop-blur 12px + glass effect - Nav link: underline animato bottom su active - Brand: dot pulsante cyan con glow - Progress bar: 8px rounded, track surface-2 - Metric card: layout left-aligned, label uppercase tracked, value 26px con accent class (cyan/purple/amber/green) per coding semantico - Tabella: header uppercase tracked, row hover cyan-tinted - Code block: surface scuro + border + JetBrains Mono Plot Plotly: - paper_bgcolor β†’ surface (no piΓΉ sfondo full-bleed) - gridcolor neutral rgba(slate, 0.08) - Legend bg surface 0.95 opacity Co-Authored-By: Claude Opus 4.7 (1M context) --- src/multi_swarm/dashboard/nicegui_app.py | 284 ++++++++++++++++------- 1 file changed, 206 insertions(+), 78 deletions(-) diff --git a/src/multi_swarm/dashboard/nicegui_app.py b/src/multi_swarm/dashboard/nicegui_app.py index db4c565..4641cbe 100644 --- a/src/multi_swarm/dashboard/nicegui_app.py +++ b/src/multi_swarm/dashboard/nicegui_app.py @@ -5,11 +5,15 @@ Default port 8080. Streamlit resta su 8501 durante la migrazione. Riusa ``dashboard.data`` (Repository helpers) senza modifiche al backend. -Palette Inter FC: -- Nero: #000000 (sfondo) -- Dark navy: #010E80 (heritage Inter, surface) -- Blu primary: #1E5BC6 -- Blu secondary: #0068A8 +Palette "Modern Fintech Dark": +- BG: #0A0E1A (deep blue-black) +- Surface: #131829 (card base) +- Surface elevata: #1A2138 (hover/active) +- Primary cyan: #06B6D4 (performance highlights) +- Secondary purple: #A78BFA (median, secondary curves) +- Accent amber: #F59E0B (warnings, p90) +- Success green: #10B981, Danger red: #EF4444 +- Text: #F1F5F9 (primary), #94A3B8 (muted) """ from __future__ import annotations @@ -34,57 +38,178 @@ from multi_swarm.dashboard.data import ( DB_PATH = os.environ.get("DB_PATH", "./runs.db") REFRESH_INTERVAL_S = 3.0 -# --- Inter FC palette --- -COLOR_BG = "#000000" -COLOR_SURFACE = "#010E80" -COLOR_PRIMARY = "#1E5BC6" -COLOR_SECONDARY = "#0068A8" -COLOR_ACCENT = "#FFD700" -COLOR_TEXT = "#E8EEFC" -COLOR_TEXT_MUTED = "#8FA3D4" +# --- Modern Fintech Dark palette --- +COLOR_BG = "#0A0E1A" +COLOR_SURFACE = "#131829" +COLOR_SURFACE_2 = "#1A2138" +COLOR_BORDER = "rgba(148, 163, 184, 0.12)" +COLOR_PRIMARY = "#06B6D4" +COLOR_SECONDARY = "#A78BFA" +COLOR_ACCENT = "#F59E0B" +COLOR_SUCCESS = "#10B981" +COLOR_DANGER = "#EF4444" +COLOR_TEXT = "#F1F5F9" +COLOR_TEXT_MUTED = "#94A3B8" _STATUS_BADGE: dict[str, tuple[str, str]] = { - "running": ("🟒 running", "positive"), - "completed": ("βœ… completed", "positive"), - "failed": ("❌ failed", "negative"), + "running": ("● running", "positive"), + "completed": ("βœ“ completed", "positive"), + "failed": ("βœ• failed", "negative"), } _CUSTOM_CSS = f""" """ @@ -98,29 +223,32 @@ def _apply_theme() -> None: accent=COLOR_ACCENT, dark=COLOR_BG, dark_page=COLOR_BG, - positive="#00C853", - negative="#D32F2F", - info=COLOR_SECONDARY, - warning="#FFB300", + positive=COLOR_SUCCESS, + negative=COLOR_DANGER, + info=COLOR_PRIMARY, + warning=COLOR_ACCENT, ) def _build_header(active: str) -> None: - with ui.header().classes("items-center justify-between q-px-md"): - with ui.row().classes("items-center gap-6"): - ui.label("βš«πŸ”΅ Multi-Swarm Coevolutivo").classes("text-h6").style( - f"color: {COLOR_TEXT}; font-weight: 700;" - ) - for path, label in ( - ("/", "Overview"), - ("/convergence", "GA Convergence"), - ("/genomes", "Genomes"), - ): - cls = "nav-link active" if active == path else "nav-link" - ui.link(label, path).classes(cls) - ui.label(f"DB: {Path(DB_PATH).resolve().name}").classes("text-caption").style( - f"color: {COLOR_TEXT_MUTED};" - ) + with ui.header().classes("items-center justify-between q-px-lg q-py-md"): + with ui.row().classes("items-center gap-8"): + with ui.row().classes("items-center gap-2").classes("brand"): + ui.html('') + ui.html('Multi-Swarm / Coevolutivo') + with ui.row().classes("items-center gap-1"): + for path, label in ( + ("/", "Overview"), + ("/convergence", "Convergence"), + ("/genomes", "Genomes"), + ): + cls = "nav-link active" if active == path else "nav-link" + ui.link(label, path).classes(cls) + with ui.row().classes("items-center gap-3"): + ui.html(f'' + f'⛁ {Path(DB_PATH).resolve().name}') def _runs_options() -> dict[str, str]: @@ -206,13 +334,13 @@ def _convergence_figure(gens_df: Any) -> go.Figure: ) fig.update_layout( template="plotly_dark", - paper_bgcolor=COLOR_BG, - plot_bgcolor=COLOR_BG, + paper_bgcolor=COLOR_SURFACE, + plot_bgcolor=COLOR_SURFACE, font={"color": COLOR_TEXT}, - xaxis={"title": "generation", "gridcolor": "rgba(30, 91, 198, 0.2)", "dtick": 1}, - yaxis={"title": "fitness", "gridcolor": "rgba(30, 91, 198, 0.2)"}, + xaxis={"title": "generation", "gridcolor": "rgba(148, 163, 184, 0.08)", "dtick": 1}, + yaxis={"title": "fitness", "gridcolor": "rgba(148, 163, 184, 0.08)"}, title={"text": "Fitness convergence", "font": {"color": COLOR_TEXT, "size": 18}}, - legend={"bgcolor": "rgba(1, 14, 128, 0.6)", "bordercolor": COLOR_PRIMARY, "borderwidth": 1}, + legend={"bgcolor": "rgba(19, 24, 41, 0.95)", "bordercolor": COLOR_PRIMARY, "borderwidth": 1}, margin={"l": 50, "r": 30, "t": 50, "b": 50}, ) return fig @@ -237,11 +365,11 @@ def _entropy_figure(gens_df: Any) -> go.Figure: ) fig.update_layout( template="plotly_dark", - paper_bgcolor=COLOR_BG, - plot_bgcolor=COLOR_BG, + paper_bgcolor=COLOR_SURFACE, + plot_bgcolor=COLOR_SURFACE, font={"color": COLOR_TEXT}, - xaxis={"title": "generation", "gridcolor": "rgba(30, 91, 198, 0.2)", "dtick": 1}, - yaxis={"title": "entropy", "gridcolor": "rgba(30, 91, 198, 0.2)"}, + xaxis={"title": "generation", "gridcolor": "rgba(148, 163, 184, 0.08)", "dtick": 1}, + yaxis={"title": "entropy", "gridcolor": "rgba(148, 163, 184, 0.08)"}, title={"text": "Diversity (fitness entropy)", "font": {"color": COLOR_TEXT, "size": 18}}, margin={"l": 50, "r": 30, "t": 50, "b": 50}, ) @@ -275,16 +403,16 @@ def index() -> None: eval_bar = ui.linear_progress(0.0, show_value=False).props("size=20px color=accent") with ui.row().classes("w-full gap-4"): - with ui.card().classes("flex-grow metric-card"): + with ui.card().classes("flex-grow metric-card accent-cyan"): ui.label("Top fitness").classes("text-caption") top_lbl = ui.label("β€”").classes("text-h4") - with ui.card().classes("flex-grow metric-card"): + with ui.card().classes("flex-grow metric-card accent-purple"): ui.label("Median fitness").classes("text-caption") median_lbl = ui.label("β€”").classes("text-h4") - with ui.card().classes("flex-grow metric-card"): + with ui.card().classes("flex-grow metric-card accent-amber"): ui.label("Parse success").classes("text-caption") parse_lbl = ui.label("β€”").classes("text-h4") - with ui.card().classes("flex-grow metric-card"): + with ui.card().classes("flex-grow metric-card accent-green"): ui.label("Cost (USD)").classes("text-caption") cost_lbl = ui.label("β€”").classes("text-h4") @@ -475,19 +603,19 @@ def genomes() -> None: ).style(f"color: {COLOR_TEXT_MUTED};") with ui.row().classes("w-full gap-4 q-mt-sm"): - with ui.card().classes("flex-grow metric-card"): + with ui.card().classes("flex-grow metric-card accent-cyan"): ui.label("fitness").classes("text-caption") fit_lbl = ui.label("β€”").classes("text-h4") - with ui.card().classes("flex-grow metric-card"): + with ui.card().classes("flex-grow metric-card accent-purple"): ui.label("DSR").classes("text-caption") dsr_lbl = ui.label("β€”").classes("text-h4") - with ui.card().classes("flex-grow metric-card"): + with ui.card().classes("flex-grow metric-card accent-amber"): ui.label("Sharpe").classes("text-caption") sharpe_lbl = ui.label("β€”").classes("text-h4") with ui.card().classes("flex-grow metric-card"): ui.label("max DD").classes("text-caption") dd_lbl = ui.label("β€”").classes("text-h4") - with ui.card().classes("flex-grow metric-card"): + with ui.card().classes("flex-grow metric-card accent-green"): ui.label("trades").classes("text-caption") trades_lbl = ui.label("β€”").classes("text-h4") with ui.card().classes("flex-grow metric-card"):