feat: Quiet Luxury design system + Pipeline (ex-Lead) redesign

- Design system foundations: Plus Jakarta Sans font, shadow-card/radius
  tokens in @theme, design-reference/DESIGN-SYSTEM.md with component inventory
- Collapsible admin shell (AdminShell): smooth w-64<->w-20 sidebar, new top
  header with "Admin" + avatar placeholder, localStorage-persisted state
- Rename route /admin/leads -> /admin/pipeline (redirect stubs preserved),
  nav label Lead -> Pipeline; DB table unchanged
- Reusable primitives: StatusBadge, SearchInput, SegmentedToggle (dual-theme)
- Luxury restyle of lead table, kanban (6 stages + @dnd-kit intact), PageHeader
- Tokenize editable-cell / option-multi-select for dark-mode legibility

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 16:16:44 +02:00
parent 43cb7e7469
commit 86e1499e8f
34 changed files with 3134 additions and 231 deletions
+30 -11
View File
@@ -15,10 +15,11 @@ import {
FileText,
} from "lucide-react";
import ThemeToggle from "@/components/ThemeToggle";
import { cn } from "@/lib/utils";
const NAV_ITEMS = [
{ href: "/admin", label: "Dashboard", icon: LayoutDashboard, exact: true },
{ href: "/admin/leads", label: "Lead", icon: Zap },
{ href: "/admin/pipeline", label: "Pipeline", icon: Zap },
{ href: "/admin/clients", label: "Clienti", icon: Users },
{ href: "/admin/projects", label: "Progetti", icon: FolderOpen },
{ href: "/admin/preventivi", label: "Preventivi", icon: FileText },
@@ -27,17 +28,32 @@ const NAV_ITEMS = [
{ href: "/admin/impostazioni", label: "Impostazioni", icon: Settings },
];
export function AdminSidebar() {
export function AdminSidebar({ collapsed = false }: { collapsed?: boolean }) {
const pathname = usePathname();
const isActive = (href: string, exact?: boolean) =>
exact ? pathname === href : pathname === href || pathname.startsWith(href + "/");
// Text fades out immediately on collapse, but only fades back in once the
// width transition is underway on expand (avoids reflow mid-animation).
const textClass = cn(
"whitespace-nowrap transition-opacity duration-200 delay-150",
collapsed && "opacity-0 pointer-events-none delay-0"
);
return (
<aside className="w-56 shrink-0 min-h-screen bg-[#1A463C] flex flex-col">
<aside
className={cn(
"shrink-0 min-h-screen bg-[#1A463C] flex flex-col overflow-hidden",
"transition-[width] duration-350 ease-[cubic-bezier(0.4,0,0.2,1)]",
collapsed ? "w-20" : "w-64"
)}
>
{/* Logo */}
<div className="px-5 py-5 border-b border-white/10">
<span className="font-bold text-white tracking-tight text-sm">iamcavalli</span>
<span className={cn("font-bold text-white tracking-tight text-sm", textClass)}>
iamcavalli
</span>
</div>
{/* Nav links */}
@@ -48,14 +64,16 @@ export function AdminSidebar() {
<Link
key={href}
href={href}
className={`flex items-center gap-3 px-3 py-2 rounded-md text-sm transition-colors ${
title={collapsed ? label : undefined}
className={cn(
"flex items-center gap-3 px-3 py-2 rounded-md text-sm transition-colors",
active
? "bg-white/15 text-white font-medium"
: "text-white/65 hover:text-white hover:bg-white/10"
}`}
)}
>
<Icon size={16} strokeWidth={1.8} />
{label}
<Icon size={16} strokeWidth={1.8} className="shrink-0" />
<span className={textClass}>{label}</span>
</Link>
);
})}
@@ -64,15 +82,16 @@ export function AdminSidebar() {
{/* Theme + Logout */}
<div className="px-3 py-4 border-t border-white/10 flex flex-col gap-2">
<div className="flex items-center justify-between px-3">
<span className="text-xs text-white/50">Tema</span>
<span className={cn("text-xs text-white/50", textClass)}>Tema</span>
<ThemeToggle />
</div>
<button
onClick={() => signOut({ callbackUrl: "/admin/login" })}
title={collapsed ? "Esci" : undefined}
className="flex items-center gap-3 px-3 py-2 w-full rounded-md text-sm text-white/65 hover:text-white hover:bg-white/10 transition-colors"
>
<LogOut size={16} strokeWidth={1.8} />
Esci
<LogOut size={16} strokeWidth={1.8} className="shrink-0" />
<span className={textClass}>Esci</span>
</button>
</div>
</aside>