104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
import { type ReactNode, useEffect, useRef, useState } from "react";
|
|
import { Link, useNavigate } from "react-router";
|
|
import { useAuth } from "../hooks/useAuth.ts";
|
|
import { DumpCreateModal } from "./DumpCreateModal.tsx";
|
|
import { NotificationBell } from "./NotificationBell.tsx";
|
|
|
|
export function AppHeader(
|
|
{ centerSlot, disableNew }: { centerSlot?: ReactNode; disableNew?: boolean },
|
|
) {
|
|
const { user } = useAuth();
|
|
const navigate = useNavigate();
|
|
const headerRef = useRef<HTMLElement>(null);
|
|
const [_showFab, setShowFab] = useState(false);
|
|
const [createModalOpen, setCreateModalOpen] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const el = headerRef.current;
|
|
if (!el) return;
|
|
const obs = new IntersectionObserver(
|
|
([entry]) => setShowFab(!entry.isIntersecting),
|
|
{ threshold: 0 },
|
|
);
|
|
obs.observe(el);
|
|
return () => obs.disconnect();
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<header
|
|
ref={headerRef}
|
|
className={`app-header${centerSlot ? " app-header--has-center" : ""}`}
|
|
>
|
|
<Link to="/" state={{ tab: "hot" }} className="app-header-brand">
|
|
🚚 gerbeur
|
|
</Link>
|
|
|
|
{centerSlot && <div className="app-header-center">{centerSlot}</div>}
|
|
|
|
<nav className="app-header-nav">
|
|
{user
|
|
? (
|
|
<>
|
|
<Link
|
|
to={`/users/${user.username}`}
|
|
className="app-header-user"
|
|
>
|
|
{user.username}
|
|
</Link>
|
|
<Link
|
|
to={`/users/${user.username}/playlists`}
|
|
className="app-header-user"
|
|
>
|
|
Playlists
|
|
</Link>
|
|
<NotificationBell />
|
|
<button
|
|
type="button"
|
|
className="btn-primary"
|
|
onClick={() => setCreateModalOpen(true)}
|
|
disabled={disableNew}
|
|
title={disableNew ? "Server unreachable" : undefined}
|
|
>
|
|
+ New
|
|
</button>
|
|
</>
|
|
)
|
|
: (
|
|
<>
|
|
<button type="button" onClick={() => navigate("/login")}>
|
|
Log in
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="btn-primary"
|
|
onClick={() => navigate("/register")}
|
|
>
|
|
Register
|
|
</button>
|
|
</>
|
|
)}
|
|
</nav>
|
|
</header>
|
|
|
|
{
|
|
/* {user && createPortal(
|
|
<button
|
|
type="button"
|
|
className={`fab-new${showFab ? " fab-new--visible" : ""}`}
|
|
onClick={() => setCreateModalOpen(true)}
|
|
aria-label="New dump"
|
|
>
|
|
+ New
|
|
</button>,
|
|
document.body,
|
|
)} */
|
|
}
|
|
|
|
{createModalOpen && (
|
|
<DumpCreateModal onClose={() => setCreateModalOpen(false)} />
|
|
)}
|
|
</>
|
|
);
|
|
}
|