DistractIQ / src /components /AppHeader.tsx
github-actions
Initial clean deploy
7ff860b
Raw
History Blame Contribute Delete
4.54 kB
import { Link, useLocation, useNavigate } from "react-router-dom";
import { Activity, Users, AlertTriangle, LogOut, Brain } from "lucide-react";
import { useAuth } from "@/contexts/AuthContext";
import { useProfile } from "@/hooks/useProfile";
import { XP_PER_LEVEL, xpInLevel, isNightMode } from "@/lib/engine";
import { Button } from "@/components/ui/button";
const tabs = [
{ to: "/", label: "Dashboard", icon: Activity },
{ to: "/social", label: "Social", icon: Users },
{ to: "/emergency", label: "Emergency", icon: AlertTriangle },
];
export default function AppHeader() {
const location = useLocation();
const navigate = useNavigate();
const { user, signOut } = useAuth();
const { profile } = useProfile();
const xp = profile?.total_xp ?? 0;
const level = profile?.level ?? 1;
const inLevel = xpInLevel(xp);
const pct = Math.min(100, (inLevel / XP_PER_LEVEL) * 100);
return (
<>
{isNightMode() && (
<div className="bg-gradient-danger/10 border-b border-warning/30 text-warning text-xs text-center py-2 font-medium">
🌙 Blue Light Alert — past 10pm. Wind down to protect tomorrow's focus.
</div>
)}
<header className="sticky top-0 z-40 glass-strong border-b border-border/50">
<div className="container flex items-center justify-between gap-4 py-3">
<Link to="/" className="flex items-center gap-2 group">
<div className="relative">
<Brain className="h-7 w-7 text-primary" />
<div className="absolute inset-0 blur-lg bg-primary/40 group-hover:bg-primary/60 transition-all" />
</div>
<span className="font-display text-xl font-bold tracking-tight">
Distract<span className="text-gradient-emerald">IQ</span>
</span>
</Link>
<nav className="hidden md:flex items-center gap-1 glass rounded-full p-1">
{tabs.map((t) => {
const active = location.pathname === t.to;
const Icon = t.icon;
return (
<Link
key={t.to}
to={t.to}
className={`flex items-center gap-2 px-4 py-1.5 rounded-full text-sm font-medium transition-all ${
active
? "bg-primary text-primary-foreground glow-emerald"
: "text-muted-foreground hover:text-foreground"
}`}
>
<Icon className="h-4 w-4" />
{t.label}
</Link>
);
})}
</nav>
<div className="flex items-center gap-3">
{user && profile && (
<div className="hidden sm:flex flex-col items-end min-w-[140px]">
<div className="flex items-center gap-2 text-xs">
<span className="font-mono text-primary">L{level}</span>
<span className="text-muted-foreground">{profile.username}</span>
</div>
<div className="w-32 h-1.5 bg-muted rounded-full overflow-hidden mt-1">
<div
className="h-full bg-gradient-emerald transition-all duration-500"
style={{ width: `${pct}%` }}
/>
</div>
<span className="text-[10px] text-muted-foreground mt-0.5 font-mono">
{inLevel}/{XP_PER_LEVEL} XP
</span>
</div>
)}
{user ? (
<Button variant="ghost" size="icon" onClick={signOut} aria-label="Sign out">
<LogOut className="h-4 w-4" />
</Button>
) : (
<Button onClick={() => navigate("/auth")} variant="default" size="sm">
Sign in
</Button>
)}
</div>
</div>
{/* Mobile nav */}
<nav className="md:hidden flex items-center justify-around border-t border-border/40 py-2">
{tabs.map((t) => {
const active = location.pathname === t.to;
const Icon = t.icon;
return (
<Link
key={t.to}
to={t.to}
className={`flex flex-col items-center gap-1 text-xs ${active ? "text-primary" : "text-muted-foreground"}`}
>
<Icon className="h-4 w-4" />
{t.label}
</Link>
);
})}
</nav>
</header>
</>
);
}