This commit is contained in:
valenti
2026-09-08 07:21:34 -04:00
commit a4b224da8e
169 changed files with 27483 additions and 0 deletions
@@ -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>
);
}