feat: add user menu dropdown with settings link and sign out

Replace the plain "Sign out" button in the header with a user icon
that opens a dropdown menu containing Settings and Sign out options.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 20:19:53 +02:00
parent 3eccbb12fd
commit 0a40d7627f
3 changed files with 104 additions and 20 deletions

View File

@@ -0,0 +1,57 @@
import { Link } from "@tanstack/react-router";
import { useEffect, useRef, useState } from "react";
import { useLogout } from "../hooks/useAuth";
import { LucideIcon } from "../lib/iconData";
export function UserMenu() {
const [open, setOpen] = useState(false);
const menuRef = useRef<HTMLDivElement>(null);
const logout = useLogout();
useEffect(() => {
if (!open) return;
function handleClick(e: MouseEvent) {
if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
setOpen(false);
}
}
document.addEventListener("mousedown", handleClick);
return () => document.removeEventListener("mousedown", handleClick);
}, [open]);
return (
<div ref={menuRef} className="relative">
<button
type="button"
onClick={() => setOpen((prev) => !prev)}
className="flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:text-gray-700 hover:bg-gray-100 transition-colors"
>
<LucideIcon name="circle-user" size={22} />
</button>
{open && (
<div className="absolute right-0 mt-1 w-40 bg-white rounded-lg shadow-lg border border-gray-200 py-1 z-50">
<Link
to="/settings"
onClick={() => setOpen(false)}
className="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 transition-colors"
>
<LucideIcon name="settings" size={16} className="text-gray-400" />
Settings
</Link>
<div className="border-t border-gray-100 my-1" />
<button
type="button"
onClick={() => {
setOpen(false);
logout.mutate();
}}
className="flex items-center gap-2 w-full px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 transition-colors"
>
<LucideIcon name="log-out" size={16} className="text-gray-400" />
Sign out
</button>
</div>
)}
</div>
);
}