Jordancole21's picture
Deploy native Gradio SEO page and tool
73e2d15 verified
Raw
History Blame Contribute Delete
7.21 kB
"""Guild-dark theme: dark green + gold, matching the original backstory forge.
Exports the CSS string and a head-HTML builder (meta tags + JSON-LD).
In Gradio 6, css/head are passed to demo.launch(), not gr.Blocks().
"""
import html as _html
import json
# Palette
BG = "#2A4032" # deep green page background
PANEL = "#3D5A47" # card/panel green
GOLD = "#D4AF37" # headings, accents
CREAM = "#F2E6CE" # body text
CREAM_DIM = "rgba(242, 230, 206, 0.85)"
RED = "#A7343B" # Loreify CTA red (matches loreify.ai accent)
RED_DARK = "#7E2429"
CSS = """
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=Inter:wght@400;500;600;700&display=swap');
:root {
--lf-bg: #2A4032;
--lf-panel: #3D5A47;
--lf-panel-deep: #24382C;
--lf-gold: #D4AF37;
--lf-cream: #F2E6CE;
--lf-cream-dim: rgba(242, 230, 206, 0.85);
--lf-red: #A7343B;
--lf-red-dark: #7E2429;
}
body, gradio-app, .gradio-container {
background-color: var(--lf-bg) !important;
color: var(--lf-cream);
font-family: 'Inter', system-ui, sans-serif;
}
.gradio-container { max-width: 72rem !important; margin: 0 auto !important; }
/* ---------- typography ---------- */
/* !important: Gradio's dark-theme prose styles (?__theme=dark on the HF
embed) otherwise override heading colors to white. */
.lf-page h1 {
font-family: 'Press Start 2P', monospace;
color: var(--lf-gold) !important;
font-size: 1.35rem;
line-height: 1.6;
margin: 1.25rem 0 0.75rem 0;
-webkit-font-smoothing: none;
word-wrap: break-word;
}
.lf-page h2 {
font-family: 'Press Start 2P', monospace;
color: var(--lf-gold) !important;
font-size: 0.95rem;
line-height: 1.6;
margin: 2rem 0 0.75rem 0;
-webkit-font-smoothing: none;
}
.lf-page h3 { color: var(--lf-gold) !important; }
/* native control accents (radios, checkboxes) — gold, not Gradio orange */
.gradio-container input[type="radio"],
.gradio-container input[type="checkbox"] { accent-color: var(--lf-gold); }
.gradio-container input[type="radio"]:checked,
.gradio-container input[type="checkbox"]:checked {
background-color: var(--lf-gold) !important;
border-color: var(--lf-gold) !important;
}
.lf-page h3 { color: var(--lf-gold); font-size: 1.05rem; margin: 1.25rem 0 0.5rem 0; font-weight: 700; }
.lf-page p, .lf-page li { color: var(--lf-cream-dim); line-height: 1.7; font-size: 1rem; }
.lf-page ul, .lf-page ol { padding-left: 1.25rem; margin: 0.75rem 0; }
.lf-page li::marker { color: var(--lf-gold); }
.lf-page a { color: var(--lf-gold); text-decoration: underline; }
.lf-page strong { color: var(--lf-gold); }
.lf-tagline { font-size: 1.1rem !important; color: var(--lf-cream) !important; }
/* ---------- panels the tool lives in ---------- */
.lf-panel, .lf-page .block, .gradio-container .form {
background-color: var(--lf-panel) !important;
border: 1px solid rgba(212, 175, 55, 0.35) !important;
border-radius: 8px;
}
.lf-page label span, .lf-page .label-wrap span { color: var(--lf-cream) !important; }
.lf-page input, .lf-page textarea, .lf-page select {
background-color: var(--lf-panel-deep) !important;
color: var(--lf-cream) !important;
border-color: rgba(212, 175, 55, 0.35) !important;
}
/* primary action buttons — gold everywhere, not Gradio's default orange */
.gradio-container button.primary, .lf-page .lf-generate button {
background: var(--lf-gold) !important;
color: #21301F !important;
border: none !important;
font-weight: 700;
}
.gradio-container button.primary:hover { filter: brightness(1.08); }
/* wide content (stat tables, battle boards) scrolls inside its container */
.lf-output { overflow-x: auto; }
.lf-output table { min-width: 480px; }
/* ---------- Loreify CTA blocks ---------- */
.lf-cta {
background: linear-gradient(160deg, rgba(167, 52, 59, 0.16), rgba(167, 52, 59, 0.05));
border: 1px solid rgba(212, 175, 55, 0.45);
border-radius: 8px;
padding: 1.25rem 1.5rem;
margin: 1.5rem 0;
text-align: center;
}
.lf-cta p { color: var(--lf-cream); font-size: 1.05rem; margin: 0 0 0.9rem 0; }
.lf-cta .lf-cta-btn {
display: inline-block;
background: var(--lf-red);
color: #FFFBE0 !important;
border: 2px solid var(--lf-red-dark);
border-radius: 6px;
padding: 0.7rem 1.5rem;
font-weight: 700;
font-size: 1rem;
text-decoration: none !important;
box-shadow: 1px 2px 4px rgba(0,0,0,0.25);
}
.lf-cta .lf-cta-btn:hover { background: var(--lf-red-dark); }
.lf-cta .lf-cta-sub { font-size: 0.85rem; color: var(--lf-cream-dim); margin-top: 0.6rem; margin-bottom: 0; }
/* ---------- output / example cards ---------- */
.lf-output, .lf-example {
background: var(--lf-panel);
border: 1px solid rgba(212, 175, 55, 0.45);
border-radius: 8px;
padding: 1.25rem 1.5rem;
margin: 0.75rem 0;
}
.lf-output h3, .lf-example h3 { margin-top: 0.75rem; }
/* related tools + footer */
.lf-related { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; margin: 1rem 0; }
.lf-related a.lf-related-card {
display: block; background: var(--lf-panel);
border: 1px solid rgba(212, 175, 55, 0.4); border-radius: 8px;
padding: 1rem; text-decoration: none;
}
.lf-related a.lf-related-card:hover { border-color: var(--lf-gold); }
.lf-related .lf-related-title { color: var(--lf-gold); font-weight: 700; margin-bottom: 0.35rem; }
.lf-related .lf-related-desc { color: var(--lf-cream-dim); font-size: 0.9rem; }
.lf-disclaimer { font-size: 0.82rem; color: rgba(242, 230, 206, 0.6); margin: 2rem 0 1rem 0; line-height: 1.6; }
/* FAQ */
.lf-faq details {
background: var(--lf-panel); border: 1px solid rgba(212, 175, 55, 0.35);
border-radius: 8px; padding: 0.85rem 1.1rem; margin: 0.6rem 0;
}
.lf-faq summary { color: var(--lf-gold); font-weight: 700; cursor: pointer; font-size: 1rem; }
.lf-faq details p { margin: 0.7rem 0 0.2rem 0; }
/* mobile */
@media (max-width: 640px) {
.lf-page h1 { font-size: 1.05rem; }
.lf-page h2 { font-size: 0.85rem; }
.lf-cta { padding: 1rem; }
}
footer { display: none !important; }
/* offscreen-but-in-DOM (e.g. clipboard source textarea) */
.lf-offscreen {
position: absolute !important;
left: -99999px !important;
top: 0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden !important;
opacity: 0;
pointer-events: none;
}
"""
def build_head(config, jsonld_extra: dict | None = None) -> str:
"""Meta description + WebApplication JSON-LD for the page head."""
desc = _html.escape(config.tagline, quote=True)
data = {
"@context": "https://schema.org",
"@type": "WebApplication",
"name": config.h1,
"description": config.tagline,
"url": config.space_url,
"applicationCategory": "GameApplication",
"operatingSystem": "Any",
"offers": {"@type": "Offer", "price": "0", "priceCurrency": "USD"},
}
if jsonld_extra:
data.update(jsonld_extra)
return (
f'<meta name="description" content="{desc}">\n'
f'<script type="application/ld+json">{json.dumps(data)}</script>'
)