Emre Sarigöl
Deploy sync_pilot dashboard - 2026-06-10 16:54
ed8f8ab
Raw
History Blame Contribute Delete
6.83 kB
"""Centralized color palette + minimal CSS tweaks for the dashboard.
Only essential overrides live here. No custom theming beyond the palette
constants the brief permits. ``apply_global_styles`` is called once from
``app.py`` on first render.
"""
from __future__ import annotations
import streamlit as st
# Single source of truth for source-coloring across every chart on every page.
# Keep these in sync with the constants imported in ``plots.py``.
MAEST_COLOR = "#5B5EA6"
CLAP_COLOR = "#1FB3A5"
MUQ_COLOR = "#9B5DE5"
MUQ_REVIEW_COLOR = "#C77DFF"
PASST_COLOR = "#F59E0B"
TAXONOMY_ADAPTER_COLOR = "#2563EB"
LYRICS_COLOR = "#E07B39"
STEM_COLOR = "#E07B39"
# Theme tags from the lyrics-llm extractor (Tier 2). Sage green deliberately
# sits outside the MAEST indigo / CLAP teal / Whisper orange palette so the
# fifth tag category is immediately distinguishable in small-multiples.
THEME_COLOR = "#8DAA7B"
# Neutral chrome.
INK_COLOR = "#1F2933"
MUTED_COLOR = "#6B7280"
ACCENT_BG = "#F5F7FA"
CARD_BG = "#FFFFFF"
DIVIDER = "#E5E7EB"
# Category color (used when a chart isn't source-split but category-split).
CATEGORY_COLORS = {
"genre": "#5B5EA6",
"mood": "#9B5DE5",
"instrument": "#1FB3A5",
"vocal": "#E07B39",
"other": "#6B7280",
}
# Reviewer badge palette (taxonomy "open questions" cards).
REVIEWER_COLORS = {
"Aran": "#5B5EA6",
"Murat": "#1FB3A5",
"Emre": "#E07B39",
}
_GLOBAL_CSS = """
<style>
/* Tighten the default Streamlit padding so wide content breathes. */
.main .block-container {
padding-top: 1.4rem;
padding-bottom: 3rem;
max-width: 1400px;
}
/* Cards used on the overview and track pages. */
.sync-card {
background: #FFFFFF;
border: 1px solid #E5E7EB;
border-radius: 12px;
padding: 18px 20px;
margin-bottom: 14px;
}
.sync-card h4 {
margin: 0 0 8px 0;
font-size: 0.95rem;
color: #1F2933;
font-weight: 600;
letter-spacing: 0.02em;
text-transform: uppercase;
}
/* Ground-truth panel — wider, with a left accent stripe and theme-agnostic
colours. The explicit white background protects the body text from
becoming invisible when Streamlit auto-picks the user's dark OS theme. */
.sync-gt-card {
background: #FFFFFF;
border: 1px solid #E5E7EB;
border-left: 4px solid #5B5EA6;
border-radius: 10px;
padding: 18px 22px 6px 22px;
margin-bottom: 18px;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.sync-gt-card .sync-gt-label {
font-size: 0.74rem;
color: #6B7280;
text-transform: uppercase;
letter-spacing: 0.06em;
font-weight: 600;
}
.sync-gt-card .sync-gt-value {
font-size: 1.0rem;
color: #0F172A;
font-weight: 500;
line-height: 1.35;
}
.sync-gt-card .sync-gt-value-muted {
color: #9CA3AF;
font-weight: 400;
font-style: italic;
}
/* Quiet header eyebrow above page titles. */
.sync-eyebrow {
font-size: 0.75rem;
color: #6B7280;
letter-spacing: 0.12em;
text-transform: uppercase;
margin-bottom: 4px;
}
.sync-track-picker-eyebrow {
margin: 0 0 6px 0;
color: #94A3B8;
font-size: 0.76rem;
font-weight: 750;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.sync-track-picker-summary {
margin: 6px 0 10px 0;
color: #94A3B8;
font-size: 0.88rem;
}
.sync-track-picker-summary strong {
color: #E5E7EB;
font-weight: 750;
}
.sync-track-picker-summary code {
color: #6EE7B7;
background: rgba(16, 185, 129, 0.10);
border-radius: 5px;
padding: 2px 6px;
}
/* Description blockquote on the track page. */
.sync-description {
background: #F5F7FA;
border-left: 4px solid #5B5EA6;
padding: 14px 18px;
border-radius: 4px;
font-size: 1.02rem;
line-height: 1.55;
color: #1F2933;
font-style: italic;
}
.sync-youtube-link {
display: inline-flex;
align-items: center;
gap: 6px;
margin: 2px 0 10px 0;
padding: 5px 11px;
border: 1px solid #CBD5E1;
border-radius: 999px;
color: #334155 !important;
background: #F8FAFC;
font-size: 0.86rem;
font-weight: 650;
text-decoration: none !important;
}
.sync-youtube-link:hover {
border-color: #94A3B8;
background: #F1F5F9;
color: #0F172A !important;
}
.sync-brief {
background: #EFF6FF;
border-left: 4px solid #2563EB;
padding: 14px 18px;
border-radius: 4px;
font-size: 1.02rem;
line-height: 1.55;
color: #1E3A8A;
}
/* Reviewer badge (taxonomy open-questions page). */
.sync-badge {
display: inline-block;
padding: 2px 10px;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 600;
color: white;
letter-spacing: 0.04em;
margin-right: 6px;
}
/* Confidence pill — used inline next to GT field values. Bordered and
weighted for legibility against a white card, with each confidence level
carrying both a hue and a saturation step so they're distinguishable in
greyscale / colour-blind viewing too. */
.sync-pill {
display: inline-block;
padding: 2px 9px;
border-radius: 999px;
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
margin-left: 8px;
vertical-align: middle;
border: 1px solid transparent;
line-height: 1.4;
}
.sync-pill-high {
background: #ECFDF5;
color: #065F46;
border-color: #6EE7B7;
}
.sync-pill-medium {
background: #FEF3C7;
color: #92400E;
border-color: #FCD34D;
}
.sync-pill-low {
background: #FFEDD5;
color: #9A3412;
border-color: #FDBA74;
}
.sync-pill-uncertain {
background: #F1F5F9;
color: #475569;
border-color: #CBD5E1;
}
.sync-pill-alert {
background: #FEE2E2;
color: #991B1B;
border-color: #FCA5A5;
}
/* Instrumentation / category chips — deeper indigo than before so the
chip stands out cleanly on the white card without competing with the
accent stripe colour. */
.sync-chip {
display: inline-block;
padding: 4px 12px;
border-radius: 999px;
background: #EEF2FF;
color: #3730A3;
border: 1px solid #C7D2FE;
font-size: 0.84rem;
font-weight: 500;
margin: 3px 6px 3px 0;
}
/* Stat cell on overview pipeline grid. */
.sync-stat {
display: flex;
flex-direction: column;
gap: 2px;
}
.sync-stat-label {
font-size: 0.72rem;
color: #6B7280;
text-transform: uppercase;
letter-spacing: 0.06em;
}
.sync-stat-value {
font-size: 1.35rem;
color: #1F2933;
font-weight: 600;
}
.sync-stat-sub {
font-size: 0.78rem;
color: #6B7280;
}
</style>
"""
def apply_global_styles() -> None:
"""Inject the small set of CSS overrides we rely on.
Idempotent — safe to call from every page; Streamlit's rerun model means
pages re-execute top-to-bottom anyway.
"""
st.markdown(_GLOBAL_CSS, unsafe_allow_html=True)