components.md 9.8 KB

Design System — Componentes Base

Componentes em src/components/base/. São a base de toda a UI — sempre prefira esses componentes a elementos HTML nativos.


BaseButton

Arquivo: src/components/base/BaseButton.vue

Botão com suporte a variantes, tamanhos e estado de carregamento.

Props

Prop Tipo Padrão Valores aceitos
variant String "primary" "primary" · "secondary" · "ghost" · "danger"
size String "md" "sm" · "md" · "lg"
type String "button" "button" · "submit" · "reset"
disabled Boolean false
loading Boolean false Exibe spinner e bloqueia cliques

Variantes

Variante Uso
primary Ação principal da tela (submit, confirmar)
secondary Ação secundária, menos destaque
ghost Ação discreta, sem borda ou fundo visível
danger Ações destrutivas (excluir, revogar)

Exemplos

<BaseButton>Salvar</BaseButton>

<BaseButton variant="secondary" size="sm">Cancelar</BaseButton>

<BaseButton variant="danger" :loading="salvando" @click="excluir">
  Excluir
</BaseButton>

<BaseButton type="submit" :disabled="!formValido">Enviar</BaseButton>

BaseBadge

Arquivo: src/components/base/BaseBadge.vue

Chip/etiqueta para exibir status, categorias ou contadores.

Props

Prop Tipo Padrão Valores aceitos
variant String "default" "default" · "success" · "danger" · "info" · "warning" · "violet"

Variantes

Variante Cor Uso sugerido
default Cinza Status genérico, neutro
success Verde Ativo, aprovado, concluído
danger Vermelho Inativo, erro, bloqueado
info Azul Informação, em andamento
warning Âmbar Alerta, pendente
violet Violeta Destaque especial, admin

Exemplos

<BaseBadge variant="success">Ativo</BaseBadge>

<BaseBadge variant="danger">Inativo</BaseBadge>

<BaseBadge variant="violet">Admin</BaseBadge>

<BaseBadge>Padrão</BaseBadge>

BaseDropdown

Arquivo: src/components/base/BaseDropdown.vue

Select customizado (não nativo), acessível (role="listbox"/"option", aria-expanded/aria-haspopup), fecha ao clicar fora ou pressionar Esc. Compatível com v-model.

Props

Prop Tipo Padrão Descrição
modelValue String "" Valor selecionado (use com v-model)
rotulo String — (obrigatório) Texto exibido antes do valor selecionado
rotuloPadrao String — (obrigatório) Texto quando nenhuma opção está selecionada (ex: "todos")
opcoes Array [] Lista de { value, label }

Emite change além de update:modelValue, útil para disparar buscas ao selecionar.

Exemplo

<BaseDropdown
  v-model="filtroSetor"
  rotulo="Setor"
  rotulo-padrao="todos"
  :opcoes="setores.map((s) => ({ value: s.sigla, label: s.nome }))"
  @change="aplicarFiltros"
/>

StatCard

Arquivo: src/components/base/StatCard.vue

Cartão de métrica (KPI) com ícone, valor em destaque e texto complementar opcional.

Props

Prop Tipo Padrão Valores aceitos
label String — (obrigatório) Rótulo da métrica
value String \| Number null Valor em destaque
suffix String "" Sufixo do valor (ex: " / 10")
variant String "default" "default" · "success" · "danger" · "info" · "warning" · "violet"

O slot #icon recebe o ícone (ideal: <BaseIcon>); o slot padrão (default) recebe um texto complementar abaixo do valor.

Exemplo

<StatCard label="Score médio" :value="stats.scoreMedio" suffix=" / 10" variant="info">
  <template #icon><BaseIcon :icon="Star" class="h-4 w-4" /></template>
  {{ stats.pendentes }} pendentes
</StatCard>

BaseIcon

Arquivo: src/components/base/BaseIcon.vue

Wrapper fino sobre ícones do Lucide (lucide-vue-next). Sempre prefira importar o ícone diretamente da lib (mantém tree-shaking) e passá-lo via prop icon, em vez de SVG inline copiado manualmente.

Props

Prop Tipo Padrão Descrição
icon Object \| Function — (obrigatório) Componente do ícone importado de lucide-vue-next
strokeWidth String \| Number 1.8 Espessura do traço

Tamanho e cor são controlados via class (ex: class="h-4 w-4 text-primary"), igual a um SVG comum.

Exemplo

<script setup>
import { Search } from "lucide-vue-next";
import BaseIcon from "@/components/base/BaseIcon.vue";
</script>

<template>
  <BaseIcon :icon="Search" class="h-4 w-4 text-muted-foreground" />
</template>

BaseModal

Arquivo: src/components/base/BaseModal.vue

