Files
gerbeur/src/components/UserMenu.tsx
2026-03-30 14:55:30 +00:00

67 lines
1.8 KiB
TypeScript

import { useEffect, useRef, useState } from "react";
import { Link } from "react-router";
import { Avatar } from "./Avatar.tsx";
import type { User } from "../model.ts";
export function UserMenu({ user }: { user: User }) {
const [open, setOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!open) return;
function onMouseDown(e: MouseEvent) {
if (ref.current && !ref.current.contains(e.target as Node)) {
setOpen(false);
}
}
function onKeyDown(e: KeyboardEvent) {
if (e.key === "Escape") setOpen(false);
}
document.addEventListener("mousedown", onMouseDown);
document.addEventListener("keydown", onKeyDown);
return () => {
document.removeEventListener("mousedown", onMouseDown);
document.removeEventListener("keydown", onKeyDown);
};
}, [open]);
return (
<div className="user-menu" ref={ref}>
<button
type="button"
className="user-menu-trigger"
onClick={() => setOpen((o) => !o)}
aria-expanded={open}
aria-label="User menu"
>
<Avatar
userId={user.id}
username={user.username}
hasAvatar={!!user.avatarMime}
size={28}
/>
</button>
{open && (
<div className="user-menu-dropdown" role="menu">
<Link
to={`/users/${user.username}`}
className="user-menu-item"
role="menuitem"
onClick={() => setOpen(false)}
>
@{user.username}
</Link>
<Link
to={`/users/${user.username}/playlists`}
className="user-menu-item"
role="menuitem"
onClick={() => setOpen(false)}
>
Playlists
</Link>
</div>
)}
</div>
);
}