211 lines
6.3 KiB
TypeScript
211 lines
6.3 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import Link from 'next/link';
|
|
import {
|
|
X,
|
|
PawPrint,
|
|
Heart,
|
|
Gift,
|
|
Home,
|
|
Search,
|
|
User,
|
|
Sun,
|
|
Moon,
|
|
ChevronRight,
|
|
Shield,
|
|
} from 'lucide-react';
|
|
|
|
interface SideMenuProps {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export default function SideMenu({ open, onClose }: SideMenuProps) {
|
|
const [dark, setDark] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setDark(
|
|
document.documentElement.classList.contains('dark') ||
|
|
document.documentElement.getAttribute('data-theme') === 'dark'
|
|
);
|
|
}, [open]);
|
|
|
|
useEffect(() => {
|
|
const handler = (e: KeyboardEvent) => {
|
|
if (e.key === 'Escape' && open) onClose();
|
|
};
|
|
window.addEventListener('keydown', handler);
|
|
return () => window.removeEventListener('keydown', handler);
|
|
}, [open, onClose]);
|
|
|
|
const toggleTheme = () => {
|
|
const isDark = document.documentElement.classList.toggle('dark');
|
|
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
|
|
setDark(isDark);
|
|
try { localStorage.setItem('petlink-theme', isDark ? 'dark' : 'light'); } catch (_) {}
|
|
};
|
|
|
|
const menuItems = [
|
|
{ href: '/', icon: Home, label: 'Início' },
|
|
{ href: '/main/animals', icon: Search, label: 'Explorar animais' },
|
|
{ href: '/main/donate', icon: Gift, label: 'Fazer uma doação' },
|
|
{ href: '/main/shelters', icon: PawPrint, label: 'Canis parceiros' },
|
|
{ href: '/main/animals', icon: Heart, label: 'Adoptar' },
|
|
];
|
|
|
|
const accountItems = [
|
|
{ href: '/auth/login', icon: User, label: 'Entrar / Registar' },
|
|
{ href: '/shelter/dashboard', icon: Shield, label: 'Área do Canil' },
|
|
];
|
|
|
|
return (
|
|
<>
|
|
{/* Overlay */}
|
|
<div
|
|
className={`side-menu-overlay${open ? ' open' : ''}`}
|
|
onClick={onClose}
|
|
aria-hidden="true"
|
|
/>
|
|
|
|
{/* Drawer */}
|
|
<aside
|
|
id="side-menu"
|
|
className={`side-menu${open ? ' open' : ''}`}
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-label="Menu de navegação"
|
|
aria-hidden={!open}
|
|
>
|
|
{/* Header do menu */}
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
padding: '20px 24px 16px',
|
|
borderBottom: '1px solid var(--parchment)',
|
|
flexShrink: 0,
|
|
}}
|
|
>
|
|
<Link
|
|
href="/"
|
|
className="logo"
|
|
onClick={onClose}
|
|
style={{ fontSize: '18px' }}
|
|
aria-label="PetLink — Início"
|
|
>
|
|
<PawPrint size={18} strokeWidth={2.5} />
|
|
PetLink
|
|
</Link>
|
|
<button
|
|
onClick={onClose}
|
|
className="menu-btn"
|
|
style={{ width: '36px', height: '36px' }}
|
|
aria-label="Fechar menu"
|
|
>
|
|
<X size={18} style={{ color: 'var(--soil)' }} />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Nav */}
|
|
<nav style={{ flex: 1, overflowY: 'auto', padding: '8px 16px' }}>
|
|
{/* Secção principal */}
|
|
<p
|
|
style={{
|
|
fontFamily: 'var(--font-accent, var(--font-fragment-mono))',
|
|
fontSize: '10px',
|
|
letterSpacing: '0.12em',
|
|
textTransform: 'uppercase',
|
|
color: 'var(--soil-faint)',
|
|
padding: '16px 8px 8px',
|
|
}}
|
|
>
|
|
Navegação
|
|
</p>
|
|
|
|
{menuItems.map(({ href, icon: Icon, label }) => (
|
|
<Link
|
|
key={`${href}-${label}`}
|
|
href={href}
|
|
onClick={onClose}
|
|
className="menu-item"
|
|
style={{ justifyContent: 'space-between' }}
|
|
>
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '14px' }}>
|
|
<Icon size={18} />
|
|
{label}
|
|
</span>
|
|
<ChevronRight size={14} style={{ color: 'var(--soil-faint)' }} />
|
|
</Link>
|
|
))}
|
|
|
|
<div style={{ margin: '12px 8px', borderTop: '1px solid var(--parchment)' }} />
|
|
|
|
<p
|
|
style={{
|
|
fontFamily: 'var(--font-accent, var(--font-fragment-mono))',
|
|
fontSize: '10px',
|
|
letterSpacing: '0.12em',
|
|
textTransform: 'uppercase',
|
|
color: 'var(--soil-faint)',
|
|
padding: '8px 8px',
|
|
}}
|
|
>
|
|
Conta
|
|
</p>
|
|
|
|
{accountItems.map(({ href, icon: Icon, label }) => (
|
|
<Link
|
|
key={href}
|
|
href={href}
|
|
onClick={onClose}
|
|
className="menu-item"
|
|
style={{ justifyContent: 'space-between' }}
|
|
>
|
|
<span style={{ display: 'flex', alignItems: 'center', gap: '14px' }}>
|
|
<Icon size={18} />
|
|
{label}
|
|
</span>
|
|
<ChevronRight size={14} style={{ color: 'var(--soil-faint)' }} />
|
|
</Link>
|
|
))}
|
|
</nav>
|
|
|
|
{/* Footer — toggle de tema */}
|
|
<div style={{ padding: '16px 24px', borderTop: '1px solid var(--parchment)', flexShrink: 0 }}>
|
|
<button
|
|
id="theme-toggle"
|
|
onClick={toggleTheme}
|
|
className="theme-toggle"
|
|
aria-label={dark ? 'Activar modo claro' : 'Activar modo escuro'}
|
|
>
|
|
<span style={{ fontFamily: 'var(--font-body)', fontWeight: 500, fontSize: '14px', color: 'var(--soil)' }}>
|
|
{dark ? 'Modo escuro activo' : 'Modo claro activo'}
|
|
</span>
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '6px',
|
|
background: dark ? 'var(--dark-raised, #2E1E0E)' : 'var(--parchment)',
|
|
borderRadius: '100px',
|
|
padding: '5px 10px',
|
|
transition: 'background 300ms ease',
|
|
}}
|
|
>
|
|
{dark
|
|
? <Moon size={14} style={{ color: 'var(--amber)' }} />
|
|
: <Sun size={14} style={{ color: 'var(--terra)' }} />
|
|
}
|
|
<span style={{ fontSize: '12px', color: 'var(--soil-mid)', fontWeight: 500 }}>
|
|
{dark ? 'Escuro' : 'Claro'}
|
|
</span>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</aside>
|
|
</>
|
|
);
|
|
}
|