Casca comum para modais: Teleport para body, backdrop, fecha com Esc ou clique fora, foco movido para dentro do modal ao abrir e preso nele (focus trap) enquanto aberto.

Props

Prop Tipo Padrão Descrição
title String "" Título exibido no cabeçalho padrão
maxWidth String "max-w-md" Classe Tailwind de largura máxima do painel
closeOnBackdrop Boolean true Fecha ao clicar fora do painel
closeDisabled Boolean false Bloqueia fechamento (ex: enquanto envia um formulário)
showClose Boolean true Exibe o botão "×" no cabeçalho

Slots

Slot Descrição
header Substitui o cabeçalho padrão (título + botão fechar)
default Conteúdo do corpo do modal
footer Rodapé opcional, com borda separadora

Exemplo

<BaseModal title="Editar usuário" :close-disabled="salvando" @close="fechar">
  <form class="grid gap-4 p-5" @submit.prevent="salvar">
    ...
  </form>
</BaseModal>

EmptyState

Arquivo: src/components/base/EmptyState.vue

Estado vazio padronizado (ícone tracejado + título + descrição), usado no lugar de cada view escrever seu próprio bloco "Nenhum item encontrado".

Props

Prop Tipo Padrão Descrição
icon Object \| Function null Ícone do Lucide exibido no topo
titulo String — (obrigatório) Texto principal
descricao String "" Texto secundário opcional
compacto Boolean false Reduz o padding vertical (para uso dentro de listas menores)

O slot padrão aceita uma ação (ex: um BaseButton) abaixo do texto.

Exemplo

<EmptyState
  :icon="History"
  titulo="Nenhuma conversa ainda"
  descricao="Suas conversas aparecerão aqui após a primeira mensagem."
/>

Spinner

Arquivo: src/components/base/Spinner.vue

Indicador de carregamento padronizado, para substituir o texto solto "Carregando..." repetido em várias views.

Props

Prop Tipo Padrão Valores aceitos
size String "md" "sm" · "md" · "lg"
label String "" Texto exibido ao lado do spinner
center Boolean false Centraliza horizontalmente com padding vertical (para loading de seção inteira)

Exemplo

<Spinner v-if="carregando" center label="Carregando avaliações..." />

CampoBusca

Arquivo: src/components/base/CampoBusca.vue

Campo de busca das listagens: input[type=search] com ícone à esquerda e botão de limpar à direita quando há texto. Não confundir com SearchBox.vue, que é o painel de busca semântica da base de conhecimento.

Props

Prop Tipo Padrão Descrição
modelValue String "" Texto da busca (v-model)
placeholder String "Buscar..."

Eventos

update:modelValue · input (a cada digitação, para debounce) · enter · limpar

Exemplo

<CampoBusca
  v-model="filtroBusca"
  placeholder="Protocolo, cliente, atendente ou data (dd/mm/aaaa)"
  @input="onBuscaInput"
  @enter="onBuscaEnter"
  @limpar="onBuscaEnter"
/>

PaginacaoLista

Arquivo: src/components/base/PaginacaoLista.vue

Rodapé de paginação "Anterior / Página X de Y / Próxima". Some sozinho quando totalPaginas <= 1 — não precisa de v-if do lado de fora.

Props

Prop Tipo Padrão Descrição
page Number Página atual (1-based)
totalPaginas Number
desabilitado Boolean false Trava os botões enquanto carrega

Eventos

ir — emitido com a página destino.

Exemplo

<PaginacaoLista :page="page" :total-paginas="totalPaginas" :desabilitado="carregando" @ir="irParaPagina" />

ItemAvaliacao

Arquivo: src/components/atendimentos/ItemAvaliacao.vue

Card de uma avaliação de atendimento nas listagens (AvaliacoesView e NaoResolvidosView): cabeçalho com protocolo/cliente/setor/atendentes, a faixa de badges (nota, resolução, sentimento, visita, cancelamento, contexto ERP) e o corpo expandido com resumo, justificativa, motivo do cancelamento, itens a melhorar e visita técnica.

Props

Prop Tipo Padrão Descrição
avaliacao Object Item retornado por listarAvaliacoes()
prefixoId String Prefixo do id no DOM, para o scroll de retorno ("avaliacao", "nao-resolvido")
expandida Boolean false

Eventos

toggle e verConversa, ambos com o AtendimentoId.


Skeletons

Pasta: src/components/skeletons/

Componente Uso
SkeletonConversation.vue Placeholder de item de conversa na sidebar
SkeletonDocumentCard.vue Placeholder de card de documento na listagem

Exibidos durante o carregamento assíncrono, substituídos pelo conteúdo real quando os dados chegam.