Frontend: hamburger menu v hlavicke na mobile

Hlavicka GameListu sa na uzkych displejoch nezmestila do jedneho
riadku. Pod sm: breakpointom sa polozky zbalia do dropdownu.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
tim
2026-07-10 01:16:40 +02:00
co-authored by Claude Opus 4.8
parent 973c279cbd
commit 8e18325660
2 changed files with 107 additions and 12 deletions
+100
View File
@@ -0,0 +1,100 @@
import { useEffect, useRef, useState } from 'react';
interface Props {
username?: string;
onHistory: () => void;
onDonate: () => void;
onLogout: () => void;
}
/** Header navigation: a row of links from `sm:` up, a hamburger dropdown below it. */
export default function HeaderMenu({ username, onHistory, onDonate, onLogout }: Props) {
const [open, setOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!open) return;
const onPointerDown = (e: PointerEvent) => {
if (!ref.current?.contains(e.target as Node)) setOpen(false);
};
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') setOpen(false);
};
document.addEventListener('pointerdown', onPointerDown);
document.addEventListener('keydown', onKeyDown);
return () => {
document.removeEventListener('pointerdown', onPointerDown);
document.removeEventListener('keydown', onKeyDown);
};
}, [open]);
const pick = (action: () => void) => () => {
setOpen(false);
action();
};
return (
<>
<div className="hidden sm:flex items-center gap-3 text-sm">
<span className="text-green-dim">{username}</span>
<button onClick={onHistory} className="text-gold hover:text-gold-bright">
História
</button>
<button onClick={onDonate} className="text-gold hover:text-gold-bright">
Na kávu
</button>
<button onClick={onLogout} className="text-green-dim hover:text-gold">
Odhlásiť
</button>
</div>
<div ref={ref} className="relative sm:hidden">
<button
onClick={() => setOpen((o) => !o)}
aria-label="Menu"
aria-expanded={open}
aria-haspopup="menu"
className="flex flex-col justify-center gap-[5px] w-9 h-9 items-center rounded-lg border border-gold/20 text-gold hover:border-gold/50 transition-colors"
>
<span className="block w-4 h-px bg-current" />
<span className="block w-4 h-px bg-current" />
<span className="block w-4 h-px bg-current" />
</button>
{open && (
<div
role="menu"
className="absolute right-0 top-11 z-40 w-44 bg-header border border-[#142018] rounded-xl py-1 shadow-[0_20px_60px_rgba(0,0,0,.6)]"
>
{username && (
<p className="px-4 py-2 text-xs text-green-dim border-b border-[#142018] truncate">
{username}
</p>
)}
<button
role="menuitem"
onClick={pick(onHistory)}
className="block w-full text-left px-4 py-2.5 text-sm text-gold hover:bg-gold/10"
>
História
</button>
<button
role="menuitem"
onClick={pick(onDonate)}
className="block w-full text-left px-4 py-2.5 text-sm text-gold hover:bg-gold/10"
>
Na kávu
</button>
<button
role="menuitem"
onClick={pick(onLogout)}
className="block w-full text-left px-4 py-2.5 text-sm text-green-dim hover:bg-gold/10 hover:text-gold"
>
Odhlásiť
</button>
</div>
)}
</div>
</>
);
}
+7 -12
View File
@@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom';
import { useGameStore } from '../store/gameStore'; import { useGameStore } from '../store/gameStore';
import { emit, socket, setAuthToken } from '../lib/socket'; import { emit, socket, setAuthToken } from '../lib/socket';
import { trackEvent } from '../lib/track'; import { trackEvent } from '../lib/track';
import HeaderMenu from '../components/HeaderMenu';
import NameModal from '../components/NameModal'; import NameModal from '../components/NameModal';
import RulesModal from '../components/RulesModal'; import RulesModal from '../components/RulesModal';
@@ -33,18 +34,12 @@ export default function GameList() {
<div className="max-w-md mx-auto p-4 pt-8 min-h-screen"> <div className="max-w-md mx-auto p-4 pt-8 min-h-screen">
<div className="flex items-center justify-between mb-6"> <div className="flex items-center justify-between mb-6">
<h1 className="font-serif text-2xl text-gold tracking-wide">Bridžik</h1> <h1 className="font-serif text-2xl text-gold tracking-wide">Bridžik</h1>
<div className="flex items-center gap-3 text-sm"> <HeaderMenu
<span className="text-green-dim">{account?.username}</span> username={account?.username}
<button onClick={() => navigate('/history')} className="text-gold hover:text-gold-bright"> onHistory={() => navigate('/history')}
História onDonate={() => navigate('/donate')}
</button> onLogout={handleLogout}
<button onClick={() => navigate('/donate')} className="text-gold hover:text-gold-bright"> />
Na kávu
</button>
<button onClick={handleLogout} className="text-green-dim hover:text-gold">
Odhlásiť
</button>
</div>
</div> </div>
<div className="flex flex-col gap-3 mb-6"> <div className="flex flex-col gap-3 mb-6">