Galleria dell'interfaccia per i mod
Scopri gli elementi dell'interfaccia che un mod di Claude Code può disegnare, come testo, pulsanti, campi, Markdown, codice e diff, con codice di esempio e screenshot del terminale.
Un mod disegna la sua interfaccia a partire da elementi: testo, riquadri, pulsanti, campi e alcuni elementi che formattano il contenuto al posto tuo. Gli esempi qui mostrano il codice che disegna un elemento, e la maggior parte è accompagnata da uno screenshot del risultato in un riquadro del terminale, così puoi scegliere un elemento in base al suo aspetto.
Per capire come funziona il disegno, inizia da Disegnare nell'interfaccia. Per le prop principali e per sapere quali app disegnano ciascun elemento, consulta il riferimento degli elementi. Le dichiarazioni dei tipi elencano tutte le prop.
Prova un esempio
Gli esempi in questa pagina sono frammenti, non mod completi. Ognuno è il codice di un elemento e di tutto ciò che è annidato al suo interno.
Per vedere un esempio nel tuo terminale, crea il piccolo mod seguendo questi passaggi e incollaci l'esempio. Il mod aggiunge un comando /gallery che apre un riquadro e vi disegna l'esempio. Un riquadro è una barra laterale accanto alla trascrizione in un terminale a schermo intero sufficientemente largo, oppure, negli altri casi, un'area delimitata sopra il prompt.
Crea il mod
Crea una directory chiamata gallery con le directory .claude-plugin e hooks al suo interno. Crea un mod spiega i file.
Salva il manifest come gallery/.claude-plugin/plugin.json:
{
"name": "gallery",
"version": "0.1.0",
"description": "Opens a pane that draws one sample",
"author": { "name": "Your Name" }
}
Indica il tuo punto di ingresso in gallery/hooks/hooks.json:
{
"modules": ["./register.js"]
}
Salva il codice come gallery/hooks/register.js. Aggiunge un comando /gallery che apre un riquadro e disegna Plain text in quel riquadro:
// Stands in for your own callback in the samples that take one
const noop = () => {}
// The Select sample keeps its choice here
let picked = 'md'
// The Raster sample packs its cells with this function
const DEFAULT_COLOR = 0x01000000
function cellsOf(rows) {
const numbers = rows.flat().flatMap(([char, color]) => [char.codePointAt(0), color, DEFAULT_COLOR])
return new Uint8Array(Uint32Array.from(numbers).buffer).toBase64()
}
export function register(on) {
on('session.start', async ($, e, next) => {
await $.command.register({ name: 'gallery', description: 'Open the sample pane' })
return next(e)
})
on('command.run', { command: 'gallery' }, async ($) => {
await $.ui.open({ id: 'gallery', focus: true, closeOnEscape: true })
return {}
})
on('ui.render', { component: 'Pane' }, async ($, e, next) => {
if (e.requestId !== 'gallery') return next(e)
const { Box, Text, Button, Input, Select, Link, Markdown, Code, Raster, Svg } = $.ui.resolve(e)
// Replace the element after return with a sample
return Text({ children: ['Plain text'] })
})
}
Esegui il mod
Nella tua shell, avvia Claude Code dalla directory che contiene gallery:
claude --plugin-dir ./gallery
Al prompt di Claude Code, esegui /gallery. Si apre un riquadro con Plain text al suo interno.
Sostituisci con un esempio
Copia un esempio da questa pagina. In register.js, incollalo al posto di Text({ children: ['Plain text'] }), in modo che segua return, e salva il file. Claude Code ricarica il modulo ogni volta che salvi, quindi esegui di nuovo /gallery per vedere il nuovo esempio.
Scegli un elemento
Gli esempi sono raggruppati in base a ciò che vuoi mostrare sullo schermo:
- Mostrare testo:
Text,MarkdowneLink - Mostrare codice e modifiche:
Code - Disporre gli elementi:
Box - Ricevere input:
Button,InputeSelect - Disegnare immagini:
Raster,Svg,ImageeClient
Mostrare testo
Tre elementi mettono parole sullo schermo: Text per uno stile personalizzato, Markdown per contenuti già formattati e Link per un URL.
`Text`
Text disegna una stringa con gli stili che gli assegni. Questo esempio mostra una riga per ogni stile:
Box({
flexDirection: 'column',
children: [
Text({ children: ['Plain text'] }),
Text({ bold: true, children: ['bold'] }),
Text({ italic: true, children: ['italic'] }),
Text({ underline: true, children: ['underline'] }),
Text({ strikethrough: true, children: ['strikethrough'] }),
Text({ dimColor: true, children: ['dimColor'] }),
Text({ inverse: true, children: ['inverse'] }),
Text({ color: 'red', children: ["color: 'red'"] }),
Text({ backgroundColor: 'blue', children: ["backgroundColor: 'blue'"] }),
],
})
dimColor disegna il testo in grigio. backgroundColor riempie solo la larghezza del testo.
`Markdown`
Markdown formatta il testo nello stesso modo in cui vengono formattate le risposte di Claude. Passa il contenuto in text, non in children:
Markdown({
text: '## Release notes\n\nThis build has **two** fixes and one `flag`:\n\n- Faster start\n- Fewer prompts\n\n> Quoted text',
})
Un titolo viene disegnato in grassetto senza i simboli #. Il codice inline viene disegnato a colori senza i backtick. Una citazione viene disegnata in corsivo con una barra alla sua sinistra.
`Link`
Link disegna un'etichetta seguita dal suo URL:
Link({ href: 'https://code.claude.com/docs', label: 'Claude Code docs' })
Il terminale disegna l'URL come testo dopo l'etichetta. Il fatto che un clic lo apra dipende dal terminale dell'utente.
Mostrare codice e modifiche
Code disegna il testo sorgente con i colori di sintassi propri di Claude Code, oppure un diff.
`Code`
Specifica il language, oppure passa un path da cui Claude Code possa dedurlo. Con startLine, le righe vengono numerate a partire da quel numero:
Code({
language: 'javascript',
startLine: 1,
source: "const name = 'mods'\nconsole.log('hello ' + name)",
})
I colori provengono dal tema dell'utente.
`Code` come diff
Con format: 'diff', source è costituito da uno o più hunk di diff unificato:
Code({
format: 'diff',
source: '@@ -1,3 +1,3 @@\n # Mods\n-A mod is a plugin.\n+A mod is a plugin that runs code.\n Read on.',
})
Claude Code disegna i numeri di riga al posto della riga @@. Quando una riga rimossa e una riga aggiunta sono simili, le parole modificate ricevono un'ombreggiatura più intensa.
Disporre gli elementi
`Box`
Box dispone ciò che contiene in una riga o in una colonna e può disegnare un bordo. Questo esempio posiziona una riga di parole sopra un riquadro con bordo:
Box({
flexDirection: 'column',
gap: 1,
children: [
Box({
flexDirection: 'row',
columnGap: 4,
children: [Text({ children: ['a row'] }), Text({ children: ['of three'] }), Text({ children: ['items'] })],
}),
Box({
borderStyle: 'round',
paddingX: 1,
children: [Text({ children: ["borderStyle: 'round'"] })],
}),
],
})
Il bordo si estende fino alla larghezza del pannello.
Ricevere input
Button, Input e Select sono controlli: l'utente si sposta tra di essi con Tab e usa quello che ha il focus. Focus della tastiera e tasti di scelta rapida spiega quali tasti li raggiungono.
Aprire un pannello con focus: true assegna al pannello il focus della tastiera. Le lettere digitate raggiungono un Input una volta che ha il focus, quindi aggiungi autoFocus: true a un campo che deve ricevere la digitazione non appena il pannello si apre.
`Button`
Un pulsante esegue onPress. Questo esempio mostra la forma predefinita, un pulsante plain con un tasto di scelta rapida e uno attenuato:
Box({
flexDirection: 'column',
children: [
Button({ key: 'save', label: 'Save', onPress: noop }),
Button({ key: 'next', label: 'Next', hotkey: 'n', plain: true, onPress: noop }),
Button({ key: 'skip', label: 'Skip', dimColor: true, onPress: noop }),
],
})
Un pulsante che ha il focus viene disegnato in video inverso. Qui l'utente ha premuto Tab due volte:
`Input`
Un Input è un campo di testo su una riga che esegue onSubmit quando l'utente preme Invio:
Input({
key: 'title',
label: 'Title',
placeholder: 'Type a title and press Enter',
value: '',
submitLabel: 'save',
onSubmit: noop,
})
Senza il focus, il campo mostra la sua etichetta e il suo placeholder:
Con il focus, l'etichetta diventa in grassetto, compare un cursore e il submitLabel viene mostrato dopo ⏎:
La digitazione sostituisce il placeholder:
`Select`
Un Select consente all'utente di scegliere una tra diverse opzioni ed esegue onSelect con il value dell'opzione:
Select({
key: 'format',
label: 'Format',
value: picked,
options: [
{ value: 'md', label: 'Markdown' },
{ value: 'html', label: 'HTML' },
{ value: 'txt', label: 'Plain text' },
],
onSelect: (value) => {
picked = value
},
})
Da chiuso, mostra la sua etichetta e l'opzione corrente:
Da aperto, elenca le sue opzioni e ne evidenzia una:
Dopo che l'utente ha scelto un'opzione, l'elenco si chiude:
Disegnare immagini
`Raster`
Un Raster è una griglia di celle di caratteri colorate, per una mappa di calore, una sparkline o una plancia di gioco. Lo disegna il terminale. Questo esempio usa la funzione cellsOf del modulo iniziale, che comprime le celle nella stringa accettata da un Raster. Disegnare una griglia di celle colorate la spiega:
Raster({
key: 'grid',
columns: 3,
rows: 2,
cells: cellsOf([
[['█', 0x2e7d32], ['█', 0xf9a825], ['█', 0xc62828]],
[['█', 0x2e7d32], ['█', 0x2e7d32], ['█', 0xf9a825]],
]),
})
Un Raster arrotonda ogni colore a una tavolozza più ridotta, quindi 0x2e7d32 viene disegnato come #337733.
`Svg`
Un Svg disegna un documento SVG nell'app Desktop:
Svg({
alt: 'Three bars of rising height',
width: 120,
height: 60,
source:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 60"><rect x="10" y="40" width="20" height="20" fill="#2e7d32"/><rect x="50" y="25" width="20" height="35" fill="#f9a825"/><rect x="90" y="5" width="20" height="55" fill="#c62828"/></svg>',
})
Nel terminale, un riquadro che restituisce solo un Svg si apre vuoto. Per disegnare qualcos'altro lì, controlla e.surface e restituisci un albero diverso.
`Image` e `Client`
Altri due elementi non hanno un esempio qui. Image disegna un PNG o pixel grezzi nel terminale. Client è una regione disegnata da un tuo secondo file, per animazioni e input del puntatore. Il riferimento degli elementi elenca le loro prop.
A meno che Claude Code non rilevi che il terminale disegna immagini del protocollo grafico di kitty con segnaposto Unicode, l'utente vede il testo alt di un Image, attenuato, al posto dell'immagine. Scrivi un testo alt che si regga da solo. Il rilevamento viene eseguito all'avvio: riesce in kitty 0.28 o successivo e in Ghostty, una volta che il terminale risponde alla richiesta grafica di Claude Code, e fallisce in questi casi:
- Altri terminali: qualsiasi terminale che non sia uno di questi due, o che non risponda alla richiesta.
- tmux e screen: una sessione eseguita all'interno di tmux o screen, in qualsiasi terminale, kitty e Ghostty inclusi.
- Sessioni in background: ogni sessione in background, qualunque sia il terminale da cui è collegata.
Se gli utenti del tuo mod vedono il testo attenuato in un terminale che disegna effettivamente quelle immagini segnaposto, possono impostare CLAUDE_CODE_FORCE_TERMINAL_IMAGES su 1, il che salta il rilevamento. All'interno di tmux o screen questo non aiuta: il testo alt scompare e Claude Code invia l'immagine senza incapsularla per il passthrough di tmux o screen.
Scopri dove un mod può disegnare
Gli esempi disegnano tutti in un pannello. Un mod può anche disegnare in altri punti e chiamare Claude Code perché mostri qualcosa al posto suo:
- Pannello e banda: Scegli dove disegnare
- Le righe di Claude Code stesso, come lo spinner: Modifica ciò che Claude Code disegna già
- Toast, riga di stato e riga di log: Mostra qualcosa senza avviare un turno
- Finestra di dialogo con domanda: Trattieni una chiamata a uno strumento finché l'utente non decide
Passaggi successivi
- Disegna nell'interfaccia: crea un pannello con schede, passo dopo passo
- Testa un disegno: premi i tuoi pulsanti da un test
- Riferimento agli elementi: le prop principali di ogni elemento e le app che lo disegnano