mazinger-dubber / theme.py
HeshamHaroon's picture
feat: cinematic dark theme with pipeline visualizer CSS
61f3e47
"""
Mazinger Dubber β€” Cinematic dark theme for Gradio.
Aesthetic: DaVinci Resolve / Premiere Pro editing suite.
"""
from __future__ import annotations
import gradio as gr
from gradio.themes.utils import colors
# ---------------------------------------------------------------------------
# Color palettes
# ---------------------------------------------------------------------------
amber = colors.Color(
name="amber",
c50="#FFF8E7",
c100="#FEF0C7",
c200="#FDD98A",
c300="#FBC24D",
c400="#F9AB10",
c500="#F5A623",
c600="#D4861A",
c700="#AA6412",
c800="#7A440B",
c900="#4A2905",
c950="#2A1B05",
)
teal = colors.Color(
name="teal",
c50="#ECFDF5",
c100="#D1FAE5",
c200="#A7F3D0",
c300="#6EE7B7",
c400="#2DD4BF",
c500="#14B8A6",
c600="#0D9488",
c700="#0F766E",
c800="#115E59",
c900="#134E4A",
c950="#042F2E",
)
studio_gray = colors.Color(
name="studio_gray",
c50="#E8E8ED",
c100="#D0D0D8",
c200="#A8A8B4",
c300="#7A7A8A",
c400="#5A5A6A",
c500="#3A3A48",
c600="#2A2A36",
c700="#1E222B",
c800="#161A21",
c900="#0D0F12",
c950="#070809",
)
# ---------------------------------------------------------------------------
# Custom CSS
# ---------------------------------------------------------------------------
CUSTOM_CSS = """
@import url('https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@200;800;900&family=IBM+Plex+Sans:wght@400;600&family=JetBrains+Mono:wght@400&display=swap');
/* ── Design tokens ─────────────────────────────────────────────────────── */
:root {
--bg-deep: #0D0F12;
--bg-surface: #161A21;
--border-subtle: rgba(255, 255, 255, 0.06);
--accent-amber: #F5A623;
--accent-teal: #2DD4BF;
--text-primary: #E8E8ED;
--text-secondary: #8B8D97;
}
/* ── Body / container resets ───────────────────────────────────────────── */
body,
.gradio-container {
background-color: var(--bg-deep) !important;
font-family: 'IBM Plex Sans', sans-serif !important;
color: var(--text-primary) !important;
}
/* ── Studio header ─────────────────────────────────────────────────────── */
.studio-header {
text-align: center;
padding: 2.5rem 1rem 1.5rem;
}
.studio-header h1 {
font-family: 'Bricolage Grotesque', sans-serif;
font-weight: 900;
font-size: 3.5rem;
line-height: 1.05;
color: var(--text-primary);
margin: 0 0 0.5rem;
letter-spacing: -0.01em;
}
.studio-header p {
font-family: 'IBM Plex Sans', sans-serif;
font-weight: 400;
font-size: 1rem;
color: var(--text-secondary);
letter-spacing: 0.08em;
margin: 0;
text-transform: uppercase;
}
/* ── Card surface ──────────────────────────────────────────────────────── */
.card-surface {
background: var(--bg-surface);
border: 1px solid var(--border-subtle);
border-radius: 12px;
padding: 1.5rem;
}
/* ── Primary action button ─────────────────────────────────────────────── */
.dub-btn,
.dub-btn button {
background: var(--accent-amber) !important;
color: var(--bg-deep) !important;
font-family: 'Bricolage Grotesque', sans-serif !important;
font-weight: 800 !important;
font-size: 1.2rem !important;
letter-spacing: 0.12em !important;
border: none !important;
border-radius: 8px !important;
padding: 0.85rem 2rem !important;
cursor: pointer !important;
transition: box-shadow 0.25s ease, transform 0.15s ease !important;
text-transform: uppercase !important;
}
.dub-btn:hover,
.dub-btn button:hover {
box-shadow: 0 0 24px rgba(245, 166, 35, 0.55),
0 0 48px rgba(245, 166, 35, 0.25) !important;
transform: translateY(-1px) !important;
}
/* ── Pipeline visualizer ───────────────────────────────────────────────── */
.pipeline-container {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: 0;
padding: 1rem 0;
}
.pipeline-node {
width: 44px;
height: 50px;
background: #1E222B;
clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
transition: background 0.4s ease, box-shadow 0.4s ease;
flex-shrink: 0;
}
.pipeline-node.active {
background: var(--accent-amber);
animation: pulse-amber 1.6s ease-in-out infinite;
}
.pipeline-node.done {
background: var(--accent-teal);
animation: none;
}
.pipeline-connector {
width: 24px;
height: 2px;
background: #1E222B;
flex-shrink: 0;
transition: background 0.4s ease;
}
.pipeline-connector.done {
background: var(--accent-teal);
}
.pipeline-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.6rem;
color: var(--text-secondary);
text-align: center;
margin-top: 0.4rem;
letter-spacing: 0.04em;
text-transform: uppercase;
}
/* ── Pulse animation ───────────────────────────────────────────────────── */
@keyframes pulse-amber {
0% { box-shadow: 0 0 0px rgba(245, 166, 35, 0); }
50% { box-shadow: 0 0 20px rgba(245, 166, 35, 0.75); }
100% { box-shadow: 0 0 0px rgba(245, 166, 35, 0); }
}
/* ── Log area ──────────────────────────────────────────────────────────── */
.log-area textarea {
font-family: 'JetBrains Mono', monospace !important;
font-size: 0.8rem !important;
color: var(--accent-amber) !important;
background: #0A0C0F !important;
border: 1px solid var(--border-subtle) !important;
border-radius: 6px !important;
resize: vertical !important;
}
/* ── Studio footer ─────────────────────────────────────────────────────── */
.studio-footer {
text-align: center;
color: var(--text-secondary);
font-size: 0.8rem;
padding: 1.5rem 1rem 2rem;
}
.studio-footer a {
color: var(--accent-amber);
text-decoration: none;
}
.studio-footer a:hover {
text-decoration: underline;
}
"""
# ---------------------------------------------------------------------------
# Theme class
# ---------------------------------------------------------------------------
class MazingerTheme(gr.themes.Base):
"""
Cinematic dark Gradio theme for Mazinger Dubber.
Primary accent: amber (#F5A623).
Secondary accent: teal (#2DD4BF).
Neutral: dark studio grays.
"""
def __init__(self, **kwargs):
super().__init__(
primary_hue=amber,
secondary_hue=teal,
neutral_hue=studio_gray,
font=["IBM Plex Sans", "sans-serif"],
font_mono=["JetBrains Mono", "monospace"],
**kwargs,
)
# Surface / background overrides
self.set(
body_background_fill="*neutral_900", # --bg-deep (#0D0F12)
body_background_fill_dark="*neutral_900",
background_fill_primary="*neutral_800", # --bg-surface (#161A21)
background_fill_primary_dark="*neutral_800",
background_fill_secondary="*neutral_900",
background_fill_secondary_dark="*neutral_900",
# Border
border_color_primary="rgba(255,255,255,0.06)",
border_color_primary_dark="rgba(255,255,255,0.06)",
# Text
body_text_color="*neutral_50", # #E8E8ED
body_text_color_dark="*neutral_50",
body_text_color_subdued="*neutral_300", # #8B8D97-ish
body_text_color_subdued_dark="*neutral_300",
# Buttons β€” primary
button_primary_background_fill="*primary_500",
button_primary_background_fill_dark="*primary_500",
button_primary_background_fill_hover="*primary_400",
button_primary_background_fill_hover_dark="*primary_400",
button_primary_text_color="*neutral_950",
button_primary_text_color_dark="*neutral_950",
# Buttons β€” secondary
button_secondary_background_fill="*neutral_700",
button_secondary_background_fill_dark="*neutral_700",
button_secondary_text_color="*neutral_50",
button_secondary_text_color_dark="*neutral_50",
# Inputs
input_background_fill="*neutral_900",
input_background_fill_dark="*neutral_900",
input_border_color="rgba(255,255,255,0.06)",
input_border_color_dark="rgba(255,255,255,0.06)",
input_border_color_focus="*primary_500",
input_border_color_focus_dark="*primary_500",
input_placeholder_color="*neutral_300",
input_placeholder_color_dark="*neutral_300",
# Block labels
block_label_text_color="*neutral_300",
block_label_text_color_dark="*neutral_300",
block_title_text_color="*neutral_50",
block_title_text_color_dark="*neutral_50",
# Radius
block_radius="12px",
button_large_radius="8px",
input_radius="6px",
# Shadow
block_shadow="0 2px 12px rgba(0,0,0,0.45)",
block_shadow_dark="0 2px 12px rgba(0,0,0,0.65)",
)