Spaces:
Build error
Build error
File size: 6,480 Bytes
fecc811 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | """Gradio HTML blocks for the DreamVoice UI β starfield, moon, and storybook."""
from __future__ import annotations
import gradio as gr
_STARFIELD_CSS = """
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,700;1,400&family=Pacifico&display=swap');
/* ββ reset & canvas ββββββββββββββββββββββββββββββββββββββββββββ */
#dv-stars-root, #dv-stars-root * { box-sizing: border-box; margin: 0; padding: 0; }
#dv-stars-root {
position: fixed; inset: 0; z-index: -1; overflow: hidden;
background: linear-gradient(170deg, #0a0a1a 0%, #1a1a3e 100%);
pointer-events: none;
}
/* ββ stars βββββββββββββββββββββββββββββββββββββββββββββββββββββ */
#dv-stars-root .star {
position: absolute; border-radius: 50%; background: #fff;
animation: dv-twinkle var(--dur) ease-in-out infinite alternate;
opacity: 0;
}
@keyframes dv-twinkle { 0% { opacity: .15; } 100% { opacity: 1; } }
/* ββ moon ββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
#dv-moon {
position: absolute; top: 60px; right: 10%; width: 90px; height: 90px;
border-radius: 50%; background: radial-gradient(circle at 35% 35%, #fffbe6 0%, #f5c842 60%, #c9a020 100%);
box-shadow: 0 0 40px 12px rgba(245,200,66,.35), 0 0 80px 24px rgba(245,200,66,.15);
animation: dv-moon-glow 4s ease-in-out infinite alternate;
}
@keyframes dv-moon-glow {
0% { box-shadow: 0 0 40px 12px rgba(245,200,66,.35), 0 0 80px 24px rgba(245,200,66,.15); }
100% { box-shadow: 0 0 55px 18px rgba(245,200,66,.45), 0 0 100px 32px rgba(245,200,66,.2); }
}
/* ββ storybook flip container ββββββββββββββββββββββββββββββββββ */
#dv-storybook-wrap {
perspective: 1200px; display: flex; justify-content: center; align-items: center;
min-height: 340px; margin: 0 auto 1.5rem; max-width: 680px;
}
#dv-storybook {
width: 100%; min-height: 340px; position: relative;
transform-style: preserve-3d;
transition: transform 0.8s cubic-bezier(.4,0,.2,1);
transform-origin: center left;
/* Plays each time Stage 2 becomes visible (display noneβblock restarts it),
so the book "opens" on every reveal. */
animation: dv-book-open .85s cubic-bezier(.2,.7,.2,1) both;
}
@keyframes dv-book-open {
0% { transform: rotateY(-72deg); opacity: 0; }
100% { transform: rotateY(0deg); opacity: 1; }
}
#dv-storybook.dv-flipped { transform: rotateY(180deg); }
#dv-book-front, #dv-book-back {
position: absolute; inset: 0; backface-visibility: hidden;
border-radius: 24px; padding: 2rem 2.2rem;
font-family: 'Lora', Georgia, serif; font-size: 1.05rem; line-height: 1.7;
color: #eee; overflow-y: auto;
background: linear-gradient(135deg, rgba(30,30,70,.85) 0%, rgba(15,15,45,.92) 100%);
border: 1.5px solid rgba(245,200,66,.25);
box-shadow: 0 8px 32px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,255,255,.06);
}
#dv-book-back { transform: rotateY(180deg); }
#dv-storybook h2.dv-story-title {
font-family: 'Pacifico', cursive; font-size: 1.65rem; color: #f5c842;
margin-bottom: 1rem; text-shadow: 0 2px 8px rgba(245,200,66,.25);
}
#dv-storybook .dv-story-text { white-space: pre-wrap; }
/* ββ accent buttons (shared) βββββββββββββββββββββββββββββββββββ */
.dv-btn-accent {
background: #f5c842; color: #1a1a3e; border: none; border-radius: 24px;
padding: .65rem 1.8rem; font-weight: 700; font-size: 1rem; cursor: pointer;
font-family: 'Lora', Georgia, serif; transition: transform .15s, box-shadow .15s;
}
.dv-btn-accent:hover { transform: translateY(-1px); box-shadow: 0 4px 14px rgba(245,200,66,.4); }
.dv-btn-accent:active { transform: translateY(0); }
/* ββ stage headings & helpers ββββββββββββββββββββββββββββββββββ */
.dv-section-title {
font-family: 'Pacifico', cursive; font-size: 1.5rem; color: #f5c842;
text-align: center; margin: .5rem 0 1rem;
}
.dv-note {
font-family: 'Lora', Georgia, serif; font-size: .88rem;
color: rgba(255,255,255,.55); text-align: center; margin-top: .3rem;
}
"""
_STARFIELD_JS = """
(function(){
var root = document.getElementById('dv-stars-root');
if (!root) return;
for (var i = 0; i < 120; i++){
var s = document.createElement('div');
s.className = 'star';
var size = 1.2 + Math.random() * 2.5;
s.style.width = size + 'px';
s.style.height = size + 'px';
s.style.left = Math.random() * 100 + '%';
s.style.top = Math.random() * 100 + '%';
s.style.setProperty('--dur', (1.5 + Math.random() * 3) + 's');
s.style.animationDelay = (Math.random() * 4) + 's';
root.appendChild(s);
}
})();
"""
def starfield_background() -> gr.HTML:
"""Full-viewport animated starfield with a glowing moon."""
return gr.HTML(
value='<div id="dv-stars-root"></div><div id="dv-moon"></div>',
head=f"<style>{_STARFIELD_CSS}</style>",
js_on_load=_STARFIELD_JS,
elem_id="dv-stars-root",
)
def storybook_markup(story: str = "", title: str = "Tonight's Story") -> str:
"""Return the storybook HTML string with *story* and *title* HTML-escaped.
Use this both to build the initial component and to update it after a story
is generated, so the storybook frame/title/escaping are preserved.
"""
import html as _html
safe_title = _html.escape(title)
safe_story = _html.escape(story) if story else "<em>The storybook is waitingβ¦</em>"
return f"""
<div id="dv-storybook-wrap">
<div id="dv-storybook">
<div id="dv-book-front">
<h2 class="dv-story-title">{safe_title}</h2>
<div class="dv-story-text">{safe_story}</div>
</div>
<div id="dv-book-back">
<h2 class="dv-story-title">The End</h2>
<p style="text-align:center;margin-top:2rem;color:#f5c842;font-size:1.2rem;">
Sweet dreams β¨
</p>
</div>
</div>
</div>
"""
def storybook_html(story: str = "", title: str = "Tonight's Story") -> gr.HTML:
"""Render the story inside the 3D storybook flip container."""
return gr.HTML(value=storybook_markup(story, title), elem_id="dv-storybook")
|