Chan-Compass / theme.py
ranranrunforit's picture
Upload 24 files
a4d2fa1 verified
Raw
History Blame Contribute Delete
9.29 kB
# Spectrum 2 theme for Gradio — Chan Compass (v2, refined)
# ---------------------------------------------------------------
# Single source of truth for the LIVE Gradio app's look. Mirrors the
# Chan Compass · Spectrum 2 design system. Drop this next to app.py.
#
# from theme import THEME, CSS
# with gr.Blocks(title="Chan Compass · US", theme=THEME, css=CSS) as demo:
# ...
# demo.launch() # Gradio 5
# # Gradio 6+: demo.launch(theme=THEME, css=CSS)
# ---------------------------------------------------------------
import gradio as gr
# ---- Spectrum 2 palette (light) -------------------------------------------
ACCENT = "#0265dc" # blue-900
ACCENT_HOVER = "#0054b6" # blue-1000
ACCENT_DOWN = "#00418f" # blue-1100
ACCENT_SUBTLE= "#e0f2ff" # blue-100
GRAY_25 = "#ffffff"
GRAY_50 = "#f8f8f8" # canvas
GRAY_75 = "#f3f3f3"
GRAY_100 = "#e6e6e6" # hairline border
GRAY_200 = "#d5d5d5"
GRAY_300 = "#b1b1b1" # field border
GRAY_500 = "#6d6d6d" # muted text
GRAY_700 = "#292929" # body text
GRAY_800 = "#1b1b1b"
POSITIVE = "#007a39"
NEGATIVE = "#d7373f"
NOTICE = "#b25309"
THEME = gr.themes.Default(
font=[gr.themes.GoogleFont("Source Sans 3"), "Adobe Clean", "system-ui", "sans-serif"],
font_mono=[gr.themes.GoogleFont("Source Code Pro"), "monospace"],
primary_hue=gr.themes.colors.blue,
neutral_hue=gr.themes.colors.gray,
radius_size=gr.themes.sizes.radius_lg,
spacing_size=gr.themes.sizes.spacing_md,
).set(
# surfaces
body_background_fill=GRAY_50,
background_fill_primary=GRAY_25,
background_fill_secondary=GRAY_75,
block_background_fill=GRAY_25,
block_border_color=GRAY_100,
block_border_width="1px",
block_radius="16px",
block_shadow="0 1px 3px rgba(0,0,0,.06), 0 1px 1px rgba(0,0,0,.04)",
block_label_text_color=GRAY_500,
block_label_text_weight="600",
block_title_text_color=GRAY_800,
block_title_text_weight="700",
border_color_primary=GRAY_100,
panel_background_fill=GRAY_25,
panel_border_color=GRAY_100,
# text
body_text_color=GRAY_700,
body_text_color_subdued=GRAY_500,
body_text_size="14px",
# buttons — Spectrum 2 signature pill
button_large_radius="9999px",
button_small_radius="9999px",
button_large_padding="10px 22px",
button_primary_background_fill=ACCENT,
button_primary_background_fill_hover=ACCENT_HOVER,
button_primary_text_color="#ffffff",
button_primary_border_color=ACCENT,
button_primary_shadow="none",
button_secondary_background_fill=GRAY_25,
button_secondary_background_fill_hover=GRAY_75,
button_secondary_border_color=GRAY_300,
button_secondary_text_color=GRAY_700,
# inputs
input_background_fill=GRAY_25,
input_border_color=GRAY_300,
input_border_color_focus=ACCENT,
input_border_width="2px",
input_radius="8px",
input_shadow="none",
# accents / links
color_accent_soft=ACCENT_SUBTLE,
link_text_color=ACCENT_HOVER,
link_text_color_hover=ACCENT_DOWN,
)
# ---- Fine-grained CSS the theme object can't express ----------------------
CSS = """
:root{
--s2-accent:#0265dc; --s2-accent-hover:#0054b6; --s2-accent-down:#00418f; --s2-accent-subtle:#e0f2ff;
--s2-gray-25:#fff; --s2-gray-50:#f8f8f8; --s2-gray-75:#f3f3f3; --s2-gray-100:#e6e6e6;
--s2-gray-200:#d5d5d5; --s2-gray-300:#b1b1b1; --s2-gray-500:#6d6d6d; --s2-gray-700:#292929; --s2-gray-800:#1b1b1b;
--s2-positive:#007a39; --s2-negative:#d7373f; --s2-notice:#b25309;
--s2-radius-card:16px; --s2-ease:cubic-bezier(.45,0,.4,1);
}
body,.gradio-container{ background:var(--s2-gray-50)!important; color:var(--s2-gray-700);
font-family:'Source Sans 3','Adobe Clean',system-ui,sans-serif; }
.gradio-container{ max-width:1200px!important; margin:0 auto!important; padding-top:8px!important; }
.gap{ gap:14px; }
/* ---------- Buttons : Spectrum 2 pill ---------- */
button.primary, button.secondary, button.lg, button.sm{
border-radius:9999px!important; font-weight:600!important; letter-spacing:0;
transition:background-color .13s var(--s2-ease), transform .12s var(--s2-ease), box-shadow .13s var(--s2-ease); }
button.primary{ box-shadow:0 1px 2px rgba(2,101,220,.18)!important; }
button.primary:hover{ box-shadow:0 2px 8px rgba(2,101,220,.22)!important; }
button.primary:active, button.secondary:active{ transform:scale(.98); }
button:focus-visible{ outline:2px solid var(--s2-accent)!important; outline-offset:2px; }
.table-wrap button, table button, .dataframe button, [class*="cell-menu"] button{
border-radius:6px!important; font-weight:500!important; box-shadow:none!important; }
/* ---------- Hero ---------- */
#s2-hero{ display:flex; align-items:center; gap:18px;
background:linear-gradient(180deg,#fff 0%,#fcfdff 100%);
border:1px solid var(--s2-gray-100); border-radius:20px;
padding:22px 26px; margin:6px 0 14px; box-shadow:0 1px 3px rgba(0,0,0,.05); }
#s2-hero .mark{ width:50px; height:50px; flex:none; border-radius:14px; display:grid; place-items:center;
background:linear-gradient(135deg,#0265dc 0%,#5258e4 58%,#7326d3 100%);
color:#fff; font-size:26px; box-shadow:0 4px 14px rgba(2,101,220,.22); }
#s2-hero h1{ margin:0; font-size:25px; font-weight:800; letter-spacing:-.015em; color:var(--s2-gray-800); }
#s2-hero h1 span{ font-weight:300; color:var(--s2-gray-500); }
#s2-hero p{ margin:4px 0 0; color:var(--s2-gray-500); font-size:13.5px; line-height:1.45; max-width:620px; }
#s2-hero .chips{ margin-left:auto; display:flex; flex-wrap:wrap; gap:6px; justify-content:flex-end; max-width:330px; }
#s2-hero .chips span{ background:var(--s2-gray-75); border:1px solid var(--s2-gray-100); border-radius:9999px;
padding:3px 11px; font-size:11.5px; font-weight:600; color:var(--s2-gray-700); white-space:nowrap; }
/* ---------- Tabs : quiet + accent underline ---------- */
.tab-nav{ border-bottom:2px solid var(--s2-gray-100)!important; gap:22px; margin-bottom:6px; }
.tab-nav button{ border:none!important; background:transparent!important; border-radius:0!important;
font-size:15.5px!important; font-weight:600!important; color:var(--s2-gray-500)!important;
padding:11px 2px!important; margin-bottom:-2px; transition:color .13s var(--s2-ease); }
.tab-nav button:hover{ color:var(--s2-gray-700)!important; }
.tab-nav button.selected{ color:var(--s2-accent)!important; box-shadow:inset 0 -2px 0 var(--s2-accent)!important; }
/* ---------- Cards / groups ---------- */
.block{ border-radius:var(--s2-radius-card)!important; }
.gr-group, .group{ border:1px solid var(--s2-gray-100)!important; border-radius:var(--s2-radius-card)!important;
background:#fff; overflow:hidden; }
/* control bar — the primary input row of each tab, framed as a card */
#s2-app .s2-bar{ background:#fff!important; border:1px solid var(--s2-gray-100)!important;
border-radius:14px!important; padding:14px 16px!important; box-shadow:0 1px 3px rgba(0,0,0,.05);
align-items:flex-end!important; }
#s2-app .s2-bar .block{ border:none!important; box-shadow:none!important; background:transparent!important; }
/* eyebrow section labels */
.s2-eyebrow p{ margin:14px 0 2px!important; font-size:11px!important; font-weight:700!important;
letter-spacing:.07em; text-transform:uppercase; color:var(--s2-gray-500)!important; }
.s2-help p{ color:var(--s2-gray-500)!important; font-size:13px!important; line-height:1.5; margin:2px 0 6px!important; }
/* ---------- Data tables ---------- */
.dataframe, table{ font-size:13.5px!important; }
thead th{ background:var(--s2-gray-75)!important; font-weight:700!important; text-transform:uppercase;
letter-spacing:.04em; font-size:11px!important; color:var(--s2-gray-500)!important; }
tbody td{ border-color:var(--s2-gray-100)!important; }
tbody tr:hover td{ background:var(--s2-gray-75)!important; }
/* ---------- AI output panel — signature accent-framed surface ---------- */
.llm-out{ border:1px solid var(--s2-gray-100); border-left:5px solid var(--s2-accent); border-radius:12px;
background:#fff; padding:16px 20px; min-height:140px; font-size:14.5px; line-height:1.6;
overflow:auto; box-shadow:0 2px 12px rgba(2,101,220,.07); }
.llm-out:empty::after{ content:"🤖 AI output appears here"; color:#9aa0a6; font-style:italic; }
.llm-out h1,.llm-out h2,.llm-out h3{ font-size:16px; margin:.4em 0 .3em; color:var(--s2-gray-800); }
/* raw-read (non-AI) markdown reads as a quiet well */
#detail-log textarea{ font-family:'Source Code Pro',monospace!important; font-size:12.5px!important;
background:var(--s2-gray-75)!important; border-radius:10px!important; }
/* ---------- Accordion (email rows, collapsible) ---------- */
.gr-accordion, .accordion{ border:1px solid var(--s2-gray-100)!important; border-radius:12px!important;
background:#fff; overflow:hidden; }
.gr-accordion > button, .accordion > button{ font-weight:600!important; color:var(--s2-gray-700)!important;
font-size:13.5px!important; }
/* ---------- Misc ---------- */
.s2-footnote p{ color:var(--s2-gray-500)!important; font-size:12.5px!important; }
hr{ border:none; border-top:1px solid var(--s2-gray-100); margin:18px 0; }
label span{ font-weight:600; }
::selection{ background:var(--s2-accent-subtle); }
"""
__all__ = ["THEME", "CSS"]