Avatar
templates/components/Avatar
O Avatar responde "quem é" no menor espaço possível: uma imagem circular que degrada graciosamente para iniciais (Fallback) e, na falha, para um ícone. Traz um selo no canto (Badge) para status/notificação e empilha sobrepostos em grupo (Group + "+N") — sempre representando identidade, nunca conteúdo genérico.
Base congelada
CN
ER
CN
LR
ER
Capacidades 8
Conteúdo
Indicador de presença
Mapeia um estado semântico (online/ausente/ocupado/offline/invisível) no…
Iniciais automáticas do nome
Deriva as iniciais a partir do…
Cascata de fallback (imagem → iniciais → ícone)
Trata o onerror que a base…
Contador de notificações
Exibe um número (mensagens/pendências) reusando o…
Empilhar com limite (+N automático)
No Avatar:Group, define quantos avatares aparecem;…
Ordem de sobreposição do grupo
Escolhe qual avatar fica por cima…
Comportamento
Tooltip de identidade
Ao passar o mouse/foco, revela nome…
Perfil clicável
Envolve o avatar num link/ação para…
Claude Code
Cole no Claude Code — ele acerta de primeira.
Avatar (UI) — Design System (Symfony UX Toolkit / shadcn)
BASE CONGELADA (não mude por instância): Forma circular (rounded-full), tamanhos sm/default/lg (size-6/8/10 via data-size), o anel/borda sutil (after:border-border; ring-2 ring-background no grupo), o Fallback em bg-muted/text-muted-foreground text-sm, o Badge fixado no canto com ring-2, a sobreposição -space-x-2 do Group, o aspect-square/object-cover da imagem e a semântica/a11y (alt obrigatório, select-none). Ligar/desligar qualquer capacidade não altera nada disso — só comportamento e conteúdo aditivo dentro dos slots já existentes.
USO: <twig:Avatar size="default" />
CAPACIDADES OPT-IN (ligue sem alterar o visual):
- Indicador de presença: Mapeia um estado semântico (online/ausente/ocupado/offline/invisível) no Avatar:Badge do canto — reusa o selo congelado, muda só a cor semântica do estado (precedente: Status da Tabela). [select → Online / Ausente / Ocupado / Offline / Invisível]- Iniciais automáticas do nome: Deriva as iniciais a partir do nome completo (ex.: 'Bruno Peters' → 'BP'), 1-2 letras em caixa alta, e preenche o Avatar:Fallback — sem digitar 'BP' à mão, sem tocar no visual do fallback. [text]- Cascata de fallback (imagem → iniciais → ícone): Trata o onerror que a base do Image não cobre: se a URL quebra (404/offline), cai para iniciais e, sem iniciais, para um ícone genérico de usuário — sem imagem quebrada. [select → Iniciais / Ícone de usuário / Iniciais e depois ícone]- Contador de notificações: Exibe um número (mensagens/pendências) reusando o Avatar:Badge como selo numérico, distinto do status de presença; conteúdo aditivo dentro do selo congelado. [number]- Tooltip de identidade: Ao passar o mouse/foco, revela nome e cargo do avatar reusando o componente Tooltip — desambigua rostos em grupos sem rótulo permanente ocupando espaço. [toggle]- Perfil clicável: Envolve o avatar num link/ação para o perfil, adicionando papel interativo, foco e teclado (a11y) — sem alterar o anel de foco, que já é convenção da base. [text]- Empilhar com limite (+N automático): No Avatar:Group, define quantos avatares aparecem; o excedente é resumido automaticamente no Avatar:GroupCount ('+N') — truncamento comportamental reusando os slots do grupo. [number]- Ordem de sobreposição do grupo: Escolhe qual avatar fica por cima na pilha sobreposta (primeiro na frente ou último na frente) — apenas z-index, sem mexer no -space-x-2 nem no anel congelados. [select → Primeiro na frente / Último na frente]FAÇA:
- Use <twig:Nome> — a base é congelada, você é dono do template em templates/components/.
- Ligue apenas capacidades opt-in listadas (e_funcao=true); a aparência não muda ao ligá-las.
- Passe atributos extras (id, aria-*, name, data-*) via {{ attributes }}.
NÃO FAÇA:
- Não mude cor/fonte/cantos/espaçamento por instância — é decisão de BASE, na fonte única assets/styles/app.css.
- Não crie variante/fork para a mesma coisa — existe UMA base por componente.
- Não reimplemente o componente nem adicione toolchain Node.
TESTE ANTES DE MUDAR: "é função ou é base?" — função = capacidade opt-in; base = mude o token na fonte única (assets/styles/app.css), para todos.
A11Y (herdada da base): ring-2 ring-background no grupo), o Fallback em bg-muted/text-muted-foreground text-sm, o Badge fixado no canto com ring-2, a sobreposição -space-x-2 do Group, o aspect-square/object-cover da imagem e a semântica/a11y (alt obrigatório, select-none)
LLM / MCP
Via MCP: tool get_component com {"id": "avatar"} · list_capabilities("avatar").
Spec crua: config/ds-specs/avatar.json · Conectar o MCP.
Spec machine-readable (JSON)
{
"$schema_version": "1.0",
"id": "avatar",
"component": "Avatar",
"eixo": "ui",
"particularidade": "O Avatar responde \"quem é\" no menor espaço possível: uma imagem circular que degrada graciosamente para iniciais (Fallback) e, na falha, para um ícone. Traz um selo no canto (Badge) para status/notificação e empilha sobrepostos em grupo (Group + \"+N\") — sempre representando identidade, nunca conteúdo genérico.",
"base_congelada": "Forma circular (rounded-full), tamanhos sm/default/lg (size-6/8/10 via data-size), o anel/borda sutil (after:border-border; ring-2 ring-background no grupo), o Fallback em bg-muted/text-muted-foreground text-sm, o Badge fixado no canto com ring-2, a sobreposição -space-x-2 do Group, o aspect-square/object-cover da imagem e a semântica/a11y (alt obrigatório, select-none). Ligar/desligar qualquer capacidade não altera nada disso — só comportamento e conteúdo aditivo dentro dos slots já existentes.",
"props": [
{
"name": "size",
"type": "'default'|'sm'|'lg'",
"default": "default",
"description": "The avatar size. Defaults to `default` #}"
}
],
"capacidades": [
{
"id": "indicador-de-presen-a",
"nome": "Indicador de presença",
"descricao": "Mapeia um estado semântico (online/ausente/ocupado/offline/invisível) no Avatar:Badge do canto — reusa o selo congelado, muda só a cor semântica do estado (precedente: Status da Tabela).",
"controle": "select",
"opcoes": [
"Online",
"Ausente",
"Ocupado",
"Offline",
"Invisível"
],
"posicionavel": true,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/avatar; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "iniciais-autom-ticas-do-nome",
"nome": "Iniciais automáticas do nome",
"descricao": "Deriva as iniciais a partir do nome completo (ex.: 'Bruno Peters' → 'BP'), 1-2 letras em caixa alta, e preenche o Avatar:Fallback — sem digitar 'BP' à mão, sem tocar no visual do fallback.",
"controle": "text",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (text). Ligue no configurador em /vitrine/ui/avatar; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "cascata-de-fallback-imagem-iniciais-cone",
"nome": "Cascata de fallback (imagem → iniciais → ícone)",
"descricao": "Trata o onerror que a base do Image não cobre: se a URL quebra (404/offline), cai para iniciais e, sem iniciais, para um ícone genérico de usuário — sem imagem quebrada.",
"controle": "select",
"opcoes": [
"Iniciais",
"Ícone de usuário",
"Iniciais e depois ícone"
],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/avatar; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "contador-de-notifica-es",
"nome": "Contador de notificações",
"descricao": "Exibe um número (mensagens/pendências) reusando o Avatar:Badge como selo numérico, distinto do status de presença; conteúdo aditivo dentro do selo congelado.",
"controle": "number",
"opcoes": [],
"posicionavel": true,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (number). Ligue no configurador em /vitrine/ui/avatar; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "tooltip-de-identidade",
"nome": "Tooltip de identidade",
"descricao": "Ao passar o mouse/foco, revela nome e cargo do avatar reusando o componente Tooltip — desambigua rostos em grupos sem rótulo permanente ocupando espaço.",
"controle": "toggle",
"opcoes": [],
"posicionavel": true,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/avatar; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "perfil-clic-vel",
"nome": "Perfil clicável",
"descricao": "Envolve o avatar num link/ação para o perfil, adicionando papel interativo, foco e teclado (a11y) — sem alterar o anel de foco, que já é convenção da base.",
"controle": "text",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (text). Ligue no configurador em /vitrine/ui/avatar; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "empilhar-com-limite-n-autom-tico",
"nome": "Empilhar com limite (+N automático)",
"descricao": "No Avatar:Group, define quantos avatares aparecem; o excedente é resumido automaticamente no Avatar:GroupCount ('+N') — truncamento comportamental reusando os slots do grupo.",
"controle": "number",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (number). Ligue no configurador em /vitrine/ui/avatar; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "ordem-de-sobreposi-o-do-grupo",
"nome": "Ordem de sobreposição do grupo",
"descricao": "Escolhe qual avatar fica por cima na pilha sobreposta (primeiro na frente ou último na frente) — apenas z-index, sem mexer no -space-x-2 nem no anel congelados.",
"controle": "select",
"opcoes": [
"Primeiro na frente",
"Último na frente"
],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/avatar; comportamento via controller Stimulus. Não altera a base."
}
],
"snippet_uso": "<twig:Avatar size=\"default\" />",
"exemplo_demo": "<div class=\"flex flex-row flex-wrap items-center gap-6 md:gap-12\">\n <twig:Avatar>\n <twig:Avatar:Image\n src=\"https://github.com/shadcn.png\"\n alt=\"@shadcn\"\n class=\"grayscale\"\n />\n <twig:Avatar:Fallback>CN</twig:Avatar:Fallback>\n </twig:Avatar>\n <twig:Avatar>\n <twig:Avatar:Image src=\"https://github.com/evilrabbit.png\" alt=\"@evilrabbit\" />\n <twig:Avatar:Fallback>ER</twig:Avatar:Fallback>\n <twig:Avatar:Badge class=\"bg-green-600 dark:bg-green-800\" />\n </twig:Avatar>\n <twig:Avatar:Group class=\"grayscale\">\n <twig:Avatar>\n <twig:Avatar:Image src=\"https://github.com/shadcn.png\" alt=\"@shadcn\" />\n <twig:Avatar:Fallback>CN</twig:Avatar:Fallback>\n </twig:Avatar>\n <twig:Avatar>\n <twig:Avatar:Image src=\"https://github.com/maxleiter.png\" alt=\"@maxleiter\" />\n <twig:Avatar:Fallback>LR</twig:Avatar:Fallback>\n </twig:Avatar>\n <twig:Avatar>\n <twig:Avatar:Image src=\"https://github.com/evilrabbit.png\" alt=\"@evilrabbit\" />\n <twig:Avatar:Fallback>ER</twig:Avatar:Fallback>\n </twig:Avatar>\n <twig:Avatar:GroupCount>+3</twig:Avatar:GroupCount>\n </twig:Avatar:Group>\n</div>",
"regras": {
"faca": [
"Use <twig:Nome> — a base é congelada, você é dono do template em templates/components/.",
"Ligue apenas capacidades opt-in listadas (e_funcao=true); a aparência não muda ao ligá-las.",
"Passe atributos extras (id, aria-*, name, data-*) via {{ attributes }}."
],
"nao_faca": [
"Não mude cor/fonte/cantos/espaçamento por instância — é decisão de BASE, na fonte única assets/styles/app.css.",
"Não crie variante/fork para a mesma coisa — existe UMA base por componente.",
"Não reimplemente o componente nem adicione toolchain Node."
]
},
"a11y": "ring-2 ring-background no grupo), o Fallback em bg-muted/text-muted-foreground text-sm, o Badge fixado no canto com ring-2, a sobreposição -space-x-2 do Group, o aspect-square/object-cover da imagem e a semântica/a11y (alt obrigatório, select-none)",
"mcp": {
"tool": "get_component",
"args": {
"id": "avatar"
}
}
}