Spaces:
Sleeping
Sleeping
| # 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"] | |