style(dashboard): redesign Neon Trading Dashboard ispirato a screenshot riferimento
Sostituita palette Modern Fintech con look "neon trading" pink+cyan: - BG #0A0A0F near-black con dual radial glow (pink top-left, cyan bottom-right) - Surface #13131A card base, hover #1C1C26 - Primary pink #FF2D87 (max fitness, key metrics) - Secondary cyan #00D9FF (median, entropy) - Accent amber #FFB800 (p90, warnings) - Success neon green #00E676, danger neon red #FF3D60 Effetti visivi aggiunti: - Card top-border glow gradient (linea pink luminosa) - Card hover: pink shadow esterno + border 0.5 opacity - Inset shadow per dare profondità (subtle highlight top) - Brand-dot pulsing animation 2s (glow pink pulsato) - Header glassmorphic blur(20px) saturate(180%) - Chart fill area gradient sotto le curve max/entropy - Linee Plotly spline smoothing 0.6 (curve morbide) - Marker bordo bianco per pop Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,15 +5,15 @@ Default port 8080. Streamlit resta su 8501 durante la migrazione.
|
||||
|
||||
Riusa ``dashboard.data`` (Repository helpers) senza modifiche al backend.
|
||||
|
||||
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)
|
||||
Palette "Neon Trading Dashboard" (ispirata screenshot 2026-05-11):
|
||||
- BG: #0A0A0F (near-black con tinge blu)
|
||||
- Surface: #13131A (card base)
|
||||
- Surface elevata: #1C1C26 (hover/active)
|
||||
- Primary pink: #FF2D87 (highlight key metrics, max fitness)
|
||||
- Secondary cyan: #00D9FF (median, secondary curves)
|
||||
- Accent amber: #FFB800 (warnings, p90)
|
||||
- Success neon green: #00E676, Danger neon red: #FF3D60
|
||||
- Text: #FFFFFF (primary), #7A7A8C (muted)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -38,18 +38,19 @@ from multi_swarm.dashboard.data import (
|
||||
DB_PATH = os.environ.get("DB_PATH", "./runs.db")
|
||||
REFRESH_INTERVAL_S = 3.0
|
||||
|
||||
# --- 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"
|
||||
# --- Neon Trading Dashboard palette ---
|
||||
COLOR_BG = "#0A0A0F"
|
||||
COLOR_SURFACE = "#13131A"
|
||||
COLOR_SURFACE_2 = "#1C1C26"
|
||||
COLOR_BORDER = "rgba(255, 45, 135, 0.12)"
|
||||
COLOR_BORDER_HOVER = "rgba(255, 45, 135, 0.45)"
|
||||
COLOR_PRIMARY = "#FF2D87"
|
||||
COLOR_SECONDARY = "#00D9FF"
|
||||
COLOR_ACCENT = "#FFB800"
|
||||
COLOR_SUCCESS = "#00E676"
|
||||
COLOR_DANGER = "#FF3D60"
|
||||
COLOR_TEXT = "#FFFFFF"
|
||||
COLOR_TEXT_MUTED = "#7A7A8C"
|
||||
|
||||
_STATUS_BADGE: dict[str, tuple[str, str]] = {
|
||||
"running": ("● running", "positive"),
|
||||
@@ -67,18 +68,40 @@ code, pre, .q-code {{ font-family: 'JetBrains Mono', 'Fira Code', monospace !imp
|
||||
body, .q-page-container, .q-page {{
|
||||
background: {COLOR_BG} !important;
|
||||
color: {COLOR_TEXT};
|
||||
background-image: radial-gradient(ellipse at top, rgba(6, 182, 212, 0.04) 0%, transparent 50%);
|
||||
background-image:
|
||||
radial-gradient(ellipse 800px 400px at 20% 0%, rgba(255, 45, 135, 0.08) 0%, transparent 60%),
|
||||
radial-gradient(ellipse 600px 400px at 80% 100%, rgba(0, 217, 255, 0.06) 0%, transparent 60%);
|
||||
background-attachment: fixed;
|
||||
}}
|
||||
|
||||
.q-card {{
|
||||
background: {COLOR_SURFACE} !important;
|
||||
color: {COLOR_TEXT} !important;
|
||||
border: 1px solid {COLOR_BORDER};
|
||||
border-radius: 12px !important;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.3), 0 4px 12px rgba(0,0,0,0.15);
|
||||
transition: border-color 0.2s, transform 0.2s;
|
||||
border-radius: 14px !important;
|
||||
box-shadow:
|
||||
0 1px 2px rgba(0,0,0,0.5),
|
||||
0 8px 24px rgba(0,0,0,0.25),
|
||||
inset 0 1px 0 rgba(255,255,255,0.04);
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}}
|
||||
.q-card::before {{
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 45, 135, 0.4), transparent);
|
||||
opacity: 0.5;
|
||||
}}
|
||||
.q-card:hover {{
|
||||
border-color: rgba(255, 45, 135, 0.5);
|
||||
box-shadow:
|
||||
0 1px 2px rgba(0,0,0,0.5),
|
||||
0 8px 32px rgba(255, 45, 135, 0.15),
|
||||
inset 0 1px 0 rgba(255,255,255,0.05);
|
||||
}}
|
||||
.q-card:hover {{ border-color: rgba(6, 182, 212, 0.35); }}
|
||||
|
||||
.metric-card {{
|
||||
padding: 20px 16px;
|
||||
@@ -108,11 +131,11 @@ body, .q-page-container, .q-page {{
|
||||
.metric-card.accent-green .text-h4 {{ color: {COLOR_SUCCESS} !important; }}
|
||||
|
||||
.q-header {{
|
||||
background: rgba(19, 24, 41, 0.85) !important;
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
background: rgba(10, 10, 15, 0.75) !important;
|
||||
backdrop-filter: blur(20px) saturate(180%);
|
||||
-webkit-backdrop-filter: blur(20px) saturate(180%);
|
||||
border-bottom: 1px solid {COLOR_BORDER} !important;
|
||||
box-shadow: none !important;
|
||||
box-shadow: 0 1px 0 rgba(255, 45, 135, 0.15) !important;
|
||||
}}
|
||||
|
||||
.nav-link {{
|
||||
@@ -131,7 +154,7 @@ body, .q-page-container, .q-page {{
|
||||
}}
|
||||
.nav-link.active {{
|
||||
color: {COLOR_PRIMARY} !important;
|
||||
background: rgba(6, 182, 212, 0.08);
|
||||
background: rgba(255, 45, 135, 0.08);
|
||||
}}
|
||||
.nav-link.active::after {{
|
||||
content: '';
|
||||
@@ -153,11 +176,16 @@ body, .q-page-container, .q-page {{
|
||||
gap: 8px;
|
||||
}}
|
||||
.brand-dot {{
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: {COLOR_PRIMARY};
|
||||
box-shadow: 0 0 12px {COLOR_PRIMARY};
|
||||
box-shadow: 0 0 16px {COLOR_PRIMARY}, 0 0 4px {COLOR_PRIMARY};
|
||||
animation: pulse-pink 2s ease-in-out infinite;
|
||||
}}
|
||||
@keyframes pulse-pink {{
|
||||
0%, 100% {{ box-shadow: 0 0 16px {COLOR_PRIMARY}, 0 0 4px {COLOR_PRIMARY}; }}
|
||||
50% {{ box-shadow: 0 0 24px {COLOR_PRIMARY}, 0 0 8px {COLOR_PRIMARY}; }}
|
||||
}}
|
||||
|
||||
.q-linear-progress {{ height: 8px !important; border-radius: 6px !important; }}
|
||||
@@ -187,8 +215,8 @@ body, .q-page-container, .q-page {{
|
||||
letter-spacing: 0.06em;
|
||||
}}
|
||||
.q-table tbody tr {{ transition: background 0.15s; }}
|
||||
.q-table tbody tr:hover {{ background: rgba(6, 182, 212, 0.05) !important; }}
|
||||
.q-table tbody tr.selected {{ background: rgba(6, 182, 212, 0.12) !important; }}
|
||||
.q-table tbody tr:hover {{ background: rgba(255, 45, 135, 0.05) !important; }}
|
||||
.q-table tbody tr.selected {{ background: rgba(255, 45, 135, 0.12) !important; }}
|
||||
.q-table td {{ border-bottom: 1px solid {COLOR_BORDER} !important; font-feature-settings: 'tnum'; }}
|
||||
|
||||
.text-h6 {{ font-weight: 600 !important; letter-spacing: -0.015em !important; }}
|
||||
@@ -202,11 +230,11 @@ body, .q-page-container, .q-page {{
|
||||
}}
|
||||
|
||||
code, pre {{
|
||||
background: #0D1220 !important;
|
||||
background: #0F0F15 !important;
|
||||
color: {COLOR_TEXT} !important;
|
||||
border: 1px solid {COLOR_BORDER};
|
||||
border-radius: 8px !important;
|
||||
padding: 12px !important;
|
||||
border-radius: 10px !important;
|
||||
padding: 14px !important;
|
||||
}}
|
||||
|
||||
.q-badge {{ border-radius: 6px !important; font-weight: 500 !important; padding: 4px 10px !important; font-size: 12px !important; }}
|
||||
@@ -312,15 +340,18 @@ def _convergence_figure(gens_df: Any) -> go.Figure:
|
||||
go.Scatter(
|
||||
x=gens_df["generation_idx"], y=gens_df["fitness_max"],
|
||||
name="max", mode="lines+markers",
|
||||
line={"color": COLOR_PRIMARY, "width": 3},
|
||||
marker={"size": 9, "color": COLOR_PRIMARY},
|
||||
line={"color": COLOR_PRIMARY, "width": 3, "shape": "spline", "smoothing": 0.6},
|
||||
marker={"size": 9, "color": COLOR_PRIMARY,
|
||||
"line": {"color": "#fff", "width": 1}},
|
||||
fill="tozeroy",
|
||||
fillcolor="rgba(255, 45, 135, 0.12)",
|
||||
)
|
||||
)
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=gens_df["generation_idx"], y=gens_df["fitness_p90"],
|
||||
name="p90", mode="lines+markers",
|
||||
line={"color": COLOR_ACCENT, "width": 2, "dash": "dot"},
|
||||
line={"color": COLOR_ACCENT, "width": 2, "dash": "dot", "shape": "spline"},
|
||||
marker={"size": 7, "color": COLOR_ACCENT},
|
||||
)
|
||||
)
|
||||
@@ -328,7 +359,7 @@ def _convergence_figure(gens_df: Any) -> go.Figure:
|
||||
go.Scatter(
|
||||
x=gens_df["generation_idx"], y=gens_df["fitness_median"],
|
||||
name="median", mode="lines+markers",
|
||||
line={"color": COLOR_SECONDARY, "width": 2},
|
||||
line={"color": COLOR_SECONDARY, "width": 2, "shape": "spline"},
|
||||
marker={"size": 7, "color": COLOR_SECONDARY},
|
||||
)
|
||||
)
|
||||
@@ -340,7 +371,7 @@ def _convergence_figure(gens_df: Any) -> go.Figure:
|
||||
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(19, 24, 41, 0.95)", "bordercolor": COLOR_PRIMARY, "borderwidth": 1},
|
||||
legend={"bgcolor": "rgba(19, 19, 26, 0.95)", "bordercolor": COLOR_PRIMARY, "borderwidth": 1},
|
||||
margin={"l": 50, "r": 30, "t": 50, "b": 50},
|
||||
)
|
||||
return fig
|
||||
@@ -353,8 +384,11 @@ def _entropy_figure(gens_df: Any) -> go.Figure:
|
||||
go.Scatter(
|
||||
x=gens_df["generation_idx"], y=gens_df["entropy"],
|
||||
mode="lines+markers",
|
||||
line={"color": COLOR_PRIMARY, "width": 3},
|
||||
marker={"size": 9, "color": COLOR_PRIMARY},
|
||||
line={"color": COLOR_SECONDARY, "width": 3, "shape": "spline", "smoothing": 0.6},
|
||||
marker={"size": 9, "color": COLOR_SECONDARY,
|
||||
"line": {"color": "#fff", "width": 1}},
|
||||
fill="tozeroy",
|
||||
fillcolor="rgba(0, 217, 255, 0.12)",
|
||||
name="entropy",
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user