style: rifinitura Quiet Luxury dashboard — bordi soft, badge, colori
Allinea la dashboard alla rifinitura del mock (finezza bordi/colori/badge): - Card su border-border-light (slate-100) per il bordo sottile - KPI: valore verde su Incassato Reale, delta verde "+N questo mese" su Clienti Attivi (nuova metrica getDashboardStats.clientiNuoviMese) - Redditività: badge "Ottimo" con tint emerald soft (non brand primary) - Follow-up: righe come box bordati (no avatar), link "Apri →" primary - Forecast: selettore anno (pill interattiva) spostato nell'header della card, barre non-picco grigie (bg-border), rimosso il numero "mese prossimo" - Offerte Più Richieste: rimossa la pill totale nell'header Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+26
-28
@@ -17,32 +17,34 @@ export const revalidate = 0;
|
||||
function MetricCard({
|
||||
label,
|
||||
value,
|
||||
valueAccent,
|
||||
delta,
|
||||
sub,
|
||||
positive,
|
||||
}: {
|
||||
label: string;
|
||||
value: string;
|
||||
valueAccent?: boolean;
|
||||
delta?: string;
|
||||
sub?: string;
|
||||
positive?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className="bg-card p-5 rounded-xl border border-border shadow-card">
|
||||
<div className="bg-card p-5 rounded-xl border border-border-light shadow-card">
|
||||
<span className="text-[10px] uppercase font-bold text-muted-foreground tracking-wider">
|
||||
{label}
|
||||
</span>
|
||||
<div className="flex items-baseline gap-2 mt-1">
|
||||
<span className="text-2xl font-bold text-foreground font-mono">{value}</span>
|
||||
{sub && (
|
||||
<span
|
||||
className={`text-xs ${
|
||||
positive
|
||||
? "font-medium text-emerald-600 dark:text-emerald-400"
|
||||
: "text-muted-foreground"
|
||||
}`}
|
||||
>
|
||||
{sub}
|
||||
</span>
|
||||
)}
|
||||
<span
|
||||
className={`text-2xl font-bold font-mono ${
|
||||
valueAccent ? "text-emerald-700 dark:text-emerald-400" : "text-foreground"
|
||||
}`}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
{delta ? (
|
||||
<span className="text-xs font-medium text-emerald-600 dark:text-emerald-400">{delta}</span>
|
||||
) : sub ? (
|
||||
<span className="text-xs text-muted-foreground">{sub}</span>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -80,14 +82,14 @@ export default async function AdminDashboard({
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-8">
|
||||
{/* Toolbar: selettore anno (governa i KPI year-scoped + redditività) */}
|
||||
<div className="flex items-center justify-end">
|
||||
<YearSelector currentYear={year} />
|
||||
</div>
|
||||
|
||||
{/* KPI strip */}
|
||||
<section className="grid grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<MetricCard label="Clienti Attivi" value={String(kpi.clientiAttivi)} sub="Totale corrente" />
|
||||
<MetricCard
|
||||
label="Clienti Attivi"
|
||||
value={String(kpi.clientiAttivi)}
|
||||
delta={kpi.clientiNuoviMese > 0 ? `+${kpi.clientiNuoviMese} questo mese` : undefined}
|
||||
sub="Totale corrente"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Contrattualizzato"
|
||||
value={fmtEur0(data.contracted)}
|
||||
@@ -96,21 +98,17 @@ export default async function AdminDashboard({
|
||||
<MetricCard
|
||||
label="Incassato Reale"
|
||||
value={fmtEur0(data.collected)}
|
||||
valueAccent={data.collected > 0}
|
||||
sub={`${collectedPct}% del totale`}
|
||||
positive={data.collected > 0}
|
||||
/>
|
||||
<MetricCard
|
||||
label="Ore Tracciate"
|
||||
value={`${totalHours}h`}
|
||||
sub="Su progetti attivi"
|
||||
/>
|
||||
<MetricCard label="Ore Tracciate" value={`${totalHours}h`} sub="Su progetti attivi" />
|
||||
</section>
|
||||
|
||||
{/* Griglia contenuti: 2/3 + 1/3 */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Colonna 2/3 */}
|
||||
<div className="lg:col-span-2 flex flex-col gap-8">
|
||||
<ForecastChart data={forecast} />
|
||||
<ForecastChart data={forecast} headerAction={<YearSelector currentYear={year} />} />
|
||||
<ClientProfitability data={profitability} />
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user