- Sticky header with bg-background/95 backdrop-blur and border-b - WulfMark + Pulse wordmark linked to /mobile/dashboard - Bell icon placeholder (aria-label=Notifications, empty onClick per SHELL-03) - Avatar circle (h-7 w-7) triggers drawer via onAvatarClick prop - pt-safe applied for notch/dynamic-island clearance (PWA-04) - Implements SHELL-02..04 requirements
72 lines
2.7 KiB
TypeScript
72 lines
2.7 KiB
TypeScript
'use client';
|
|
|
|
/* HeaderBar — phase 02 (SHELL-02..04).
|
|
*
|
|
* Sticky top bar inside the /mobile shell. Three slots:
|
|
* left: WulfMark + "Pulse" wordmark, linked to /mobile/dashboard
|
|
* right: Bell icon button (placeholder, aria-label="Notifications")
|
|
* right: compact avatar circle — opens the More drawer (parent owns state)
|
|
*
|
|
* No page title in the header — pages render their own H1. */
|
|
|
|
import Link from 'next/link';
|
|
import { Bell } from 'lucide-react';
|
|
import { WulfMark } from '@/components/branding/wulf-mark';
|
|
import { useSession } from '@/lib/auth-client';
|
|
|
|
interface HeaderBarProps {
|
|
onAvatarClick: () => void;
|
|
}
|
|
|
|
export function HeaderBar({ onAvatarClick }: HeaderBarProps) {
|
|
const { data: session } = useSession();
|
|
const user = session?.user as
|
|
| { name?: string; email?: string }
|
|
| undefined;
|
|
|
|
const initials = (user?.name ?? user?.email ?? '?')
|
|
.split(/[\s@]/)
|
|
.filter(Boolean)
|
|
.slice(0, 2)
|
|
.map((p) => p[0]?.toUpperCase())
|
|
.join('');
|
|
|
|
return (
|
|
<header className="sticky top-0 z-30 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 border-b pt-safe">
|
|
<div className="flex items-center justify-between px-4 h-14">
|
|
{/* Left: brand mark + wordmark, linked to /mobile/dashboard */}
|
|
<Link
|
|
href="/mobile/dashboard"
|
|
className="flex items-center gap-2 -ml-1 px-1 rounded-md hover:bg-accent/50 transition-colors"
|
|
aria-label="Pulse — go to Dashboard"
|
|
>
|
|
<WulfMark variant="mark" className="h-6 w-auto" />
|
|
<span className="font-bold text-base tracking-tight">Pulse</span>
|
|
</Link>
|
|
|
|
{/* Right: Bell placeholder, then avatar trigger */}
|
|
<div className="flex items-center gap-1">
|
|
<button
|
|
type="button"
|
|
onClick={() => { /* SHELL-03: placeholder — no menu, no badge */ }}
|
|
aria-label="Notifications"
|
|
className="inline-flex items-center justify-center h-9 w-9 rounded-md hover:bg-accent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
>
|
|
<Bell className="h-5 w-5" />
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={onAvatarClick}
|
|
aria-label="Open menu"
|
|
className="inline-flex items-center justify-center h-9 w-9 rounded-md hover:bg-accent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
>
|
|
<span className="inline-flex h-7 w-7 items-center justify-center rounded-full bg-primary/15 text-primary text-[11px] font-semibold">
|
|
{initials}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
);
|
|
}
|