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
+65
View File
@@ -0,0 +1,65 @@
"use client";
import { useEffect, useState } from "react";
import { Menu, User } from "lucide-react";
import { AdminSidebar } from "@/components/admin/AdminSidebar";
const SIDEBAR_STORAGE_KEY = "iamcavalli:sidebar";
/**
* Client shell for every /admin/* page: collapsible sidebar + top header +
* <main>. Collapse state is persisted to localStorage and read on mount
* (starts expanded on server/first paint to avoid a hydration mismatch,
* then reconciles client-side — mirrors the pattern used by useTheme).
*/
export function AdminShell({ children }: { children: React.ReactNode }) {
const [collapsed, setCollapsed] = useState(false);
useEffect(() => {
const stored = window.localStorage.getItem(SIDEBAR_STORAGE_KEY);
if (stored === "collapsed") setCollapsed(true);
}, []);
function toggleCollapsed() {
setCollapsed((prev) => {
const next = !prev;
window.localStorage.setItem(SIDEBAR_STORAGE_KEY, next ? "collapsed" : "expanded");
return next;
});
}
return (
<div className="flex min-h-screen bg-background">
<AdminSidebar collapsed={collapsed} />
<div className="flex-1 flex flex-col min-w-0">
{/* Top header bar */}
<header className="h-16 shrink-0 bg-card border-b border-border px-6 flex items-center justify-between">
<div className="flex items-center gap-4">
<button
type="button"
onClick={toggleCollapsed}
title="Espandi/Comprimi Sidebar"
aria-label="Espandi/Comprimi Sidebar"
className="p-2 -ml-2 rounded-lg text-muted-foreground hover:bg-muted hover:text-foreground transition-colors focus:outline-none"
>
<Menu className="w-5 h-5" />
</button>
<span className="text-xs font-medium text-muted-foreground">Area di Lavoro</span>
</div>
<div className="flex items-center gap-3">
<span className="text-xs font-semibold text-foreground">Admin</span>
{/* TODO: gestione utenti/collaboratori — placeholder avatar until
real user accounts + uploaded profile images are wired up. */}
<div className="w-8 h-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center shrink-0">
<User className="w-4 h-4" />
</div>
</div>
</header>
<main className="flex-1 px-8 py-8 overflow-y-auto">{children}</main>
</div>
</div>
);
}