// ========================================================================== // LandingHome — Liquid Glass zero-state. // // Renders when a thread has 0 messages AND the canvas is hidden. // Voice: a translucent studio panel floating over the iridescent stage. // Greeting period word ("night", "morning") picks up the iris gradient as // a wow-moment. Composer + starter tiles are glass surfaces with shimmer. // ========================================================================== function LandingHome() { const { me, threads, sendMessage, uploadFiles, currentThread, route, navigate, streaming } = useStore(); const [value, setValue] = React.useState(''); const fileInputRef = React.useRef(null); const disabled = !route.threadId || streaming.active; const hour = new Date().getHours(); const period = hour < 5 ? 'night' : hour < 12 ? 'morning' : hour < 17 ? 'afternoon' : hour < 22 ? 'evening' : 'night'; const firstName = (me && me.name) ? me.name.split(' ')[0] : 'there'; const send = () => { const v = value.trim(); if (!v) return; setValue(''); sendMessage(v); }; const onFiles = (files) => { const arr = Array.from(files); if (arr.length) uploadFiles(arr); }; const starters = [ { kicker: 'Brame', label: 'Dry January push', prompt: 'Launch a Dry January push for BRAME. 3 concepts, Meta + TikTok, approved claims only.' }, { kicker: 'Craft Heritage', label: 'Post-launch readout', prompt: 'Readout of last month’s Craft Heritage launch. Which creatives won, which fatigued, what to double down on.' }, { kicker: 'Q2 panel', label: 'Refresh', prompt: 'Refresh the consumer panel for Q2 — tilt toward occasion-led drinkers, keep the current skews.' }, { kicker: 'LinkedIn', label: 'Creator brief', prompt: 'Write a 1-page creator brief for a LinkedIn-native founder story for BRAME.' }, { kicker: 'Low-cal RTD', label: 'Naming sprint', prompt: 'Run a naming sprint for a low-calorie RTD. 15 candidates, 3 territories, availability checked.' }, ]; const recentThreads = (threads || []).filter(t => t.id !== currentThread.id).slice(0, 6); const brands = [ { id: 'b_brame', name: 'BRAME', kicker: 'Botanical aperitif · 3 SKU' }, { id: 'b_craft', name: 'Craft Heritage', kicker: 'Aged spirits · Q3 launch' }, { id: 'b_loop', name: 'Loop Foods', kicker: 'Plant-forward · house brand' }, { id: 'b_veldt', name: 'Veldt', kicker: 'Single-origin · on-trade' }, ]; const subline = period === 'morning' ? 'What are we launching today?' : period === 'afternoon' ? 'Pick up where you left off — or start something new.' : period === 'evening' ? 'A quiet hour for the big thinking.' : 'Burning the late shift — what are we cracking?'; const today = new Date(); const folio = `Vol. ${String(today.getFullYear()).slice(-2)}.${String(today.getMonth() + 1).padStart(2, '0')} · No. ${String(today.getDate()).padStart(2, '0')}`; const dateLine = today.toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' }); return (
{/* ── Folio bar ─────────────────────────────────────────────────── */}
{folio}
{dateLine}
{/* ── Hero: greeting + glass composer + starter tiles ──────────── */}
Good {period}, {firstName}.
{subline}
{/* Composer — glass desk, iridescent send pill */} { onFiles(e.target.files); e.target.value = ''; }} />
{ e.preventDefault(); }} onDrop={(e) => { e.preventDefault(); onFiles(e.dataTransfer.files); }} className="glass-strong" style={{ width: '100%', borderRadius: 'var(--radius-lg)', padding: '20px 24px 18px', display: 'flex', flexDirection: 'column', gap: 12, }}>
Brief desk Open