import React, { useEffect, useMemo, useRef, useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { BookOpen, ChevronLeft, ChevronRight, Moon, Stars, Sparkles, Volume2, Pause, Play, User, Wand2, Music2, Image as ImageIcon, Castle, Trees, Crown, Heart, Bird, Gem, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Progress } from "@/components/ui/progress"; import { Slider } from "@/components/ui/slider"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; const PAGE_COUNT = 100; const CHAPTERS = 10; const kingdoms = [ "Bosque da Lua Dourada", "Vale das Névoas Azuis", "Castelo das Estrelas", "Jardim das Fadas de Cristal", "Montanhas do Coração Antigo", "Rio de Prata Cantante", "Floresta dos Segredos Suaves", "Ilha do Sol Adormecido", "Campos da Aurora", "Torre do Vento Encantado", ]; const guardians = [ "uma loba celestial", "um cervo de vidro", "uma coruja dourada", "um dragão gentil", "uma raposa luminosa", "um cavaleiro de musgo", "uma sereia dos lagos", "um gato mágico", "uma princesa viajante", "um relojoeiro encantado", ]; const treasures = [ "a chave do amanhecer", "o rubi da coragem", "a rosa eterna", "o mapa dos desejos", "a ampulheta do destino", "o colar das marés", "a lanterna dos sonhos", "o espelho da verdade", "o sino de prata", "a pena das memórias", ]; const moods = [ "misteriosa", "acolhedora", "brilhante", "poética", "encantadora", "suave", "heróica", "sonhadora", "radiante", "mágica", ]; const illustrations = [ { icon: Castle, label: "Castelo encantado" }, { icon: Trees, label: "Floresta mágica" }, { icon: Crown, label: "Reino dourado" }, { icon: Heart, label: "Coração do destino" }, { icon: Bird, label: "Mensageira celestial" }, { icon: Gem, label: "Tesouro antigo" }, ]; const chapterThemes = [ "O Chamado da Primeira Estrela", "A Floresta dos Sussurros", "O Portal das Rosas", "As Torres do Reino Antigo", "O Segredo do Lago de Cristal", "A Coroa da Aurora", "A Travessia do Vento", "Os Guardiões do Coração", "A Última Chave Encantada", "O Reino que Aprendeu a Sonhar", ]; function makePages() { return Array.from({ length: PAGE_COUNT }, (_, i) => { const chapter = Math.floor(i / 10) + 1; const kingdom = kingdoms[i % kingdoms.length]; const guardian = guardians[(i * 3) % guardians.length]; const treasure = treasures[(i * 7) % treasures.length]; const mood = moods[(i * 5) % moods.length]; const chapterTheme = chapterThemes[chapter - 1]; const illustration = illustrations[i % illustrations.length]; const title = i === 0 ? "Prólogo: A Primeira Luz" : i === PAGE_COUNT - 1 ? "Epílogo: O Reino que Aprendeu a Sonhar" : `Capítulo ${chapter} · Página ${i + 1}`; const text = i === 0 ? `Era uma vez, além das nuvens cor de mel, um reino chamado ${kingdom}. Em cada janela brilhava uma esperança antiga, e em cada caminho de pedra havia o eco de um novo destino. Numa noite especialmente ${mood}, uma pequena centelha desceu do céu e escolheu o coração de quem abrisse este livro.` : i === PAGE_COUNT - 1 ? `Quando a última estrela tocou o horizonte, o povo de ${kingdom} entendeu que a verdadeira magia nunca esteve apenas em coroas, torres ou feitiços. Ela morava em gestos de bondade, em promessas cumpridas e na coragem de continuar. E assim, o conto terminou do jeito mais bonito: com espaço para um novo começo.` : `No coração de ${kingdom}, ${guardian} guardava ${treasure}. A trilha daquela página era ${mood}, feita de brilhos, música distante e escolhas delicadas. A cada passo, a personagem principal aprendia que a magia mais forte nasce quando o medo encontra coragem, quando a dúvida encontra ternura e quando o impossível finalmente decide florescer.`; const choiceA = i % 3 === 0 ? "Seguir a luz da lanterna encantada" : "Conversar com o guardião do caminho"; const choiceB = i % 2 === 0 ? "Abrir o portal escondido entre as flores" : "Esperar a canção do vento revelar um segredo"; const accent = [ "from-rose-200 via-amber-100 to-fuchsia-200", "from-sky-200 via-cyan-100 to-indigo-200", "from-violet-200 via-purple-100 to-pink-200", "from-emerald-200 via-lime-100 to-teal-200", "from-yellow-200 via-orange-100 to-rose-200", ][i % 5]; return { id: i + 1, chapter, chapterTheme, title, text, kingdom, guardian, treasure, choiceA, choiceB, accent, quote: `"Toda página guarda um milagre para quem continua lendo."`, illustration, }; }); } function MagicalIllustration({ icon: Icon, label, accent }) { return (
Ilustração do capítulo
{label}

Arte simbólica para representar o clima visual desta parte do conto, com brilho mágico, relevo suave e atmosfera cinematográfica.

); } export default function LivroContoDeFadasLuxuoso() { const pages = useMemo(() => makePages(), []); const [page, setPage] = useState(0); const [isPlaying, setIsPlaying] = useState(false); const [voiceMode, setVoiceMode] = useState("feminina"); const [rate, setRate] = useState([0.95]); const [pitch, setPitch] = useState([1.08]); const [autoNarrate, setAutoNarrate] = useState(false); const [voices, setVoices] = useState([]); const [bookOpen, setBookOpen] = useState(false); const [musicOn, setMusicOn] = useState(false); const [musicVolume, setMusicVolume] = useState([22]); const utteranceRef = useRef(null); const audioContextRef = useRef(null); const bgNodesRef = useRef([]); const current = pages[page]; const progress = ((page + 1) / PAGE_COUNT) * 100; const chapterProgress = (((page % 10) + 1) / 10) * 100; useEffect(() => { const loadVoices = () => { const list = window.speechSynthesis?.getVoices?.() || []; setVoices(list); }; loadVoices(); if (window.speechSynthesis) { window.speechSynthesis.onvoiceschanged = loadVoices; } return () => { if (window.speechSynthesis) window.speechSynthesis.cancel(); if (audioContextRef.current) audioContextRef.current.close().catch(() => {}); }; }, []); useEffect(() => { bgNodesRef.current.forEach((node) => { if (node?.gain) { node.gain.gain.value = musicOn ? musicVolume[0] / 100 / 8 : 0; } }); }, [musicOn, musicVolume]); const initMusic = async () => { if (audioContextRef.current) return; const AudioCtx = window.AudioContext || window.webkitAudioContext; if (!AudioCtx) return; const ctx = new AudioCtx(); audioContextRef.current = ctx; const createOsc = (type, frequency, gainValue) => { const osc = ctx.createOscillator(); const gain = ctx.createGain(); osc.type = type; osc.frequency.value = frequency; gain.gain.value = musicOn ? gainValue : 0; osc.connect(gain); gain.connect(ctx.destination); osc.start(); return { osc, gain }; }; bgNodesRef.current = [ createOsc("sine", 261.63, musicVolume[0] / 100 / 10), createOsc("triangle", 329.63, musicVolume[0] / 100 / 16), createOsc("sine", 392.0, musicVolume[0] / 100 / 20), ]; }; const toggleMusic = async () => { await initMusic(); if (audioContextRef.current?.state === "suspended") { await audioContextRef.current.resume(); } setMusicOn((prev) => !prev); }; const preferredVoice = useMemo(() => { if (!voices.length) return null; const femaleHints = ["female", "woman", "mulher", "feminina", "luciana", "maria", "helena", "samantha", "victoria", "google português do brasil"]; const maleHints = ["male", "man", "homem", "masculina", "daniel", "felipe", "antonio", "jorge"]; const hints = voiceMode === "feminina" ? femaleHints : maleHints; const exact = voices.find((v) => hints.some((hint) => `${v.name} ${v.lang}`.toLowerCase().includes(hint))); if (exact) return exact; const portuguese = voices.find((v) => v.lang?.toLowerCase().includes("pt-br") || v.lang?.toLowerCase().includes("pt")); return portuguese || voices[0]; }, [voices, voiceMode]); const narrationText = useMemo(() => { return `${current.title}. ${current.text} Escolha um caminho. Opção 1: ${current.choiceA}. Opção 2: ${current.choiceB}.`; }, [current]); const speak = () => { if (!window.speechSynthesis) return; window.speechSynthesis.cancel(); const utterance = new SpeechSynthesisUtterance(narrationText); if (preferredVoice) utterance.voice = preferredVoice; utterance.lang = preferredVoice?.lang || "pt-BR"; utterance.rate = rate[0]; utterance.pitch = pitch[0]; utterance.onend = () => setIsPlaying(false); utterance.onerror = () => setIsPlaying(false); utteranceRef.current = utterance; window.speechSynthesis.speak(utterance); setIsPlaying(true); }; const stopSpeaking = () => { if (!window.speechSynthesis) return; window.speechSynthesis.cancel(); setIsPlaying(false); }; const nextPage = () => setPage((p) => Math.min(PAGE_COUNT - 1, p + 1)); const prevPage = () => setPage((p) => Math.max(0, p - 1)); const jumpToChoice = (choice) => { const offset = choice === "A" ? 2 : 3; setPage((p) => Math.min(PAGE_COUNT - 1, p + offset)); }; useEffect(() => { if (autoNarrate && bookOpen) { const t = setTimeout(() => speak(), 450); return () => clearTimeout(t); } stopSpeaking(); }, [page, autoNarrate, preferredVoice, bookOpen]); const currentIllustrationIcon = current.illustration.icon; return (
{Array.from({ length: 42 }).map((_, i) => ( ))}
{!bookOpen ? (
Edição Luxuosa

O Grande Livro dos Contos Encantados

Uma experiência digital luxuosa com capa animada, trilha sonora suave, ilustrações por capítulo, narração selecionável e efeito visual realista de páginas sendo reveladas como um verdadeiro tomo mágico.

{[ "Capa cinematográfica", "Virada de páginas", "Trilha sonora suave", "Ilustrações mágicas", ].map((item) => (
{item}
))}
) : (

Livro encantado

Versão Luxuosa Interativa

Experiência premium com narração, ambientação sonora, ilustrações de capítulo e navegação cinematográfica entre as páginas do conto.

Progresso do livro {page + 1} / {PAGE_COUNT}
Capítulo {current.chapter} {current.chapterTheme}
Velocidade da voz: {rate[0].toFixed(2)}
Tom da voz: {pitch[0].toFixed(2)}
Narração automática
Lê cada página ao abrir
Trilha sonora
Ambiente musical suave em tempo real
Volume: {musicVolume[0]}%
Destaques desta edição
  • • Capa animada de abertura
  • • Revelação cinematográfica das páginas
  • • Trilha sonora ambiente
  • • Ilustrações simbólicas por capítulo
Página {current.id}
{current.chapterTheme}

{current.title}

{current.kingdom} {current.guardian} {current.treasure}

{current.text}

{current.quote}
Ilustração e escolhas
Prévia da narração

{narrationText}

Vire as páginas e descubra um novo pedaço do conto.
)}
); }