ui: unified frosted glass frame around Live2D stage
Single bg-white/40 backdrop-blur-xl container as CSS grid. Sidebars, top bar, bottom bar are grid cells sharing one rounded frame. Center cell transparent for Live2D. Thin border-white/20 dividers.
This commit is contained in:
+42
-43
@@ -115,30 +115,30 @@ export default function App() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Particles type={currentScene.particles ?? 'none'} />
|
<Particles type={currentScene.particles ?? 'none'} />
|
||||||
<div className="relative z-20 h-full flex flex-col">
|
<div className="relative z-20 h-full p-4">
|
||||||
{/* ── Top bar: scene selector + clock ── */}
|
<div className="h-full bg-white/40 backdrop-blur-xl rounded-2xl grid grid-rows-[auto_1fr_auto] grid-cols-[288px_1fr_256px] overflow-hidden">
|
||||||
<div className="flex items-center justify-between px-5 py-3 shrink-0 bg-white/40 backdrop-blur-xl rounded-2xl mx-4">
|
|
||||||
<div className="flex items-center gap-1">
|
|
||||||
{SCENES.map((s) => (
|
|
||||||
<button key={s.id} onClick={() => handleSceneChange(s.id)}
|
|
||||||
className={'w-8 h-8 rounded-full flex items-center justify-center text-sm transition-all '
|
|
||||||
+ (s.id === currentSceneId ? 'bg-white/60 shadow-sm scale-110' : 'hover:bg-white/30')}>
|
|
||||||
{s.icon}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<span className="text-kira-plum/30 text-xs font-medium">
|
|
||||||
{new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} · {new Date().toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })}
|
|
||||||
</span>
|
|
||||||
<span className="text-xs text-kira-plum/20">🌸 body double</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* ── Main three-column body ── */}
|
{/* ── Top bar: scene selector + clock ── */}
|
||||||
<div className="flex-1 flex min-h-0 px-4 gap-4">
|
<div className="col-span-3 flex items-center justify-between px-5 py-3 shrink-0">
|
||||||
{/* LEFT: Focus Timer + Chat + Input */}
|
<div className="flex items-center gap-1">
|
||||||
<div className="w-72 shrink-0 flex flex-col gap-3 bg-white/40 backdrop-blur-xl rounded-2xl p-3">
|
{SCENES.map((s) => (
|
||||||
|
<button key={s.id} onClick={() => handleSceneChange(s.id)}
|
||||||
|
className={'w-8 h-8 rounded-full flex items-center justify-center text-sm transition-all '
|
||||||
|
+ (s.id === currentSceneId ? 'bg-white/60 shadow-sm scale-110' : 'hover:bg-white/30')}>
|
||||||
|
{s.icon}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<span className="text-kira-plum/30 text-xs font-medium">
|
||||||
|
{new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} · {new Date().toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })}
|
||||||
|
</span>
|
||||||
|
<span className="text-xs text-kira-plum/20">🌸 body double</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── Left sidebar ── */}
|
||||||
|
<div className="flex flex-col gap-3 p-3 overflow-y-auto border-r border-white/20">
|
||||||
<div className="shrink-0">
|
<div className="shrink-0">
|
||||||
<Timer />
|
<Timer />
|
||||||
</div>
|
</div>
|
||||||
@@ -148,8 +148,8 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* CENTER: Avatar UI overlay (Live2D renders on the background stage) */}
|
{/* ── Center: transparent for Live2D ── */}
|
||||||
<div className="flex-1 min-w-0 rounded-2xl bg-transparent overflow-hidden">
|
<div className="min-w-0 overflow-hidden">
|
||||||
<KiraAvatar
|
<KiraAvatar
|
||||||
isSpeaking={isKiraSpeaking}
|
isSpeaking={isKiraSpeaking}
|
||||||
isListening={isRecording}
|
isListening={isRecording}
|
||||||
@@ -161,32 +161,31 @@ export default function App() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* RIGHT: Ambient + Companions */}
|
{/* ── Right sidebar ── */}
|
||||||
<div className="w-64 shrink-0 flex flex-col bg-white/40 backdrop-blur-xl rounded-2xl p-3">
|
<div className="flex flex-col p-3 overflow-y-auto border-l border-white/20">
|
||||||
<div className="flex-1 flex flex-col gap-3 overflow-y-auto">
|
<div className="flex-1 flex flex-col gap-3 overflow-y-auto">
|
||||||
<MusicPlayer />
|
<MusicPlayer />
|
||||||
<WhiteNoise />
|
<WhiteNoise />
|
||||||
<Wardrobe onOutfitChange={handleOutfitChange} onAccessoryChange={handleAccessoryChange} />
|
<Wardrobe onOutfitChange={handleOutfitChange} onAccessoryChange={handleAccessoryChange} />
|
||||||
</div>
|
</div>
|
||||||
<div className="shrink-0 pt-2">
|
</div>
|
||||||
|
|
||||||
|
{/* ── Bottom status bar ── */}
|
||||||
|
<div className="col-span-3 shrink-0 px-5 py-2 flex items-center justify-between text-[11px] text-kira-plum/30 border-t border-white/20">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className={`w-1.5 h-1.5 rounded-full ${
|
||||||
|
isRecording ? 'bg-red-400 animate-pulse'
|
||||||
|
: isKiraSpeaking ? 'bg-kira-pink animate-pulse'
|
||||||
|
: 'bg-kira-mint'
|
||||||
|
}`} />
|
||||||
|
{isRecording ? 'listening...' : isKiraSpeaking ? 'kira speaking...' : `kira's here for you, ${userName}`}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className={isConnected ? '' : 'text-red-300'}>{isConnected ? '' : 'reconnecting...'}</span>
|
||||||
|
<span>💖</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* ── Bottom status bar ── */}
|
|
||||||
<div className="shrink-0 px-5 py-2 flex items-center justify-between text-[11px] text-kira-plum/30 bg-white/40 backdrop-blur-xl rounded-2xl mx-4">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span className={`w-1.5 h-1.5 rounded-full ${
|
|
||||||
isRecording ? 'bg-red-400 animate-pulse'
|
|
||||||
: isKiraSpeaking ? 'bg-kira-pink animate-pulse'
|
|
||||||
: 'bg-kira-mint'
|
|
||||||
}`} />
|
|
||||||
{isRecording ? 'listening...' : isKiraSpeaking ? 'kira speaking...' : `kira's here for you, ${userName}`}
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span className={isConnected ? '' : 'text-red-300'}>{isConnected ? '' : 'reconnecting...'}</span>
|
|
||||||
<span>💖</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user