File size: 4,896 Bytes
a566fb0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
import React, { useState, useEffect } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { createPageUrl } from '@/utils';
import { motion, AnimatePresence } from 'framer-motion';
import { Brain, Home, BookOpen, Cpu, Target, Menu, X, Sparkles } from 'lucide-react';
import { Button } from '@/components/ui/button';
const navItems = [
{ name: 'Home', icon: Home, page: 'Home' },
{ name: 'Lessons', icon: BookOpen, page: 'Lessons' },
{ name: 'Quiz', icon: Target, page: 'Quiz' }
];
export default function Layout({ children, currentPageName }) {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const location = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [location.pathname]);
return (
<div className="min-h-screen bg-slate-900">
{/* Navigation */}
<nav className="fixed top-0 left-0 right-0 z-50 bg-slate-900/80 backdrop-blur-xl border-b border-white/10">
<div className="max-w-6xl mx-auto px-6">
<div className="flex items-center justify-between h-16">
{/* Logo */}
<Link to={createPageUrl('Home')} className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center">
<Brain className="w-6 h-6 text-white" />
</div>
<span className="font-bold text-white text-lg hidden sm:block">Computer Vision Lab</span>
</Link>
{/* Desktop Navigation */}
<div className="hidden md:flex items-center gap-1">
{navItems.map((item) => {
const isActive = currentPageName === item.page;
return (
<Link key={item.page} to={createPageUrl(item.page)}>
<Button
variant="ghost"
className={`relative rounded-xl px-4 ${
isActive
? 'text-white bg-white/10'
: 'text-white/70 hover:text-white hover:bg-white/5'
}`}
>
<item.icon className="w-4 h-4 mr-2" />
{item.name}
{isActive && (
<motion.div
layoutId="activeTab"
className="absolute bottom-0 left-0 right-0 h-0.5 bg-gradient-to-r from-blue-500 to-purple-500"
/>
)}
</Button>
</Link>
);
})}
</div>
{/* Mobile Menu Button */}
<Button
size="icon"
className="md:hidden text-white bg-transparent hover:bg-white/10 border-0"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
>
{mobileMenuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
</Button>
</div>
</div>
{/* Mobile Menu */}
<AnimatePresence>
{mobileMenuOpen && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
className="md:hidden bg-slate-900/95 backdrop-blur-xl border-b border-white/10"
>
<div className="px-6 py-4 space-y-2">
{navItems.map((item) => {
const isActive = currentPageName === item.page;
return (
<Link
key={item.page}
to={createPageUrl(item.page)}
onClick={() => setMobileMenuOpen(false)}
>
<div className={`flex items-center gap-3 p-3 rounded-xl ${
isActive
? 'bg-white/10 text-white'
: 'text-white/70 hover:bg-white/5 hover:text-white'
}`}>
<item.icon className="w-5 h-5" />
<span className="font-medium">{item.name}</span>
</div>
</Link>
);
})}
</div>
</motion.div>
)}
</AnimatePresence>
</nav>
{/* Main Content */}
<main>
{children}
</main>
{/* Footer */}
<footer className="bg-slate-900 border-t border-white/10 py-9 px-6">
<div className="max-w-6xl mx-auto">
<div className="pt-3 text-center text-white/40 text-sm">
<p>© 2026 Computer Vision Lab</p>
</div>
</div>
</footer>
</div>
);
} |