40b99f3add
Deploy / deploy (push) Successful in 3m19s
At phone width the sidebar stayed 240px wide, leaving pages a ~135px strip. Below md it is now hidden behind a menu button in the header and opens as a drawer (closes on navigation, backdrop, X or Escape); from md up the sidebar is unchanged. Page wrappers use p-4 on phones and keep p-6/p-8 from md. Shot detail: on phones the thumbnail takes the full width with the details below it instead of pushing them off screen, the action buttons wrap, and the tab bar scrolls sideways. Desktop sizing is kept as it was. Every change is behind a md: breakpoint, so the desktop layout is the same. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
118 lines
4.3 KiB
TypeScript
118 lines
4.3 KiB
TypeScript
"use client";
|
|
|
|
import { useSession, signOut } from "next-auth/react";
|
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
import { NotificationBell } from "@/components/notifications/NotificationBell";
|
|
import { getInitials } from "@/lib/utils";
|
|
import { LogOut, User, Settings, Menu } from "lucide-react";
|
|
import Link from "next/link";
|
|
import { useMobileNav } from "@/components/layout/MobileNav";
|
|
|
|
interface HeaderProps {
|
|
title?: string;
|
|
breadcrumbs?: { label: string; href?: string }[];
|
|
}
|
|
|
|
export function Header({ title, breadcrumbs }: HeaderProps) {
|
|
const { data: session } = useSession();
|
|
const user = session?.user;
|
|
const { setOpen: setMobileNavOpen } = useMobileNav();
|
|
|
|
return (
|
|
<header className="flex h-14 items-center justify-between border-b border-zinc-800 bg-zinc-950 px-4 md:px-6">
|
|
{/* Left: Title / Breadcrumbs */}
|
|
<div className="flex items-center gap-2 min-w-0">
|
|
{/* Phones only: the sidebar is hidden below md and opens as a drawer. */}
|
|
<button
|
|
type="button"
|
|
onClick={() => setMobileNavOpen(true)}
|
|
className="md:hidden -ml-2 rounded-md p-2 text-zinc-400 hover:bg-zinc-800 hover:text-white"
|
|
aria-label="Open menu"
|
|
>
|
|
<Menu className="h-5 w-5" />
|
|
</button>
|
|
{breadcrumbs ? (
|
|
<nav className="flex items-center gap-1.5 text-sm">
|
|
{breadcrumbs.map((crumb, i) => (
|
|
<span key={i} className="flex items-center gap-1.5">
|
|
{i > 0 && <span className="text-muted-foreground">/</span>}
|
|
{crumb.href ? (
|
|
<Link
|
|
href={crumb.href}
|
|
className="text-muted-foreground hover:text-foreground transition-colors"
|
|
>
|
|
{crumb.label}
|
|
</Link>
|
|
) : (
|
|
<span className="text-foreground font-medium truncate">
|
|
{crumb.label}
|
|
</span>
|
|
)}
|
|
</span>
|
|
))}
|
|
</nav>
|
|
) : (
|
|
title && (
|
|
<h1 className="text-sm font-semibold truncate">{title}</h1>
|
|
)
|
|
)}
|
|
</div>
|
|
|
|
{/* Right: Notifications + User menu */}
|
|
<div className="flex items-center gap-3">
|
|
<NotificationBell />
|
|
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<button className="flex items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-secondary transition-colors">
|
|
<Avatar className="h-7 w-7">
|
|
{user?.image && <AvatarImage src={user.image} alt={user.name ?? ""} />}
|
|
<AvatarFallback className="text-xs">
|
|
{getInitials(user?.name)}
|
|
</AvatarFallback>
|
|
</Avatar>
|
|
<div className="hidden sm:block text-left">
|
|
<p className="text-xs font-medium leading-none">{user?.name ?? user?.email}</p>
|
|
<p className="text-xs text-muted-foreground capitalize">
|
|
{user?.role?.toLowerCase()}
|
|
</p>
|
|
</div>
|
|
</button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-48">
|
|
<DropdownMenuLabel>
|
|
<p className="font-medium truncate">{user?.name}</p>
|
|
<p className="text-xs text-muted-foreground font-normal truncate">
|
|
{user?.email}
|
|
</p>
|
|
</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem asChild>
|
|
<Link href="/settings" className="flex items-center gap-2 cursor-pointer">
|
|
<Settings className="h-4 w-4" />
|
|
Settings
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem
|
|
className="text-destructive focus:text-destructive cursor-pointer"
|
|
onClick={() => signOut({ callbackUrl: "/login" })}
|
|
>
|
|
<LogOut className="h-4 w-4 mr-2" />
|
|
Sign out
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</header>
|
|
);
|
|
}
|