Upload files to "/"

This commit is contained in:
2026-09-14 23:34:36 +08:00
parent a26bbecbd1
commit 1e893db246
5 changed files with 631 additions and 0 deletions
+193
View File
@@ -0,0 +1,193 @@
import { useState, useEffect } from 'react';
import { Navbar, NavTab, AgeGroup } from './components/Navbar';
import { StoryReader } from './components/StoryReader';
import { StoryboardView } from './components/StoryboardView';
import { ArtDirectionView } from './components/ArtDirectionView';
import { CharacterVault } from './components/CharacterVault';
import { AdaptabilityView } from './components/AdaptabilityView';
import { FormatStrategyView } from './components/FormatStrategyView';
import { ActivityCorner } from './components/ActivityCorner';
import { PitchDeckModal } from './components/PitchDeckModal';
import { BOOK_METADATA } from './data/storyData';
import { soundManager } from './utils/audio';
import { Heart } from 'lucide-react';
export function App() {
const [activeTab, setActiveTab] = useState<NavTab>('reader');
const [ageGroup, setAgeGroup] = useState<AgeGroup>('pictureBook');
const [isBedtimeMode, setIsBedtimeMode] = useState<boolean>(false);
const [soundEnabled, setSoundEnabled] = useState<boolean>(true);
const [isPitchDeckOpen, setIsPitchDeckOpen] = useState<boolean>(false);
const [storyboardSceneId, setStoryboardSceneId] = useState<number>(1);
// Sync global .dark class on <html> with Bedtime Mode so all dark: variants apply
useEffect(() => {
const root = document.documentElement;
if (isBedtimeMode) {
root.classList.add('dark');
} else {
root.classList.remove('dark');
}
}, [isBedtimeMode]);
const handleExploreStoryboard = (sceneId: number) => {
soundManager.playPop();
setStoryboardSceneId(sceneId);
setActiveTab('storyboard');
};
return (
<div className={`min-h-screen flex flex-col font-reading transition-colors duration-500 ${
isBedtimeMode
? 'bg-slate-950 text-indigo-50'
: 'bg-[#faf6ee] text-stone-900'
}`}>
{/* Top Navigation */}
<Navbar
activeTab={activeTab}
setActiveTab={setActiveTab}
ageGroup={ageGroup}
setAgeGroup={setAgeGroup}
isBedtimeMode={isBedtimeMode}
setIsBedtimeMode={setIsBedtimeMode}
soundEnabled={soundEnabled}
setSoundEnabled={setSoundEnabled}
onOpenPitchDeck={() => setIsPitchDeckOpen(true)}
/>
{/* Main View Router */}
<main className="flex-1">
{activeTab === 'reader' && (
<StoryReader
ageGroup={ageGroup}
setAgeGroup={setAgeGroup}
isBedtimeMode={isBedtimeMode}
soundEnabled={soundEnabled}
onExploreStoryboard={handleExploreStoryboard}
/>
)}
{activeTab === 'storyboard' && (
<StoryboardView
isBedtimeMode={isBedtimeMode}
selectedSceneId={storyboardSceneId}
/>
)}
{activeTab === 'art' && (
<ArtDirectionView
isBedtimeMode={isBedtimeMode}
/>
)}
{activeTab === 'characters' && (
<CharacterVault
isBedtimeMode={isBedtimeMode}
/>
)}
{activeTab === 'adaptability' && (
<AdaptabilityView
isBedtimeMode={isBedtimeMode}
/>
)}
{activeTab === 'publishing' && (
<FormatStrategyView
isBedtimeMode={isBedtimeMode}
onOpenPitchDeck={() => setIsPitchDeckOpen(true)}
/>
)}
{activeTab === 'activities' && (
<ActivityCorner
isBedtimeMode={isBedtimeMode}
/>
)}
</main>
{/* Footer */}
<footer className={`border-t py-8 px-4 sm:px-6 lg:px-8 transition-colors ${
isBedtimeMode
? 'bg-indigo-950/70 border-indigo-900 text-indigo-200'
: 'bg-[#f7f2e7] border-amber-200/80 text-stone-700'
}`}>
<div className="max-w-7xl mx-auto flex flex-col sm:flex-row items-center justify-between gap-4 text-xs">
<div className="flex items-center gap-2">
<span className="text-xl">🦔</span>
<div>
<p className="font-heading font-bold text-sm text-stone-900 dark:text-white">
{BOOK_METADATA.title}
</p>
<p className="text-[11px] font-medium text-stone-600 dark:text-indigo-300">
Children's Storybook Concept & Interactive Story Experience
</p>
</div>
</div>
<div className="flex flex-wrap items-center justify-center gap-4 text-xs font-semibold">
<button
onClick={() => { soundManager.playPop(); setActiveTab('reader'); }}
className="hover:text-amber-600 transition-colors"
>
Story Reader
</button>
<button
onClick={() => { soundManager.playPop(); setActiveTab('storyboard'); }}
className="hover:text-amber-600 transition-colors"
>
Storyboard
</button>
<button
onClick={() => { soundManager.playPop(); setActiveTab('art'); }}
className="hover:text-amber-600 transition-colors"
>
Art Direction
</button>
<button
onClick={() => { soundManager.playPop(); setActiveTab('characters'); }}
className="hover:text-amber-600 transition-colors"
>
Character Vault
</button>
<button
onClick={() => { soundManager.playPop(); setActiveTab('adaptability'); }}
className="hover:text-amber-600 transition-colors"
>
Age Matrix
</button>
<button
onClick={() => { soundManager.playPop(); setActiveTab('publishing'); }}
className="hover:text-amber-600 transition-colors"
>
Publishing Specs
</button>
<button
onClick={() => { soundManager.playPop(); setIsPitchDeckOpen(true); }}
className="text-amber-700 dark:text-amber-400 font-bold hover:underline"
>
Editorial Pitch Deck
</button>
</div>
<div className="flex items-center gap-1.5 text-[11px] font-semibold text-stone-700 dark:text-indigo-200">
<span>Crafted with</span>
<Heart className="w-3.5 h-3.5 text-rose-500 fill-rose-500" />
<span>by</span>
<span className="font-heading font-bold text-stone-900 dark:text-white tracking-wide">aimirah</span>
<span className="text-stone-500 dark:text-indigo-400">|</span>
<span className="font-heading font-bold text-amber-800 dark:text-amber-300 tracking-wide">mi4inc</span>
</div>
</div>
</footer>
{/* Editorial Pitch Deck Modal */}
<PitchDeckModal
isOpen={isPitchDeckOpen}
onClose={() => setIsPitchDeckOpen(false)}
/>
</div>
);
}
export default App;