feat(02-01): create HeaderBar component with brand, Bell placeholder, avatar trigger
- 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
This commit is contained in:
parent
2ef843766d
commit
05611cd80e
1 changed files with 72 additions and 0 deletions
72
components/mobile/HeaderBar.tsx
Normal file
72
components/mobile/HeaderBar.tsx
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
'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>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue