""" Shared Gradio theme for Davies Tech Labs AI demos. Consistent styling across all demo applications. Cyberpunk aesthetic - dark with yellow/gold accents. """ import gradio as gr # Cyberpunk color palette CYBER_YELLOW = "#d4a700" CYBER_GOLD = "#ffcc00" CYBER_DARK = "#0d0d0d" CYBER_DARKER = "#080808" CYBER_GRAY = "#1a1a1a" CYBER_TEXT = "#e5e5e5" CYBER_MUTED = "#888888" def get_lab_theme() -> gr.Theme: """ Create a custom Gradio theme matching cyberpunk styling. Dark theme with yellow/gold accents. """ return gr.themes.Base( primary_hue=gr.themes.colors.yellow, secondary_hue=gr.themes.colors.amber, neutral_hue=gr.themes.colors.zinc, font=[gr.themes.GoogleFont("Space Grotesk"), "ui-sans-serif", "system-ui", "sans-serif"], font_mono=[gr.themes.GoogleFont("JetBrains Mono"), "ui-monospace", "monospace"], ).set( # Background colors body_background_fill=CYBER_DARK, body_background_fill_dark=CYBER_DARKER, background_fill_primary=CYBER_GRAY, background_fill_primary_dark=CYBER_DARK, background_fill_secondary=CYBER_DARKER, background_fill_secondary_dark="#050505", # Text colors body_text_color=CYBER_TEXT, body_text_color_dark=CYBER_TEXT, body_text_color_subdued=CYBER_MUTED, body_text_color_subdued_dark=CYBER_MUTED, # Borders border_color_primary=CYBER_YELLOW, border_color_primary_dark=CYBER_YELLOW, border_color_accent=CYBER_GOLD, border_color_accent_dark=CYBER_GOLD, # Buttons button_primary_background_fill=CYBER_YELLOW, button_primary_background_fill_dark=CYBER_YELLOW, button_primary_background_fill_hover="#b8940a", button_primary_background_fill_hover_dark="#b8940a", button_primary_text_color=CYBER_DARK, button_primary_text_color_dark=CYBER_DARK, button_primary_border_color=CYBER_GOLD, button_primary_border_color_dark=CYBER_GOLD, button_secondary_background_fill="transparent", button_secondary_background_fill_dark="transparent", button_secondary_text_color=CYBER_YELLOW, button_secondary_text_color_dark=CYBER_YELLOW, button_secondary_border_color=CYBER_YELLOW, button_secondary_border_color_dark=CYBER_YELLOW, # Inputs input_background_fill=CYBER_DARKER, input_background_fill_dark=CYBER_DARKER, input_border_color="#333333", input_border_color_dark="#333333", input_border_color_focus=CYBER_YELLOW, input_border_color_focus_dark=CYBER_YELLOW, # Shadows and effects shadow_drop="0 4px 20px rgba(212, 167, 0, 0.15)", shadow_drop_lg="0 8px 40px rgba(212, 167, 0, 0.2)", # Block styling block_background_fill=CYBER_GRAY, block_background_fill_dark=CYBER_GRAY, block_border_color="#2a2a2a", block_border_color_dark="#2a2a2a", block_label_background_fill="#1a1a00", block_label_background_fill_dark="#1a1a00", block_label_text_color=CYBER_YELLOW, block_label_text_color_dark=CYBER_YELLOW, block_label_border_color=CYBER_YELLOW, block_label_border_color_dark=CYBER_YELLOW, block_title_text_color=CYBER_TEXT, block_title_text_color_dark=CYBER_TEXT, # Table / Dataframe table_border_color="#2a2a2a", table_even_background_fill="#111111", table_even_background_fill_dark="#111111", table_odd_background_fill=CYBER_GRAY, table_odd_background_fill_dark=CYBER_GRAY, table_row_focus="#1f1a00", table_row_focus_dark="#1f1a00", # Panel / accordion panel_background_fill=CYBER_DARK, panel_background_fill_dark=CYBER_DARK, panel_border_color="#2a2a2a", panel_border_color_dark="#2a2a2a", # Checkbox / radio checkbox_background_color=CYBER_DARKER, checkbox_background_color_dark=CYBER_DARKER, checkbox_label_background_fill=CYBER_GRAY, checkbox_label_background_fill_dark=CYBER_GRAY, checkbox_label_text_color=CYBER_TEXT, checkbox_label_text_color_dark=CYBER_TEXT, # Colors color_accent=CYBER_YELLOW, color_accent_soft="#1f1a00", color_accent_soft_dark="#1f1a00", ) # Common CSS for all demos - Cyberpunk theme CUSTOM_CSS = """ /* Cyberpunk font import */ @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=JetBrains+Mono:wght@400;500&display=swap'); /* Root variables */ :root { --cyber-yellow: #d4a700; --cyber-gold: #ffcc00; --cyber-dark: #0d0d0d; --cyber-gray: #1a1a1a; --cyber-text: #e5e5e5; } /* Container styling */ .gradio-container { max-width: 1400px !important; margin: auto !important; background: var(--cyber-dark) !important; } /* Header/title styling - glitch effect */ .title-row, h1 { color: var(--cyber-text) !important; font-family: 'Space Grotesk', sans-serif !important; font-weight: 700 !important; text-transform: uppercase; letter-spacing: 0.15em; position: relative; } h1::after { content: ''; position: absolute; bottom: -8px; left: 0; width: 100%; height: 2px; background: linear-gradient(90deg, var(--cyber-yellow), transparent); } /* Yellow accent lines - horizontal separator */ .cyber-line { width: 100%; height: 2px; background: var(--cyber-yellow); margin: 1.5rem 0; box-shadow: 0 0 10px var(--cyber-yellow); } /* Scrolling Japanese text effect */ .cyber-marquee { overflow: hidden; background: linear-gradient(90deg, var(--cyber-dark), transparent 5%, transparent 95%, var(--cyber-dark)); padding: 0.5rem 0; border-top: 1px solid var(--cyber-yellow); border-bottom: 1px solid var(--cyber-yellow); } .cyber-marquee-content { display: inline-block; white-space: nowrap; animation: marquee 20s linear infinite; color: var(--cyber-yellow); font-family: 'Space Grotesk', sans-serif; letter-spacing: 0.5em; } @keyframes marquee { 0% { transform: translateX(0); } 100% { transform: translateX(-50%); } } /* Status indicators */ .status-ok { color: #00ff88 !important; font-weight: 600; text-shadow: 0 0 10px #00ff88; } .status-error { color: #ff3366 !important; font-weight: 600; text-shadow: 0 0 10px #ff3366; } .status-pending { color: var(--cyber-yellow) !important; font-weight: 600; text-shadow: 0 0 10px var(--cyber-yellow); } /* Metrics display - terminal style */ .metrics-box { background: rgba(13, 13, 13, 0.9) !important; border: 1px solid var(--cyber-yellow) !important; border-radius: 0 !important; padding: 16px !important; font-family: 'JetBrains Mono', monospace !important; color: var(--cyber-gold) !important; box-shadow: 0 0 20px rgba(212, 167, 0, 0.1); } /* Code blocks */ .code-block, pre, code { background: #0a0a0a !important; border: 1px solid #333 !important; border-left: 3px solid var(--cyber-yellow) !important; font-family: 'JetBrains Mono', monospace !important; } /* Buttons - cyber style */ .gr-button-primary { background: var(--cyber-yellow) !important; color: var(--cyber-dark) !important; border: none !important; text-transform: uppercase !important; letter-spacing: 0.1em !important; font-weight: 600 !important; transition: all 0.3s ease !important; clip-path: polygon(0 0, calc(100% - 8px) 0, 100% 8px, 100% 100%, 8px 100%, 0 calc(100% - 8px)); } .gr-button-primary:hover { background: var(--cyber-gold) !important; box-shadow: 0 0 30px rgba(212, 167, 0, 0.5) !important; transform: translateY(-2px); } .gr-button-secondary { background: transparent !important; color: var(--cyber-yellow) !important; border: 1px solid var(--cyber-yellow) !important; text-transform: uppercase !important; letter-spacing: 0.1em !important; } /* Input fields */ .gr-input, .gr-textbox, textarea, input { background: #0a0a0a !important; border: 1px solid #333 !important; color: var(--cyber-text) !important; border-radius: 0 !important; transition: border-color 0.3s ease !important; } .gr-input:focus, .gr-textbox:focus, textarea:focus, input:focus { border-color: var(--cyber-yellow) !important; box-shadow: 0 0 10px rgba(212, 167, 0, 0.3) !important; } /* Tabs - angular cyber style */ .gr-tab-nav { border-bottom: 2px solid var(--cyber-yellow) !important; } .gr-tab { background: transparent !important; color: var(--cyber-muted) !important; border: none !important; text-transform: uppercase !important; letter-spacing: 0.1em !important; } .gr-tab.selected { color: var(--cyber-yellow) !important; background: rgba(212, 167, 0, 0.1) !important; } /* Accordion */ .gr-accordion { border: 1px solid #333 !important; background: var(--cyber-gray) !important; } /* Labels and text */ label, .gr-label { color: var(--cyber-yellow) !important; text-transform: uppercase !important; font-size: 0.75rem !important; letter-spacing: 0.1em !important; } /* Slider styling */ .gr-slider { --slider-color: var(--cyber-yellow) !important; } /* Footer - cyber style */ .footer { text-align: center; color: #666; font-size: 0.8rem; padding: 1.5rem; border-top: 1px solid #333; margin-top: 2rem; font-family: 'JetBrains Mono', monospace; letter-spacing: 0.05em; } .footer a { color: var(--cyber-yellow); text-decoration: none; transition: all 0.3s ease; } .footer a:hover { text-shadow: 0 0 10px var(--cyber-yellow); } /* Cyber badge/tag */ .cyber-badge { display: inline-block; padding: 4px 12px; background: transparent; border: 1px solid var(--cyber-yellow); color: var(--cyber-yellow); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.1em; font-family: 'JetBrains Mono', monospace; } /* Progress bars */ .progress-bar { background: #1a1a1a !important; border: 1px solid #333 !important; } .progress-bar-fill { background: linear-gradient(90deg, var(--cyber-yellow), var(--cyber-gold)) !important; } /* Scrollbar styling */ ::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-track { background: var(--cyber-dark); } ::-webkit-scrollbar-thumb { background: #333; border: 1px solid var(--cyber-yellow); } ::-webkit-scrollbar-thumb:hover { background: #444; } /* Glowing text effect utility */ .glow-text { text-shadow: 0 0 10px var(--cyber-yellow), 0 0 20px var(--cyber-yellow); } /* ── Examples table / Dataframe overrides ── */ /* Gradio renders Examples as a inside a Dataset component. The default styles inject white / light-gray rows that blow out the cyberpunk palette. Force them dark here. */ .gr-samples-table, .gr-sample-textbox, table.table, .gr-examples table, div[class*="dataset"] table { background: var(--cyber-dark) !important; color: var(--cyber-text) !important; } .gr-samples-table tr, .gr-examples table tr, div[class*="dataset"] table tr { background: #111111 !important; border-bottom: 1px solid #222 !important; } .gr-samples-table tr:nth-child(even), .gr-examples table tr:nth-child(even), div[class*="dataset"] table tr:nth-child(even) { background: #0d0d0d !important; } .gr-samples-table tr:hover, .gr-examples table tr:hover, div[class*="dataset"] table tr:hover { background: #1f1a00 !important; cursor: pointer; } .gr-samples-table th, .gr-examples table th, div[class*="dataset"] table th { background: var(--cyber-gray) !important; color: var(--cyber-yellow) !important; text-transform: uppercase !important; font-size: 0.75rem !important; letter-spacing: 0.1em !important; border-bottom: 2px solid var(--cyber-yellow) !important; padding: 10px 16px !important; } .gr-samples-table td, .gr-examples table td, div[class*="dataset"] table td { color: #999 !important; border-bottom: 1px solid #1a1a1a !important; padding: 10px 16px !important; font-family: 'JetBrains Mono', monospace !important; font-size: 0.85rem !important; } /* ── Block label pill (e.g. "GENERATED AUDIO", "STATUS") ── */ /* These are the small floating labels above each component block */ span[class*="label-wrap"], .gr-block-label, .label-wrap { background: #1a1a00 !important; border: 1px solid var(--cyber-yellow) !important; color: var(--cyber-yellow) !important; } /* ── Dropdown / select menus ── */ .gr-dropdown, select, ul[role="listbox"], div[class*="dropdown"], .secondary-wrap { background: #0a0a0a !important; color: var(--cyber-text) !important; border-color: #333 !important; } ul[role="listbox"] li, div[class*="dropdown"] li { background: #0a0a0a !important; color: var(--cyber-text) !important; } ul[role="listbox"] li:hover, ul[role="listbox"] li[aria-selected="true"], div[class*="dropdown"] li:hover { background: #1f1a00 !important; color: var(--cyber-yellow) !important; } /* ── Audio player ── */ .gr-audio, audio { background: var(--cyber-dark) !important; border: 1px solid #2a2a2a !important; } /* Audio waveform container */ div[data-testid="waveform-container"], div[class*="audio"] { background: #0a0a0a !important; } /* ── Markdown inside blocks ── */ .gr-markdown, .gr-markdown p, .prose { color: var(--cyber-text) !important; } .gr-markdown h3, .gr-markdown h2 { color: var(--cyber-yellow) !important; letter-spacing: 0.05em !important; } .gr-markdown strong { color: var(--cyber-gold) !important; } /* ── Examples accordion header ("Examples" label) ── */ .gr-examples .label-wrap, div[id*="examples"] .label-wrap, span[data-testid="block-label"] { background: #1a1a00 !important; color: var(--cyber-yellow) !important; border: 1px solid var(--cyber-yellow) !important; font-size: 0.7rem !important; text-transform: uppercase !important; letter-spacing: 0.1em !important; } /* ── Misc: tooltip, info text ── */ .gr-info, .gr-description { color: #666 !important; } /* ── Svelte internal: make sure no white backgrounds leak ── */ .contain > div, .wrap > div { background: inherit !important; } /* ── Tab content panels ── */ .tabitem { background: var(--cyber-dark) !important; } """ def create_header(title: str, description: str) -> gr.Markdown: """Create a cyberpunk-style header for demo apps.""" # Japanese text for marquee effect jp_text = "サイバー · コマース · フューチャー · " return gr.Markdown(f"""
STORE v2.0 ONLINE

{title.upper()}

{description}

{jp_text * 8}
""") def create_footer() -> gr.Markdown: """Create a cyberpunk-style footer for demo apps.""" return gr.Markdown("""
""")