Files
Pip---the-Whispering-Cloud/Navbar.tsx
T
2026-09-14 23:35:23 +08:00

229 lines
9.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React from 'react';
import {
BookOpen,
Film,
Palette,
Users,
Sparkles,
Printer,
Volume2,
VolumeX,
Moon,
Sun,
Layers,
BookMarked
} from 'lucide-react';
import { soundManager } from '../utils/audio';
export type NavTab =
| 'reader'
| 'storyboard'
| 'art'
| 'characters'
| 'adaptability'
| 'publishing'
| 'activities';
export type AgeGroup = 'toddler' | 'pictureBook' | 'earlyReader';
interface NavbarProps {
activeTab: NavTab;
setActiveTab: (tab: NavTab) => void;
ageGroup: AgeGroup;
setAgeGroup: (age: AgeGroup) => void;
isBedtimeMode: boolean;
setIsBedtimeMode: (val: boolean) => void;
soundEnabled: boolean;
setSoundEnabled: (val: boolean) => void;
onOpenPitchDeck: () => void;
}
export const Navbar: React.FC<NavbarProps> = ({
activeTab,
setActiveTab,
ageGroup,
setAgeGroup,
isBedtimeMode,
setIsBedtimeMode,
soundEnabled,
setSoundEnabled,
onOpenPitchDeck,
}) => {
const tabs = [
{ id: 'reader' as NavTab, label: 'Story Reader', icon: BookOpen, badge: 'Live Book' },
{ id: 'storyboard' as NavTab, label: 'Storyboard', icon: Film, badge: '5 Scenes' },
{ id: 'art' as NavTab, label: 'Art Direction', icon: Palette, badge: 'Palette & Style' },
{ id: 'characters' as NavTab, label: 'Characters', icon: Users, badge: 'Cast' },
{ id: 'adaptability' as NavTab, label: 'Age Editions', icon: Layers, badge: '3 Ages' },
{ id: 'publishing' as NavTab, label: 'Format & Pitch', icon: BookMarked, badge: 'Specs' },
{ id: 'activities' as NavTab, label: 'Activity Corner', icon: Sparkles, badge: 'Creative' },
];
const handleTabClick = (tabId: NavTab) => {
soundManager.playPop();
setActiveTab(tabId);
};
const handleSoundToggle = () => {
const newState = !soundEnabled;
setSoundEnabled(newState);
soundManager.enabled = newState;
if (newState) soundManager.playChime();
};
const handleBedtimeToggle = () => {
soundManager.playHarp();
setIsBedtimeMode(!isBedtimeMode);
};
return (
<header className={`sticky top-0 z-50 border-b transition-colors duration-300 backdrop-blur-md ${
isBedtimeMode
? 'bg-indigo-950/90 border-indigo-800 text-indigo-100 shadow-lg shadow-indigo-950/40'
: 'bg-[#fffdfa]/95 border-amber-200/70 text-amber-950 shadow-sm'
}`}>
{/* Top Banner with Brand and Controls */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-2.5 flex flex-wrap items-center justify-between gap-3">
{/* Brand */}
<div
onClick={() => handleTabClick('reader')}
className="flex items-center gap-2.5 cursor-pointer group"
>
<div className="w-10 h-10 rounded-2xl bg-gradient-to-tr from-amber-400 via-rose-300 to-sky-300 flex items-center justify-center text-xl shadow-md group-hover:scale-105 transition-transform">
🦔
</div>
<div>
<div className="flex items-center gap-2">
<span className="font-heading font-bold text-lg sm:text-xl tracking-tight leading-none text-amber-900 dark:text-amber-100 group-hover:text-amber-600 transition-colors">
Pip & the Whispering Cloud
</span>
<span className="hidden md:inline-flex text-[11px] font-semibold px-2 py-0.5 rounded-full bg-amber-100 text-amber-800 border border-amber-300/60">
Storybook Studio
</span>
</div>
<p className="text-xs text-amber-800/70 dark:text-indigo-300">
Heartwarming Children's Story & Concept Architecture
</p>
</div>
</div>
{/* Global Toolbar Controls */}
<div className="flex items-center gap-2 flex-wrap">
{/* Age Adaptability Selector */}
<div className="flex items-center bg-amber-100/70 dark:bg-indigo-900/80 p-1 rounded-xl border border-amber-200/80 dark:border-indigo-700 text-xs font-semibold">
<span className="px-2 text-amber-800/80 dark:text-indigo-300 hidden sm:inline">Edition:</span>
<button
onClick={() => { soundManager.playPop(); setAgeGroup('toddler'); }}
className={`px-2.5 py-1 rounded-lg transition-all ${
ageGroup === 'toddler'
? 'bg-amber-500 text-white shadow-sm font-bold'
: 'text-amber-900 dark:text-indigo-200 hover:bg-amber-200/50 dark:hover:bg-indigo-800'
}`}
title="Ages 1-3: Sensory, Onomatopoeia & Touch"
>
Toddler (1–3)
</button>
<button
onClick={() => { soundManager.playPop(); setAgeGroup('pictureBook'); }}
className={`px-2.5 py-1 rounded-lg transition-all ${
ageGroup === 'pictureBook'
? 'bg-amber-500 text-white shadow-sm font-bold'
: 'text-amber-900 dark:text-indigo-200 hover:bg-amber-200/50 dark:hover:bg-indigo-800'
}`}
title="Ages 4-7: Lyrical Picture Book & Read-Aloud"
>
Picture Book (4–7)
</button>
<button
onClick={() => { soundManager.playPop(); setAgeGroup('earlyReader'); }}
className={`px-2.5 py-1 rounded-lg transition-all ${
ageGroup === 'earlyReader'
? 'bg-amber-500 text-white shadow-sm font-bold'
: 'text-amber-900 dark:text-indigo-200 hover:bg-amber-200/50 dark:hover:bg-indigo-800'
}`}
title="Ages 7-9: Illustrated Chapters & Vocabulary"
>
Early Reader (7–9)
</button>
</div>
{/* Bedtime / Day Toggle */}
<button
onClick={handleBedtimeToggle}
className={`p-2 rounded-xl border transition-all flex items-center gap-1.5 text-xs font-medium ${
isBedtimeMode
? 'bg-indigo-900 border-indigo-700 text-amber-300 shadow-inner'
: 'bg-amber-50 border-amber-200 text-amber-800 hover:bg-amber-100'
}`}
title={isBedtimeMode ? "Switch to Daytime Mode" : "Switch to Bedtime Lullaby Mode"}
>
{isBedtimeMode ? <Moon className="w-4 h-4 fill-amber-300" /> : <Sun className="w-4 h-4 text-amber-500" />}
<span className="hidden md:inline">{isBedtimeMode ? 'Bedtime Mode' : 'Day Mode'}</span>
</button>
{/* Sound FX Toggle */}
<button
onClick={handleSoundToggle}
className={`p-2 rounded-xl border transition-all ${
soundEnabled
? 'bg-emerald-50 border-emerald-200 text-emerald-700 dark:bg-emerald-950 dark:border-emerald-700 dark:text-emerald-300'
: 'bg-stone-100 border-stone-200 text-stone-400 dark:bg-stone-900 dark:border-stone-800'
}`}
title={soundEnabled ? "Mute Sound Effects" : "Enable Sound Effects"}
>
{soundEnabled ? <Volume2 className="w-4 h-4" /> : <VolumeX className="w-4 h-4" />}
</button>
{/* Pitch Deck / Presentation Button */}
<button
onClick={() => { soundManager.playHarp(); onOpenPitchDeck(); }}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-xl bg-gradient-to-r from-amber-600 to-rose-600 hover:from-amber-700 hover:to-rose-700 text-white font-medium text-xs shadow-sm hover:shadow transition-all"
>
<Printer className="w-3.5 h-3.5" />
<span className="hidden sm:inline">Pitch Deck</span>
</button>
</div>
</div>
{/* Navigation Sub-Tabs */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 overflow-x-auto scrollbar-none">
<nav className="flex space-x-1 sm:space-x-2 py-1.5 min-w-max">
{tabs.map((tab) => {
const Icon = tab.icon;
const isActive = activeTab === tab.id;
return (
<button
key={tab.id}
onClick={() => handleTabClick(tab.id)}
className={`flex items-center gap-2 px-3.5 py-1.5 rounded-xl text-xs sm:text-sm font-semibold transition-all ${
isActive
? isBedtimeMode
? 'bg-indigo-800 text-amber-200 shadow-sm border border-indigo-600'
: 'bg-amber-500 text-white shadow-sm border border-amber-600/30'
: isBedtimeMode
? 'text-indigo-200 hover:bg-indigo-900/60 hover:text-white'
: 'text-amber-900/80 hover:bg-amber-100/70 hover:text-amber-950'
}`}
>
<Icon className={`w-4 h-4 ${isActive ? 'scale-110' : ''}`} />
<span>{tab.label}</span>
{tab.badge && (
<span className={`text-[10px] px-1.5 py-0.2 rounded-full font-bold ${
isActive
? 'bg-white/20 text-white'
: isBedtimeMode
? 'bg-indigo-900 text-indigo-300'
: 'bg-amber-200/60 text-amber-800'
}`}>
{tab.badge}
</span>
)}
</button>
);
})}
</nav>
</div>
</header>
);
};