84 lines
3.3 KiB
TypeScript
84 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import { cn } from "@/lib/cn";
|
|
import { CoMark } from "@/components/co-mark";
|
|
import { AssistantConsole } from "@/components/assistant-console";
|
|
import { MobileNav } from "@/components/mobile-nav";
|
|
import { ThemeToggle } from "@/components/theme-toggle";
|
|
import { JobsProvider } from "@/components/jobs/job-store";
|
|
import { PipelineProvider } from "@/components/pipeline/pipeline-provider";
|
|
import { ApplyProvider } from "@/components/apply/apply-provider";
|
|
import { ExploreProvider } from "@/components/explore/explore-provider";
|
|
import { FirstScoreView } from "@/components/explore/first-score-view";
|
|
import { BetaBanner } from "@/components/beta/beta-banner";
|
|
import { WorkerPills } from "@/components/jobs/worker-pills";
|
|
import { UsageMeter } from "@/components/usage-meter";
|
|
import { instrumentSerif } from "@/lib/fonts";
|
|
import { NAV_ITEMS, isActivePath } from "@/lib/nav-items";
|
|
|
|
export function AppShell({ children }: { children: React.ReactNode }) {
|
|
const pathname = usePathname();
|
|
return (
|
|
<JobsProvider>
|
|
<PipelineProvider>
|
|
<ApplyProvider>
|
|
<ExploreProvider>
|
|
<MobileNav />
|
|
<div className="flex min-h-screen">
|
|
<aside className="sticky top-0 hidden h-screen w-60 shrink-0 flex-col overflow-y-auto border-r border-border bg-surface/30 p-4 md:flex">
|
|
<Link href="/" className="mb-8 flex items-center gap-2.5 px-1">
|
|
<CoMark size={32} />
|
|
<span className={`${instrumentSerif.className} relative -top-px text-2xl font-normal tracking-tight text-landing`}>
|
|
career-ops
|
|
</span>
|
|
</Link>
|
|
<nav className="flex flex-col gap-1">
|
|
{NAV_ITEMS.map(({ href, label, icon: Icon, chip }) => {
|
|
const active = isActivePath(href, pathname);
|
|
return (
|
|
<Link
|
|
key={href}
|
|
href={href}
|
|
className={cn(
|
|
"flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors",
|
|
active
|
|
? "bg-brand-soft text-brand"
|
|
: "text-muted hover:bg-surface-hover hover:text-foreground",
|
|
)}
|
|
>
|
|
<Icon className="size-4" />
|
|
{label}
|
|
{chip && (
|
|
<span className="ml-auto rounded-full border border-brand/30 bg-brand-soft px-1.5 py-0.5 text-[9px] font-bold uppercase tracking-wide text-brand">
|
|
{chip}
|
|
</span>
|
|
)}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
|
|
<WorkerPills />
|
|
|
|
<div className="mt-auto space-y-3 pt-4">
|
|
<UsageMeter />
|
|
<div className="flex items-center justify-between px-1">
|
|
<span className={`${instrumentSerif.className} text-sm text-faint`}>local-first · v0</span>
|
|
<ThemeToggle />
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
<main className="flex-1 overflow-x-hidden">{children}</main>
|
|
<AssistantConsole />
|
|
<FirstScoreView />
|
|
<BetaBanner />
|
|
</div>
|
|
</ExploreProvider>
|
|
</ApplyProvider>
|
|
</PipelineProvider>
|
|
</JobsProvider>
|
|
);
|
|
}
|