/* @component-map * App — Main container, handles layout and view switching * StarScatter — Decorative animated star background * TopicSelector — Topic pill buttons for poem subject selection * PoemDisplay — Shows generated poem card with copy functionality * PoemHistory — History dot strip for navigating past poems * @end-component-map */ import { StarScatter } from './components/StarScatter.jsx'; import { TopicSelector } from './components/TopicSelector.jsx'; import { PoemDisplay } from './components/PoemDisplay.jsx'; import { PoemHistory } from './components/PoemHistory.jsx'; import { useCallback, useState } from 'react'; import { useCollection, useAI } from '@deplixo/sdk'; function App() { const [selectedTopic, setSelectedTopic] = useState(null); const [currentIndex, setCurrentIndex] = useState(-1); const { items: poems, add } = useCollection('poems', { personal: true }); const { generate, loading } = useAI(); const currentPoem = currentIndex >= 0 && poems[currentIndex] ? poems[currentIndex] : poems[poems.length - 1]; const handleGenerate = useCallback(async () => { if (loading) return; const topicForPrompt = selectedTopic || randomTopic(); const styles = ['haiku', 'free verse', 'sonnet-like', 'limerick', 'ode']; const style = styles[Math.floor(Math.random() * styles.length)]; try { const result = await generate({ system: `You are a poetic bard of the Star Wars galaxy. Write short, evocative poems about Star Wars. Your poems should feel cinematic and emotional, using vivid imagery, metaphor, and the specific language of the Star Wars universe. Return ONLY the poem text — no title, no explanation, no preamble. Just pure verse. Keep it between 6–14 lines. Make it beautiful, surprising, and memorable.`, user: `Write a ${style} poem about: ${topicForPrompt}`, }); const poem = result.trim(); await add({ topic: topicForPrompt, text: poem, createdAt: Date.now() }); setCurrentIndex(-1); } catch (e) { /* generation failed silently */ } }, [loading, selectedTopic, generate, add]); const handleSelectHistoryItem = useCallback((idx) => { setCurrentIndex(idx); }, []); return (