diff --git a/design-reference/DESIGN-SYSTEM.md b/design-reference/DESIGN-SYSTEM.md index a41750d..3540dc0 100644 --- a/design-reference/DESIGN-SYSTEM.md +++ b/design-reference/DESIGN-SYSTEM.md @@ -239,6 +239,30 @@ Griglia responsive di card `bg-card rounded-xl border-border p-6 shadow-card` (Tier · Servizi · Pubblico), righe `font-mono` `divide-y divide-border`; solo i tier con `servicesTotal > 0` o `public_price` valorizzato; "Pubblico" assente → `—`. +### Catalogo (griglia servizi) notes + +`/admin/catalog` migrata a "Quiet Luxury" (replica `design-reference/pagina-catalogo`). +È una griglia editabile in stile foglio di calcolo: `ServiceTable` in un contenitore +`bg-card rounded-xl border-border shadow-card overflow-hidden`, header uppercase muted +(`text-[11px] font-semibold uppercase tracking-wider text-muted-foreground`, `bg-muted/50`), +righe `hover:bg-muted/40` / `divide` via `border-border`. + +- **Celle inline**: nome/descrizione/prezzo/stato usano `EditableCell`; fase usa + `OptionSelect`; offerta/pacchetto usano `OptionMultiSelect`. I badge fase/offerta/ + pacchetto sono colorati deterministicamente via `getOptionColor` (hash → palette a 7 + colori) — nessun colore semantico fisso, coerente col sistema tag del resto dell'app. +- **Colonne**: riordinabili via drag (`GripVertical` on hover) e ordinabili sulle colonne + `sortable` (`ArrowUp/Down` in `text-primary`); ordine persistito in `localStorage` + (`catalog_col_order`). +- **Quick-add**: ultima riga `bg-muted/40` con input inline (`+ Aggiungi servizio`, prezzo, + fase datalist) — Invio ↵ crea il servizio. Servizi disattivati raggruppati sotto un header + `bg-muted/40` e resi `opacity-50`. +- **Search**: `SearchInput` primitivo (non più input+icona inline) su nome/categoria/fase/ + tag/pacchetto. Footer tabella "Visualizzazione di N servizi" (singolare/plurale). +- **Nota primitivi**: in questa pass `OptionSelect` ed `EditableCell` (`accent-primary`) + sono stati tokenizzati — erano rimasti con hex hardcoded mentre `OptionMultiSelect` era + già token-based. Il fix vale per tutte le pagine che li usano (Offerte, Lead). + ### Client Portal restyle notes The `/client/[token]` portal was migrated to the same "Quiet Luxury" tokens diff --git a/src/app/admin/catalog/CatalogSearch.tsx b/src/app/admin/catalog/CatalogSearch.tsx index e31c08a..b870538 100644 --- a/src/app/admin/catalog/CatalogSearch.tsx +++ b/src/app/admin/catalog/CatalogSearch.tsx @@ -1,8 +1,7 @@ "use client"; import { useState, useMemo, useRef } from "react"; -import { Input } from "@/components/ui/input"; -import { Search } from "lucide-react"; +import { SearchInput } from "@/components/ui/SearchInput"; import { ServiceTable, DEFAULT_COL_ORDER } from "@/components/admin/catalog/ServiceTable"; import type { ColumnKey } from "@/components/admin/catalog/ServiceTable"; import type { ServiceWithTags, CatalogFieldOptions } from "@/lib/admin-queries"; @@ -124,16 +123,12 @@ export function CatalogSearch({ return (
-
- - setQuery(e.target.value)} - className="pl-9 h-9" - /> -
+ setQuery(e.target.value)} + containerClassName="max-w-sm" + /> - +
); diff --git a/src/components/admin/catalog/ServiceTable.tsx b/src/components/admin/catalog/ServiceTable.tsx index 9521c0d..e1ae0a7 100644 --- a/src/components/admin/catalog/ServiceTable.tsx +++ b/src/components/admin/catalog/ServiceTable.tsx @@ -73,7 +73,7 @@ function ServiceRow({ switch (key) { case "nome": return ( - + + @@ -218,7 +218,7 @@ function QuickAddRow({ } const cellInput = - "border-0 bg-transparent shadow-none h-8 text-sm placeholder:text-[#71717a] focus-visible:ring-1 focus-visible:ring-primary"; + "border-0 bg-transparent shadow-none h-8 text-sm placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-primary"; function renderCell(key: ColumnKey) { switch (key) { @@ -279,18 +279,18 @@ function QuickAddRow({ ); case "stato": return ( - + Invio ↵ ); default: - return ; + return ; } } return ( <> - + {colOrder.map((key) => renderCell(key))} {error && ( @@ -331,15 +331,17 @@ export function ServiceTable({ if (!COLUMN_DEFS[colKey].sortable) return null; if (sortKey !== colKey) return ; return sortDir === "asc" - ? - : ; + ? + : ; } + const totalCount = activeServices.length + inactiveServices.length; + return ( -
+
- + {colOrder.map((key) => { const def = COLUMN_DEFS[key]; @@ -351,8 +353,8 @@ export function ServiceTable({ onDragOver={(e) => onColDragOver(e, key)} onDrop={() => onColDrop(key)} onClick={() => def.sortable && onSortClick(key)} - className={`text-left py-2 px-3 font-semibold text-[#71717a] select-none whitespace-nowrap group ${ - def.sortable ? "cursor-pointer hover:text-[#1a1a1a]" : "cursor-grab" + className={`text-left py-3 px-3 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground select-none whitespace-nowrap group ${ + def.sortable ? "cursor-pointer hover:text-foreground" : "cursor-grab" }`} style={{ minWidth: def.minWidth }} > @@ -373,10 +375,10 @@ export function ServiceTable({ {inactiveServices.length > 0 && ( <> - + @@ -389,6 +391,11 @@ export function ServiceTable({
Servizi disattivati
+
+ {totalCount === 1 + ? "Visualizzazione di 1 servizio" + : `Visualizzazione di ${totalCount} servizi`} +
); } diff --git a/src/components/ui/editable-cell.tsx b/src/components/ui/editable-cell.tsx index 4239597..4f94a3e 100644 --- a/src/components/ui/editable-cell.tsx +++ b/src/components/ui/editable-cell.tsx @@ -146,7 +146,7 @@ export function EditableCell({ // WR-01: onChange already saves + closes — a blur-commit here would // fire a second (possibly stale) updateServiceField for the same field. onKeyDown={(e) => { if (e.key === "Escape") cancel(); }} - className="h-4 w-4 cursor-pointer accent-[#1A463C]" + className="h-4 w-4 cursor-pointer accent-primary" /> ) : ( !disabled && setIsOpen((v) => !v)} className={cn( "flex items-center gap-1 px-2 py-1 rounded transition-colors duration-150 min-h-[28px]", - disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:bg-[#f0f0f0]" + disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:bg-muted" )} > {value ? ( @@ -91,12 +91,12 @@ export function OptionSelect({ {value} ) : ( - + )}
{isOpen && ( -
+
Rimuovi @@ -154,7 +154,7 @@ export function OptionSelect({ ) : (
)}