Componenti veri. Tuoi fino all'ultima parte.
Tutto quello che vedi in questa pagina — i bottoni, le schede, le tabelle, la barra qui accanto — è fatto con i componenti che l'agente usa per la tua app. Si usano senza scrivere CSS, si piegano a sette livelli e i blocchi grandi parlano col backend da soli.
| Ordine | Cliente | Stato |
|---|---|---|
| 1042 | Rossi Srl | Pagato |
| 1047 | Bianchi & C. | In attesa |
| 1051 | Verdi Snc | Scaduto |
Una riga, e il componente è finito
Non c'è un foglio di stile da scrivere per avere una schermata che regge: i componenti leggono il tema del progetto — colori, carattere, raggio, densità, movimento — e portano da soli lo stato, il focus, il chiaro e lo scuro. Il tono di un riquadro lo prendono anche i bottoni che ci stanno dentro.
<Alert tone="danger" title="Pagamento rifiutato"
actions={<Button size="sm">Riprova</Button>}>
La carta è stata respinta dalla banca.
</Alert>
<Stat variant="card" label="Ordini" value="1.284"
delta="+12%" trend="up" icon="shopping-bag" />Il bottone «Riprova» non ha un tono scritto: è di pericolo perché sta in un riquadro di pericolo.
Sette livelli, dal valore di una prop a un tuo file
Ci si ferma dove basta. Ogni livello arriva un po' più in là del precedente e costa un po' di più; i primi quattro non toccano il codice di nessun componente.
Una prop
variant, tone e size hanno gli stessi valori in tutto il kit: imparati su un componente, valgono per tutti.
<Button variant="soft" tone="success">Salva</Button>
<Button variant="outline" size="lg" icon="plus">Nuovo</Button>
<Badge tone="warning" dot>In attesa</Badge>I predefiniti del tema
Il valore che una prop ha quando la pagina non lo scrive si cambia per tutto il progetto, una volta, nel theme.json. Le pagine restano come sono.
{
"components": {
"Tabs": { "variant": "line" },
"Button": { "pill": true }
}
}Un token
Ogni componente legge i propri token (--sp-card-pad, --sp-button-h…) con un ripiego. Si cambiano su :root per tutto il sito o su un contenitore per quello che ha dentro.
.vetrina {
--sp-card-pad: 1.75rem;
--sp-card-radius: 1.75rem;
--sp-button-h: 3rem;
--sp-button-px: 1.6rem;
}Il CSS delle parti
Ogni parte di un componente ha un indirizzo — [data-slot="card-header"], [data-variant="soft"], [data-state="open"] — e il CSS del kit pesa zero: una regola tua vince sempre, senza !important. Il catalogo elenca le parti di ogni componente.
.sala [data-slot="card-header"] {
background: linear-gradient(100deg,
color-mix(in oklab, var(--sp-primary) 22%, transparent), transparent);
}
.sala [data-slot="card-title"] {
font-family: var(--sp-font-mono);
letter-spacing: .08em;
text-transform: uppercase;
}
.sala [data-slot="badge"] { border-radius: 2px; }Una sola istanza
className sulla radice e classNames sulle parti toccano un componente solo, con le utility che già conosci.
<Card
icon="package"
title="Ordine 1042"
classNames={{ title: "font-heading text-xl italic", icon: "rotate-6" }}
className="border-primary/40"
/>Senza lo stile del kit
unstyled toglie tutto il CSS del kit da quell'istanza e dalle sue parti. Resta il comportamento: l'accessibilità, i gesti, gli stati.
<Button unstyled className="underline decoration-dotted underline-offset-4">
Informativa sulla privacy
</Button>Un tuo file al posto del suo
Un file con lo stesso nome di un componente del kit lo sostituisce — il .tsx e il .css —, e tutti gli altri componenti che lo usano usano il tuo. Per ciò che il kit non prevede, i componenti del progetto vivono nella stessa cartella.
client/_ui/button.tsx il tuo Button, in tutte le superfici
client/_ui/button.css e il suo aspetto
client/app/ui/card.tsx la tua Card, solo nella superficie «app»I blocchi grandi parlano col progetto da soli
Un modulo, una tabella di gestione, l'accesso, la chat con un agente: nella tua app sono una riga, perché sanno già con quale azione, tabella o agente del progetto parlare.
<ActionForm action="ordini.crea" />
Un campo per ogni input dell'azione, col controllo giusto per il suo tipo, i vincoli, gli errori del server messi sotto il campo che li ha causati e il messaggio di esito. Cambi l'azione e il modulo cambia.
// server/actions/ordini/crea.ts dichiara l'input; la pagina scrive una riga
<ActionForm action="ordini.crea" />
// o dispone i campi a mano, senza ridisegnarli
<ActionForm action="ordini.crea">
<Field name="cliente" />
<Field name="note" control="textarea" hint="Le vede solo il magazzino" />
</ActionForm>IVA esclusa
<ResourcePage … create="clienti.create" />
La schermata di gestione intera di una tabella: testata, filtri, elenco, creazione, modifica e cancellazione con il modulo generato dalle azioni, lo stato vuoto e quello d'errore, la paginazione; su un telefono le righe diventano schede. La lettura resta della pagina, la scrittura passa dalle azioni che nomini e un permesso che manca toglie il comando invece di spegnerlo.
const lista = useApiState("clienti.list", { page: pagina });
<ResourcePage
title="Clienti"
rows={lista.data?.items ?? []}
total={lista.data?.total}
columns={[{ key: "nome", label: "Nome", sortable: true }, { key: "citta" }, { key: "stato" }]}
create="clienti.create"
update="clienti.update"
remove="clienti.remove"
exportCsv
/>| Nome | Città | Stato |
|---|---|---|
| Rossi Srl | Torino | Attivo |
| Bianchi & C. | Bari | Sospeso |
| Verdi Snc | Lecce | Attivo |
<LoginForm />
L'accesso del progetto: i metodi che la superficie offre — password, codice via email, account Google — la registrazione, il recupero, il secondo fattore. Quello che cambia fra un progetto e l'altro è nel manifest della superficie, non nella pagina.
// client/app/accedi.tsx
export default definePage(function Accedi() {
return <AuthShell><LoginForm /></AuthShell>;
});<AgentChat agent="assistente" />
La conversazione con un agente del progetto: risposte che arrivano mentre vengono scritte, gli strumenti che l'agente usa mostrati riga per riga, le conversazioni salvate. L'agente lo descrivi come descrivi il resto; la chat c'è già.
// client/app/aiuto.tsx
<AgentChat agent="assistente" placeholder="Chiedi qualcosa sui tuoi ordini" />Qui i blocchi sono disegnati con le primitive del kit: un sito di presentazione non ha un backend a cui collegarli.
Altri blocchi che si collegano con una riga
Le parti di un prodotto che tutti riscrivono, già scritte e già collegate.
Ogni componente, in ogni variante
Una pagina sola che li mostra tutti nello stato in cui li trova la tua app, con le varianti, i toni e le parti che il catalogo dichiara. È lo stesso kit di questo sito.
Descrivi l'app. I componenti ci sono già.
L'agente li usa per te, e quando vuoi andare più a fondo sai a quale livello fermarti.