| """Praxy Field Guide — shared design system for the Build-Small hackathon apps. |
| |
| One CSS framework, themed per app via tokens. Injected via gr.HTML('<style>…</style>') |
| because Gradio 6.0 dropped the css= argument from gr.Blocks(). All colour pairings |
| are chosen to pass WCAG AA (body text >=4.5:1, large text / UI >=3:1). |
| |
| A copy of this file lives in each hf_space_* directory (the spaces upload |
| independently and cannot share a module). Keep them in sync. |
| """ |
| from __future__ import annotations |
|
|
| |
| THEMES = { |
| |
| "nidra": { |
| "bg": "#0B1026", "bg2": "#070A1C", "surface": "#161C3F", "surface2": "#1E2550", |
| "ink": "#F4EFDE", "muted": "#AEB4D6", "faint": "#9CA2C8", |
| "accent": "#F5C842", "accent_ink": "#1A1304", "accent2": "#9E86FF", |
| "border": "rgba(245,200,66,.20)", "ring": "rgba(245,200,66,.45)", |
| "display": "Fraunces", "body": "Plus Jakarta Sans", |
| }, |
| |
| "readit": { |
| "bg": "#FBF3E3", "bg2": "#F6E9CE", "surface": "#FFFCF5", "surface2": "#F5EDE0", |
| "ink": "#2D1306", "muted": "#6B3D1E", "faint": "#9A7550", |
| "accent": "#C2410C", "accent_ink": "#FFFFFF", "accent2": "#7B1F2E", |
| "border": "rgba(120,60,0,.18)", "ring": "rgba(194,65,12,.35)", |
| "display": "Fraunces", "body": "Plus Jakarta Sans", |
| }, |
| |
| "polyglot": { |
| "bg": "#0E1020", "bg2": "#080A18", "surface": "#181B33", "surface2": "#20243F", |
| "ink": "#F1EEF8", "muted": "#AFB0CC", "faint": "#9698BE", |
| "accent": "#8B7FF9", "accent_ink": "#0B0B1A", "accent2": "#5BB8F2", |
| "border": "rgba(255,255,255,.10)", "ring": "rgba(139,127,249,.45)", |
| "display": "Fraunces", "body": "Plus Jakarta Sans", |
| }, |
| |
| |
| "owls": { |
| "bg": "#F0E6CC", "bg2": "#E6D8B6", "surface": "#FAF5EB", "surface2": "#F2E9D2", |
| "ink": "#221E14", "muted": "#5C4A1E", "faint": "#8A7B5C", |
| "accent": "#2F5D44", "accent_ink": "#F7F1E1", "accent2": "#8B6914", |
| "border": "rgba(60,50,30,.22)", "ring": "rgba(47,93,68,.40)", |
| "display": "Fraunces", "body": "Plus Jakarta Sans", |
| }, |
| } |
|
|
| _FONTS = ("https://fonts.googleapis.com/css2?" |
| "family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,600;0,9..144,700;0,9..144,900;" |
| "1,9..144,400;1,9..144,600&" |
| "family=Plus+Jakarta+Sans:wght@400;500;600;700;800&" |
| "family=Noto+Sans:wght@400;500;600&display=swap") |
|
|
|
|
| def build_css(theme: str, extra: str = "") -> str: |
| """Return the full themed stylesheet for `theme` (a key in THEMES).""" |
| t = THEMES[theme] |
| return f""" |
| @import url('{_FONTS}'); |
| |
| :root {{ |
| --bg:{t['bg']}; --bg2:{t['bg2']}; --surface:{t['surface']}; --surface2:{t['surface2']}; |
| --ink:{t['ink']}; --muted:{t['muted']}; --faint:{t['faint']}; |
| --accent:{t['accent']}; --accent-ink:{t['accent_ink']}; --accent2:{t['accent2']}; |
| --border:{t['border']}; --ring:{t['ring']}; |
| --display:'{t['display']}',Georgia,serif; --body:'{t['body']}','Noto Sans',sans-serif; |
| --radius:18px; --gap:18px; |
| }} |
| |
| /* ---- fill the whole viewport, widen the column ---- */ |
| html, body, gradio-app, .gradio-container, .app, #root {{ |
| background: var(--bg) !important; |
| }} |
| body, .gradio-container {{ font-family: var(--body) !important; color: var(--ink) !important; }} |
| .gradio-container {{ |
| max-width: 1180px !important; margin: 0 auto !important; |
| padding-left: 20px !important; padding-right: 20px !important; |
| }} |
| .gradio-container, .gradio-container * {{ box-sizing: border-box; }} |
| |
| /* headings + prose */ |
| h1,h2,h3 {{ font-family: var(--display) !important; color: var(--ink) !important; }} |
| |
| /* ---- surfaces / cards ---- */ |
| .gr-form, .gr-block, .gr-panel, .block, .contain, .gr-box, .form {{ |
| background: var(--surface) !important; |
| border: 1px solid var(--border) !important; |
| border-radius: var(--radius) !important; |
| }} |
| .gap, .panel, .wrap {{ gap: var(--gap) !important; }} |
| |
| /* ---- labels ---- */ |
| label > span, .label-wrap > span, span[data-testid="block-info"] {{ |
| color: var(--muted) !important; font-size: 11px !important; |
| font-weight: 700 !important; letter-spacing: .09em !important; |
| text-transform: uppercase !important; font-family: var(--body) !important; |
| }} |
| |
| /* floating component labels (Audio / File / Image): Gradio overlays these with a |
| near-white chip; theme them so they don't read as unstyled white blobs. */ |
| .block-label, span.block-label, div.block-label {{ |
| background: var(--surface2) !important; color: var(--muted) !important; |
| border: 1px solid var(--border) !important; box-shadow: none !important; |
| backdrop-filter: none !important; |
| }} |
| .block-label span, .block-label p {{ color: var(--muted) !important; }} |
| .block-label svg, .block-label svg * {{ color: var(--muted) !important; fill: currentColor !important; }} |
| |
| /* ---- inputs ---- */ |
| input[type=text], input[type=number], textarea, select, .gr-text-input {{ |
| background: var(--surface2) !important; |
| border: 1.5px solid var(--border) !important; |
| border-radius: 12px !important; |
| color: var(--ink) !important; font-size: 15px !important; |
| font-family: var(--body) !important; |
| }} |
| input::placeholder, textarea::placeholder {{ color: var(--faint) !important; opacity: 1; }} |
| input:focus, textarea:focus, select:focus {{ |
| border-color: var(--accent) !important; outline: none !important; |
| box-shadow: 0 0 0 3px var(--ring) !important; |
| }} |
| input[type=range] {{ accent-color: var(--accent) !important; }} |
| input[type=checkbox] {{ accent-color: var(--accent) !important; width:18px; height:18px; }} |
| |
| /* ---- accessible focus ring for keyboard users ---- */ |
| :focus-visible {{ outline: 3px solid var(--ring) !important; outline-offset: 2px !important; }} |
| |
| /* ---- primary CTA ---- */ |
| button.primary, .gr-button-primary, #cta button {{ |
| background: var(--accent) !important; color: var(--accent-ink) !important; |
| font-weight: 800 !important; font-size: 16px !important; letter-spacing: .02em !important; |
| font-family: var(--body) !important; border: none !important; |
| border-radius: 14px !important; padding: 16px 30px !important; width: 100% !important; |
| cursor: pointer !important; |
| box-shadow: 0 6px 22px rgba(0,0,0,.18) !important; |
| transition: transform .15s ease, box-shadow .25s ease, filter .2s ease !important; |
| }} |
| button.primary:hover, .gr-button-primary:hover, #cta button:hover {{ |
| transform: translateY(-2px) !important; filter: brightness(1.05) !important; |
| box-shadow: 0 10px 34px rgba(0,0,0,.28) !important; |
| }} |
| #cta button:active {{ transform: translateY(0) !important; }} |
| |
| /* secondary buttons */ |
| .gr-button-secondary {{ |
| background: var(--surface2) !important; color: var(--ink) !important; |
| border: 1.5px solid var(--border) !important; border-radius: 12px !important; |
| font-family: var(--body) !important; font-weight: 600 !important; |
| }} |
| |
| /* audio + image blocks */ |
| .waveform-container, .gr-audio, audio {{ border-radius: 12px !important; }} |
| |
| /* tidy chrome */ |
| footer {{ display: none !important; }} |
| .gradio-container .prose a {{ color: var(--accent2) !important; }} |
| ::-webkit-scrollbar {{ width: 8px; height: 8px; }} |
| ::-webkit-scrollbar-track {{ background: var(--bg2); }} |
| ::-webkit-scrollbar-thumb {{ background: var(--accent); border-radius: 6px; opacity:.6; }} |
| |
| /* shared pill / divider helpers used inside gr.HTML output */ |
| .pf-pill {{ |
| display:inline-block; padding:5px 14px; border-radius:20px; font-size:11px; |
| font-weight:700; letter-spacing:.06em; font-family:var(--body); |
| }} |
| .pf-divider {{ height:1px; background:linear-gradient(90deg,transparent,var(--border),transparent); margin:18px 0; border:none; }} |
| |
| @media (max-width: 760px) {{ |
| .gradio-container {{ padding-left: 12px !important; padding-right: 12px !important; }} |
| }} |
| {extra} |
| """ |
|
|