first
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import {
|
||||
LayoutDashboard,
|
||||
ClipboardList,
|
||||
Search,
|
||||
Code2,
|
||||
GitBranch,
|
||||
Bot,
|
||||
GitFork,
|
||||
Rocket,
|
||||
ShieldCheck,
|
||||
Activity,
|
||||
Plug,
|
||||
BarChart3,
|
||||
Settings2,
|
||||
Sparkles,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface NavItem {
|
||||
href: string;
|
||||
label: string;
|
||||
icon: React.ComponentType<{ className?: string }>;
|
||||
badge?: string;
|
||||
}
|
||||
|
||||
export const NAV: NavItem[] = [
|
||||
{ href: "/", label: "Overview", icon: LayoutDashboard },
|
||||
{ href: "/requirements", label: "Requirements", icon: ClipboardList },
|
||||
{ href: "/context", label: "Context Explorer", icon: Search },
|
||||
{ href: "/code", label: "Code", icon: Code2 },
|
||||
{ href: "/traceability", label: "Traceability", icon: GitBranch },
|
||||
{ href: "/ask-asf", label: "Ask ASF", icon: Sparkles, badge: "AI" },
|
||||
{ href: "/jobs", label: "Jobs", icon: Activity },
|
||||
{ href: "/ai-agents", label: "AI Agents", icon: Bot, badge: "α" },
|
||||
{ href: "/pipelines", label: "Pipelines", icon: GitFork },
|
||||
{ href: "/deployments", label: "Deployments", icon: Rocket },
|
||||
{ href: "/quality", label: "Quality", icon: ShieldCheck },
|
||||
{ href: "/observability", label: "Observability", icon: Activity },
|
||||
{ href: "/integrations", label: "Integrations", icon: Plug },
|
||||
{ href: "/usage", label: "Usage", icon: BarChart3 },
|
||||
{ href: "/settings", label: "Settings", icon: Settings2 },
|
||||
];
|
||||
|
||||
export function Sidebar() {
|
||||
const path = usePathname();
|
||||
return (
|
||||
<aside className="hidden lg:flex w-64 shrink-0 border-r border-slate-200/80 bg-white/60 backdrop-blur-sm flex-col">
|
||||
<div className="h-16 flex items-center gap-3 px-5 border-b border-slate-200/80">
|
||||
<div className="w-9 h-9 rounded-lg bg-gradient-to-br from-brand-500 to-accent shadow-soft grid place-items-center text-white font-bold">
|
||||
A
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="text-sm font-semibold text-slate-800 leading-tight">
|
||||
{process.env.NEXT_PUBLIC_APP_NAME || "ASF"}
|
||||
</div>
|
||||
<div className="text-[11px] text-slate-500 leading-tight">
|
||||
Software Factory
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav className="flex-1 overflow-y-auto p-3 space-y-0.5">
|
||||
{NAV.map(({ href, label, icon: Icon, badge }) => {
|
||||
const active = href === "/" ? path === "/" : path.startsWith(href);
|
||||
return (
|
||||
<Link
|
||||
key={href}
|
||||
href={href}
|
||||
className={cn("asf-nav-item", active && "asf-nav-item-active")}
|
||||
>
|
||||
<Icon className="w-4.5 h-4.5 w-[18px] h-[18px] shrink-0" />
|
||||
<span className="flex-1">{label}</span>
|
||||
{badge && (
|
||||
<span className="asf-chip border-accent/20 bg-accent/10 text-accent-muted !px-1.5">
|
||||
{badge}
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
|
||||
<div className="p-3 border-t border-slate-200/80">
|
||||
<button
|
||||
onClick={() => {
|
||||
// keyboard shortcut is handled in layout; this button also triggers.
|
||||
const ev = new CustomEvent("asf:open-command");
|
||||
window.dispatchEvent(ev);
|
||||
}}
|
||||
className="w-full asf-btn-secondary justify-between !px-3"
|
||||
type="button"
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
<Sparkles className="w-4 h-4 text-accent" />
|
||||
<span className="text-slate-700">Ask ASF…</span>
|
||||
</span>
|
||||
<kbd className="asf-chip !text-[10px]">⌘ K</kbd>
|
||||
</button>
|
||||
<p className="mt-3 text-[11px] text-slate-400 leading-relaxed">
|
||||
Tip: every lifecycle element in ASF is an <span className="font-mono text-slate-600 bg-slate-100 rounded px-1">Artifact</span>.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user