83 lines
2.8 KiB
TypeScript
83 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import {
|
|
Code2,
|
|
ClipboardList,
|
|
Globe,
|
|
Database,
|
|
Settings,
|
|
CreditCard,
|
|
PlaneTakeoff,
|
|
} from "lucide-react";
|
|
|
|
export function DashboardSidebar({ workspace, projectId, children }: { workspace: string, projectId: string, children: React.ReactNode }) {
|
|
const pathname = usePathname() ?? "";
|
|
const projectBase = `/${workspace}/project/${projectId}`;
|
|
const isPreview = pathname === `${projectBase}/preview` || pathname.startsWith(`${projectBase}/preview/`);
|
|
|
|
if (isPreview) {
|
|
return <>{children}</>;
|
|
}
|
|
|
|
const items = [
|
|
{ segment: "plan", label: "Plan", Icon: ClipboardList },
|
|
{ segment: "market", label: "Market", Icon: PlaneTakeoff },
|
|
{ segment: "product", label: "Code", Icon: Code2, aliases: ["code"] },
|
|
{ segment: "hosting", label: "Hosting", Icon: Globe },
|
|
{ segment: "infrastructure", label: "Infra", Icon: Database },
|
|
{ segment: "billing", label: "Billing", Icon: CreditCard },
|
|
{ segment: "settings", label: "Settings", Icon: Settings },
|
|
];
|
|
|
|
return (
|
|
<div style={{ display: "flex", flex: 1, minHeight: 0, minWidth: 0 }}>
|
|
<div style={{
|
|
width: 240,
|
|
borderRight: "1px solid #e4e4e7",
|
|
background: "#fafafa",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
padding: "16px 12px",
|
|
gap: 4,
|
|
overflowY: "auto"
|
|
}}>
|
|
<div style={{ fontSize: "0.75rem", fontWeight: 600, color: "#a1a1aa", padding: "0 8px 8px", textTransform: "uppercase", letterSpacing: "0.05em" }}>
|
|
Dashboard
|
|
</div>
|
|
{items.map(item => {
|
|
const active = pathname === `${projectBase}/${item.segment}` || (item.aliases && item.aliases.some(a => pathname === `${projectBase}/${a}`));
|
|
return (
|
|
<Link
|
|
key={item.segment}
|
|
href={`${projectBase}/${item.segment}`}
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: 10,
|
|
padding: "8px 12px",
|
|
borderRadius: 8,
|
|
fontSize: "0.85rem",
|
|
fontWeight: 500,
|
|
color: active ? "#18181b" : "#52525b",
|
|
background: active ? "#fff" : "transparent",
|
|
boxShadow: active ? "0 1px 2px rgba(0,0,0,0.05)" : "none",
|
|
border: active ? "1px solid #e4e4e7" : "1px solid transparent",
|
|
textDecoration: "none",
|
|
transition: "all 0.15s ease"
|
|
}}
|
|
>
|
|
<item.Icon size={16} color={active ? "#18181b" : "#a1a1aa"} />
|
|
{item.label}
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
<div style={{ flex: 1, minWidth: 0, overflow: "auto", background: "#fff", display: "flex", flexDirection: "column" }}>
|
|
{children}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|