Files
placebo.mk/pwa/src/components/layout/Header.tsx
T
2026-02-22 01:11:20 +01:00

220 lines
9.8 KiB
TypeScript

import { useState } from 'react';
import { Link } from '@tanstack/react-router';
import { useAuth } from '../../contexts/AuthContext';
import { Button } from '../ui/button';
import { ThemeToggle } from './ThemeToggle';
import { Menu, X, Zap } from 'lucide-react';
const mkMonths = ['Јануари', 'Февруари', 'Март', 'Април', 'Мај', 'Јуни', 'Јули', 'Август', 'Септември', 'Октомври', 'Ноември', 'Декември'];
const mkWeekdays = ['Понеделник', 'Вторник', 'Среда', 'Четврток', 'Петок', 'Сабота', 'Недела'];
const formatDateMk = () => {
const d = new Date();
return `${mkWeekdays[d.getDay()]}, ${d.getDate()} ${mkMonths[d.getMonth()]} ${d.getFullYear()}`;
};
export function Header() {
const { user, logout, isAuthenticated, hasRole } = useAuth();
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const toggleMobileMenu = () => {
setIsMobileMenuOpen(!isMobileMenuOpen);
};
const closeMobileMenu = () => {
setIsMobileMenuOpen(false);
};
const navLinks = [
{ to: '/', label: 'Почетна' },
{ to: '/sport', label: 'Спорт' },
{ to: '/art', label: 'Уметност' },
{ to: '/science', label: 'Наука' },
{ to: '/archive', label: 'Архива' },
{ to: '/live-blogs', label: 'LIVE' },
];
const adminLinks = [
{ to: '/admin', label: 'Admin' },
{ to: '/admin/live-blogs/create', label: '+ New Live' },
];
return (
<header className="sticky top-0 z-50 border-b-4 border-foreground bg-[hsl(var(--background))]">
<div className="border-b-2 border-foreground/20">
<div className="container mx-auto max-w-7xl px-4">
<div className="flex items-center justify-between py-2">
<div className="hidden md:flex items-center gap-2 text-xs font-mono uppercase tracking-wider text-muted-foreground">
<Zap className="w-3 h-3" />
<span>Сатирични вести од Македонија</span>
</div>
<div className="text-xs font-mono uppercase tracking-wider text-muted-foreground">
{formatDateMk()}
</div>
</div>
</div>
</div>
<div className="container mx-auto max-w-6xl px-4 py-4">
<div className="flex items-center justify-between">
<Link to="/" className="group">
<h1 className="text-4xl md:text-5xl font-display tracking-tight">
<span className="inline-block transition-transform group-hover:-translate-y-1 group-hover:translate-x-1">P</span>
<span className="inline-block transition-transform group-hover:-translate-y-1 group-hover:translate-x-0.5 delay-75">l</span>
<span className="inline-block transition-transform group-hover:-translate-y-1 group-hover:translate-x-0 delay-100">a</span>
<span className="inline-block transition-transform group-hover:-translate-y-1 group-hover:translate-x-0.5 delay-150">c</span>
<span className="inline-block transition-transform group-hover:-translate-y-1 group-hover:translate-x-0 delay-200">e</span>
<span className="inline-block transition-transform group-hover:-translate-y-1 group-hover:translate-x-0.5 delay-250">b</span>
<span className="inline-block transition-transform group-hover:-translate-y-1 group-hover:translate-x-0 delay-300">o</span>
<span className="text-accent inline-block transition-transform group-hover:-translate-y-1 group-hover:translate-x-0.5 delay-350">.</span>
<span className="inline-block transition-transform group-hover:-translate-y-1 group-hover:translate-x-1 delay-400">m</span>
<span className="inline-block transition-transform group-hover:-translate-y-1 group-hover:translate-x-0.5 delay-500">k</span>
</h1>
</Link>
<div className="hidden md:flex items-center gap-1">
{navLinks.map((link, index) => (
<Link
key={link.to}
to={link.to}
className="px-4 py-2 font-body text-sm font-medium uppercase tracking-wider border-2 border-transparent hover:border-foreground hover:bg-accent hover:text-foreground transition-all duration-150"
style={{ animationDelay: `${index * 50}ms` }}
>
{link.label}
</Link>
))}
{isAuthenticated ? (
<>
{(hasRole('admin') || hasRole('contributor')) && (
<>
{adminLinks.map((link) => (
<Link
key={link.to}
to={link.to}
className="px-3 py-2 font-body text-sm font-medium uppercase tracking-wider border-2 border-accent bg-accent text-foreground hover:bg-foreground hover:text-accent transition-all duration-150"
>
{link.label}
</Link>
))}
</>
)}
<div className="flex items-center gap-3 ml-4 pl-4 border-l-2 border-foreground/20">
<span className="font-body text-xs uppercase tracking-wider text-muted-foreground">
{user?.username}
</span>
<Button
variant="brutal"
size="sm"
onClick={logout}
>
OUT
</Button>
</div>
</>
) : (
<Link to="/auth" className="px-4 py-2 font-body text-sm font-medium uppercase tracking-wider border-2 border-foreground bg-foreground text-background hover:bg-accent hover:text-foreground hover:border-accent transition-all duration-150 ml-2">
Login
</Link>
)}
<div className="ml-4 pl-4 border-l-2 border-foreground/20 flex items-center gap-3">
<a
href="https://www.buymeacoffee.com/placebomk"
target="_blank"
rel="noopener noreferrer"
className="hidden lg:block border-2 border-foreground bg-yellow-400 hover:bg-yellow-300 transition-colors px-3 py-1 font-body text-xs font-bold uppercase tracking-wider"
>
☕ Купи ми кафе
</a>
<ThemeToggle />
</div>
</div>
<div className="flex items-center gap-2 md:hidden">
<ThemeToggle />
<Button
variant="brutal"
size="icon"
onClick={toggleMobileMenu}
className="h-10 w-10"
aria-label={isMobileMenuOpen ? 'Close menu' : 'Open menu'}
>
{isMobileMenuOpen ? (
<X className="h-5 w-5" />
) : (
<Menu className="h-5 w-5" />
)}
</Button>
</div>
</div>
{isMobileMenuOpen && (
<div className="md:hidden mt-4 pt-4 border-t-4 border-foreground animate-scale-in">
<div className="flex flex-col gap-2">
{navLinks.map((link, index) => (
<Link
key={link.to}
to={link.to}
className="px-4 py-3 font-body text-sm font-medium uppercase tracking-wider border-2 border-foreground hover:bg-accent hover:border-accent transition-all duration-150"
style={{ animationDelay: `${index * 50}ms` }}
onClick={closeMobileMenu}
>
{link.label}
</Link>
))}
{isAuthenticated ? (
<>
{(hasRole('admin') || hasRole('contributor')) && (
<div className="pt-3 mt-2 border-t-4 border-foreground">
<p className="font-body text-xs uppercase tracking-wider text-muted-foreground mb-2 pl-2">Admin</p>
{adminLinks.map((link) => (
<Link
key={link.to}
to={link.to}
className="px-4 py-3 font-body text-sm font-medium uppercase tracking-wider border-2 border-accent bg-accent hover:bg-foreground hover:text-accent transition-all duration-150 block"
onClick={closeMobileMenu}
>
{link.label}
</Link>
))}
</div>
)}
<div className="pt-3 mt-2 border-t-4 border-foreground">
<div className="flex items-center justify-between p-2">
<span className="font-body text-xs uppercase tracking-wider text-muted-foreground">
{user?.username}
</span>
<Button
variant="brutal"
size="sm"
onClick={() => {
logout();
closeMobileMenu();
}}
>
OUT
</Button>
</div>
</div>
</>
) : (
<Link
to="/auth"
className="px-4 py-3 font-body text-sm font-medium uppercase tracking-wider border-2 border-foreground bg-foreground text-background hover:bg-accent hover:text-foreground hover:border-accent transition-all duration-150 mt-2"
onClick={closeMobileMenu}
>
Login
</Link>
)}
</div>
</div>
)}
</div>
</header>
);
}