ttm-webapp-hf / theme.py
Daniel Wojahn
UI fixes
2c93726
"""
Tibetan Text Metrics Theme - Gradio 6 Compatible
This theme provides a clean, professional look for the TTM application.
Updated for Gradio 6.x compatibility where theme/css are passed to launch().
"""
import gradio as gr
from gradio.themes.utils import colors, sizes, fonts
class TibetanAppTheme(gr.themes.Soft):
"""
Custom theme for Tibetan Text Metrics application.
Gradio 6 Migration Notes:
- Theme is now passed to demo.launch(theme=...) instead of gr.Blocks(theme=...)
- CSS is now passed to demo.launch(css=...) instead of gr.Blocks(css=...)
- Use elem_id and elem_classes for stable CSS targeting
"""
def __init__(self):
super().__init__(
primary_hue=colors.blue,
secondary_hue=colors.orange,
neutral_hue=colors.slate,
font=[
fonts.GoogleFont("Inter"),
"ui-sans-serif",
"system-ui",
"sans-serif",
],
radius_size=sizes.radius_md,
text_size=sizes.text_md,
)
# Theme variable overrides using Gradio's theming system
self.theme_vars_for_set = {
# Global & Body Styles
"body_background_fill": "#f0f2f5",
"body_text_color": "#333333",
"body_text_color_subdued": "#4b5563",
# Block/Card Styles
"block_background_fill": "#ffffff",
"block_radius": "16px",
"block_shadow": "0 4px 12px rgba(0, 0, 0, 0.08)",
"block_padding": "24px",
"block_border_width": "0px",
# Button Styles - Secondary
"button_secondary_background_fill": "#ffffff",
"button_secondary_text_color": "#374151",
"button_secondary_border_color": "#d1d5db",
"button_secondary_border_color_hover": "#adb5bd",
"button_secondary_background_fill_hover": "#f9fafb",
# Button Styles - Primary
"button_primary_background_fill": "#2563eb",
"button_primary_text_color": "#ffffff",
"button_primary_border_color": "transparent",
"button_primary_background_fill_hover": "#1d4ed8",
# Border colors
"border_color_accent_subdued": "#e5e7eb",
"border_color_primary": "#d1d5db",
# Input styles
"input_background_fill": "#ffffff",
"input_border_color": "#d1d5db",
"input_border_color_focus": "#2563eb",
}
super().set(**self.theme_vars_for_set)
def get_css_string(self) -> str:
"""
Returns custom CSS string for additional styling.
Gradio 6 uses different class naming conventions. This CSS uses:
- elem_id selectors (#id) for specific components
- elem_classes selectors (.class) for groups of components
- Gradio 6 native classes where stable
"""
return """
/* ============================================
GLOBAL STYLES
============================================ */
.gradio-container {
font-family: 'Inter', ui-sans-serif, system-ui, sans-serif !important;
max-width: 1600px !important;
margin: 0 auto !important;
font-size: 16px !important;
}
/* Base font size for all text */
body, .gradio-container * {
font-size: 16px;
}
/* ============================================
TYPOGRAPHY
============================================ */
h1 {
font-size: 32px !important;
font-weight: 600 !important;
color: #111827 !important;
margin-bottom: 12px !important;
}
h2 {
font-size: 26px !important;
font-weight: 600 !important;
color: var(--primary-600, #2563eb) !important;
margin-top: 24px !important;
margin-bottom: 16px !important;
}
h3 {
font-size: 22px !important;
font-weight: 600 !important;
color: #1f2937 !important;
margin-top: 20px !important;
margin-bottom: 12px !important;
}
/* Labels and form text */
label, .label-wrap, span.svelte-1gfkn6j {
font-size: 16px !important;
}
/* Info text under inputs */
.info {
font-size: 14px !important;
}
/* ============================================
LAYOUT - Steps Row
============================================ */
#steps-row {
display: flex !important;
align-items: stretch !important;
gap: 24px !important;
}
.step-column {
display: flex !important;
flex-direction: column !important;
flex: 1 !important;
}
.step-box {
padding: 1.5rem !important;
flex-grow: 1 !important;
display: flex !important;
flex-direction: column !important;
}
/* ============================================
BUTTONS
============================================ */
/* Primary action buttons */
#run-btn-quick, #run-btn-custom {
background: var(--button-primary-background-fill, #2563eb) !important;
color: var(--button-primary-text-color, #ffffff) !important;
font-weight: 600 !important;
font-size: 18px !important;
padding: 12px 24px !important;
border: none !important;
border-radius: 8px !important;
box-shadow: 0 2px 4px rgba(37, 99, 235, 0.2) !important;
transition: all 0.2s ease !important;
margin-top: 16px !important;
}
#run-btn-quick:hover, #run-btn-custom:hover {
background: var(--button-primary-background-fill-hover, #1d4ed8) !important;
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3) !important;
transform: translateY(-1px) !important;
}
/* Secondary buttons */
button.secondary {
background-color: #ffffff !important;
color: #374151 !important;
border: 1px solid #d1d5db !important;
border-radius: 8px !important;
padding: 10px 20px !important;
font-weight: 500 !important;
}
button.secondary:hover {
background-color: #f9fafb !important;
border-color: #adb5bd !important;
}
/* ============================================
TABS
============================================ */
.tabs {
margin-top: 8px !important;
}
.tab-nav {
border-bottom: 1px solid #e5e7eb !important;
margin-bottom: 16px !important;
}
.tab-nav button {
color: #6b7280 !important;
background-color: transparent !important;
padding: 12px 20px !important;
border: none !important;
border-bottom: 2px solid transparent !important;
font-weight: 500 !important;
transition: all 0.2s ease !important;
}
.tab-nav button:hover {
color: #374151 !important;
}
.tab-nav button.selected {
border-bottom: 2px solid var(--primary-500, #3b82f6) !important;
color: var(--primary-600, #2563eb) !important;
background-color: transparent !important;
}
/* ============================================
ACCORDIONS
============================================ */
.accordion {
border: 1px solid #e5e7eb !important;
border-radius: 8px !important;
margin-bottom: 12px !important;
overflow: hidden !important;
}
/* Metric info accordions with colored borders */
.metric-info-accordion {
border-left: 4px solid #3B82F6 !important;
margin-bottom: 1rem !important;
background-color: #F8FAFC !important;
border-radius: 6px !important;
}
.jaccard-info { border-left-color: #3B82F6 !important; }
.lcs-info { border-left-color: #10B981 !important; }
.fuzzy-info { border-left-color: #F59E0B !important; }
.semantic-info { border-left-color: #8B5CF6 !important; }
.wordcount-info { border-left-color: #EC4899 !important; }
/* ============================================
FORM ELEMENTS
============================================ */
/* Radio buttons */
.radio-group label {
display: flex !important;
align-items: center !important;
padding: 10px 16px !important;
border: 1px solid #e5e7eb !important;
border-radius: 8px !important;
margin-bottom: 8px !important;
cursor: pointer !important;
transition: all 0.2s ease !important;
}
.radio-group label:hover {
background-color: #f9fafb !important;
border-color: #d1d5db !important;
}
.radio-group input:checked + label,
.radio-group label.selected {
background-color: var(--primary-50, #eff6ff) !important;
border-color: var(--primary-500, #3b82f6) !important;
}
/* Dropdowns */
select, .dropdown {
border: 1px solid #d1d5db !important;
border-radius: 8px !important;
padding: 10px 12px !important;
background-color: #ffffff !important;
}
/* Checkboxes */
input[type="checkbox"] {
width: 18px !important;
height: 18px !important;
accent-color: var(--primary-500, #3b82f6) !important;
}
/* ============================================
PRESET TABLE
============================================ */
.preset-table table {
font-size: 15px !important;
margin-top: 16px !important;
width: 100% !important;
border-collapse: collapse !important;
}
.preset-table th, .preset-table td {
padding: 12px 16px !important;
text-align: center !important;
border-bottom: 1px solid #e5e7eb !important;
}
.preset-table th {
background-color: #f9fafb !important;
font-weight: 600 !important;
color: #374151 !important;
font-size: 15px !important;
}
.preset-table tr:hover {
background-color: #f9fafb !important;
}
/* Radio button options - larger text */
.gr-radio label, .gr-radio span {
font-size: 16px !important;
}
/* Dropdown options */
.gr-dropdown, select {
font-size: 16px !important;
}
/* ============================================
RESULTS SECTION
============================================ */
/* Heatmaps and plots - full width */
.plot-container, .plotly, .js-plotly-plot {
width: 100% !important;
max-width: 100% !important;
}
/* Remove extra padding/margin from plot containers */
.gr-plot, [data-testid="plot"] {
width: 100% !important;
padding: 0 !important;
}
/* Tab content should use full width */
.tabitem, [data-testid="tabitem"] {
width: 100% !important;
padding: 16px 0 !important;
}
/* Remove dead space after plots */
.tabs .tabitem > div {
margin-bottom: 0 !important;
}
.metric-heatmap {
max-width: 100% !important;
width: 100% !important;
}
/* ============================================
LLM ANALYSIS OUTPUT
============================================ */
#llm-analysis {
background-color: #f8f9fa !important;
border-left: 4px solid #3B82F6 !important;
border-radius: 8px !important;
padding: 20px 24px !important;
margin: 16px 0 !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05) !important;
}
#llm-analysis h2 {
color: #1e40af !important;
font-size: 22px !important;
margin-bottom: 16px !important;
border-bottom: 1px solid #e5e7eb !important;
padding-bottom: 8px !important;
}
#llm-analysis h3, #llm-analysis h4 {
color: #1e3a8a !important;
margin-top: 18px !important;
margin-bottom: 10px !important;
}
#llm-analysis p {
line-height: 1.7 !important;
margin-bottom: 12px !important;
color: #374151 !important;
}
#llm-analysis ul, #llm-analysis ol {
margin-left: 24px !important;
margin-bottom: 16px !important;
}
#llm-analysis li {
margin-bottom: 6px !important;
}
#llm-analysis strong, #llm-analysis b {
color: #1f2937 !important;
font-weight: 600 !important;
}
/* ============================================
RESPONSIVE ADJUSTMENTS
============================================ */
@media (max-width: 768px) {
#steps-row {
flex-direction: column !important;
}
.step-column {
width: 100% !important;
}
#run-btn-quick, #run-btn-custom {
font-size: 16px !important;
padding: 10px 20px !important;
}
}
/* ============================================
UTILITY CLASSES
============================================ */
.custom-header {
margin-bottom: 12px !important;
color: #374151 !important;
}
.info-text {
font-size: 14px !important;
color: #6b7280 !important;
margin-top: 4px !important;
}
"""
# Instantiate the theme for easy import
tibetan_theme = TibetanAppTheme()