Files
Skori/src/components/NavigationMenu.tsx
T
Zed ce1db937f2
Build and Publish Docker Image / build-and-push-image (push) Successful in 1m48s
rework pwa cc
2026-07-11 02:01:08 +02:00

129 lines
5.0 KiB
TypeScript

import { useState, useRef, useEffect } from "react";
import {
Menu,
Home,
History,
Settings,
Users,
BarChart2,
MapPin,
UserCircle,
ChevronRight,
} from "lucide-react";
import { useNavigate } from "react-router-dom";
import { motion, AnimatePresence } from "framer-motion";
import { Button } from "./ui/button";
import { Avatar } from "./ui/avatar";
import { useProfileStore } from "../stores/profileStore";
export function NavigationMenu() {
const [isOpen, setIsOpen] = useState(false);
const navigate = useNavigate();
const menuRef = useRef<HTMLDivElement>(null);
const activeProfile = useProfileStore((s) => s.activeProfile);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
setIsOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
const nav = (path: string) => {
setIsOpen(false);
navigate(path);
};
return (
<div ref={menuRef} className="relative z-50">
<Button
variant="ghost"
size="icon"
onClick={() => setIsOpen(!isOpen)}
className="rounded-full hover:bg-black/10 dark:hover:bg-white/10"
>
<Menu className="w-6 h-6" />
</Button>
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ opacity: 0, scale: 0.95, transformOrigin: "top left" }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{ duration: 0.15 }}
className="absolute top-full left-0 mt-2 w-60 bg-card border shadow-xl rounded-2xl overflow-hidden"
>
<div className="flex flex-col">
<button
onClick={() => nav("/profiles")}
className="flex items-center w-full p-4 hover:bg-secondary text-left transition-colors bg-primary/5"
>
<Avatar
src={activeProfile?.avatar}
name={activeProfile?.name || "?"}
size="md"
className="mr-3"
/>
<div className="flex-1 min-w-0">
<div className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">
Profil actif
</div>
<div className="font-black truncate">
{activeProfile?.name || "—"}
</div>
</div>
<ChevronRight className="w-4 h-4 text-muted-foreground shrink-0" />
</button>
<button
onClick={() => nav("/")}
className="flex items-center w-full p-4 hover:bg-secondary text-left font-medium transition-colors border-t border-border/50"
>
<Home className="w-5 h-5 mr-3 text-primary" /> Accueil
</button>
<button
onClick={() => nav("/history")}
className="flex items-center w-full p-4 hover:bg-secondary text-left font-medium transition-colors border-t border-border/50"
>
<History className="w-5 h-5 mr-3 text-primary" /> Historique
</button>
<button
onClick={() => nav("/players")}
className="flex items-center w-full p-4 hover:bg-secondary text-left font-medium transition-colors border-t border-border/50"
>
<Users className="w-5 h-5 mr-3 text-primary" /> Joueurs
</button>
<button
onClick={() => nav("/locations")}
className="flex items-center w-full p-4 hover:bg-secondary text-left font-medium transition-colors border-t border-border/50"
>
<MapPin className="w-5 h-5 mr-3 text-primary" /> Emplacements
</button>
<button
onClick={() => nav("/stats")}
className="flex items-center w-full p-4 hover:bg-secondary text-left font-medium transition-colors border-t border-border/50"
>
<BarChart2 className="w-5 h-5 mr-3 text-primary" /> Statistiques
</button>
<button
onClick={() => nav("/profiles")}
className="flex items-center w-full p-4 hover:bg-secondary text-left font-medium transition-colors border-t border-border/50"
>
<UserCircle className="w-5 h-5 mr-3 text-primary" /> Profils
</button>
<button
onClick={() => nav("/settings")}
className="flex items-center w-full p-4 hover:bg-secondary text-left font-medium transition-colors border-t border-border/50"
>
<Settings className="w-5 h-5 mr-3 text-primary" /> Paramètres
</button>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}