Files
nextcraft/apps/web/components/header.tsx
T
CIAgent 810485ecc8 docs(milestone): complete v0.1-nextcraft-ui-prototype
---ci---
phase: 7
milestone: v0.1
status: complete
requirements:
  covered: [REQ-001, REQ-002, REQ-003, REQ-004, REQ-005, REQ-006, REQ-007, REQ-008, REQ-009, REQ-010, REQ-011, REQ-012, REQ-013, REQ-014, REQ-015, REQ-016, REQ-017, REQ-018, REQ-019, REQ-020, REQ-021, REQ-022, REQ-023, REQ-024, REQ-025, REQ-026, REQ-027, REQ-028]
  partial: []
---/ci---

Milestone v0.1 (nextcraft-ui-prototype) complete.

Summary:
- 7 phases (P0 pre-execution + P1-P6 execution + P7 final review)
- 28 requirements covered (all complete)
- 4 surfaces: Learner (7 pages), Marketplace (5), Employer Dashboard (4), Admin (4)
- 19 routes, 104 TypeScript files
- Shared component library (5 primitives + design tokens)
- Mock data: 5 competency stacks (70 competencies), 20 jobs, 15 candidates, 10 employers
- Tech: Next.js 15, Tailwind CSS v4, lucide-react, recharts, @xyflow/react, Inter font
- Storybook with 6 stories
- Dark mode, breadcrumbs, role switcher, responsive design
- Build passes, typecheck passes, Storybook build passes

Phases:
  P0 pre-execution     → v0.0.1
  P1 project-scaffolding → v0.0.2
  P2 learner-surface   → v0.0.3
  P3 marketplace-surface → v0.0.4
  P4 employer-dashboard → v0.0.5
  P5 admin-surface     → v0.0.6
  P6 polish-integration → v0.0.7
  P7 final-review-ship → v0.1.0 (milestone release)
2026-09-10 22:47:56 +00:00

70 lines
2.6 KiB
TypeScript

'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { Workflow } from 'lucide-react';
import { DarkModeToggle } from './dark-mode-toggle';
import { RoleSwitcher } from './role-switcher';
import { Breadcrumbs } from './breadcrumbs';
const NAV_LINKS = [
{ label: 'Learner', href: '/', segment: 'learner' },
{ label: 'Marketplace', href: '/marketplace', segment: 'marketplace' },
{ label: 'Employer', href: '/employer', segment: 'employer' },
{ label: 'Admin', href: '/admin', segment: 'admin' },
];
/** Map the current pathname to the active surface segment. */
function activeSegment(pathname: string): string {
if (pathname.startsWith('/marketplace')) return 'marketplace';
if (pathname.startsWith('/employer')) return 'employer';
if (pathname.startsWith('/admin')) return 'admin';
return 'learner';
}
export function Header() {
const pathname = usePathname() ?? '/';
const active = activeSegment(pathname);
return (
<header className="sticky top-0 z-30 border-b border-slate-200 bg-white/80 backdrop-blur dark:border-slate-800 dark:bg-slate-950/80">
<div className="mx-auto flex h-14 max-w-7xl items-center gap-4 px-4 sm:px-6">
<Link href="/" className="flex items-center gap-2 font-semibold">
<span className="flex h-8 w-8 items-center justify-center rounded-md bg-primary-600 text-white">
<Workflow className="h-4 w-4" />
</span>
<span className="text-slate-900 dark:text-slate-100">Nextcraft</span>
</Link>
<nav className="ml-4 hidden items-center gap-1 md:flex" aria-label="Primary">
{NAV_LINKS.map((l) => {
const isActive = l.segment === active;
return (
<Link
key={l.href}
href={l.href}
aria-current={isActive ? 'page' : undefined}
className={`rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${
isActive
? 'bg-primary-50 text-primary-700 dark:bg-primary-900/30 dark:text-primary-200'
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-300 dark:hover:bg-slate-800 dark:hover:text-slate-100'
}`}
>
{l.label}
</Link>
);
})}
</nav>
<div className="ml-auto flex items-center gap-2">
<RoleSwitcher />
<DarkModeToggle />
</div>
</div>
{/* Breadcrumb strip — rendered inside the sticky header so it stays
visible and consistent across all four surfaces. */}
<Breadcrumbs />
</header>
);
}