Componentes em src/components/base/. São a base de toda a UI — sempre prefira esses componentes a elementos HTML nativos.
Arquivo: src/components/base/BaseButton.vue
Botão com suporte a variantes, tamanhos e estado de carregamento.
| 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 |
| 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) |
<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>
Arquivo: src/components/base/BaseBadge.vue
Chip/etiqueta para exibir status, categorias ou contadores.
| Prop | Tipo | Padrão | Valores aceitos |
|---|---|---|---|
variant |
String |
"default" |
"default" · "success" · "danger" · "info" · "warning" · "violet" |
| 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 |
<BaseBadge variant="success">Ativo</BaseBadge>
<BaseBadge variant="danger">Inativo</BaseBadge>
<BaseBadge variant="violet">Admin</BaseBadge>
<BaseBadge>Padrão</BaseBadge>
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.
| 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.
<BaseDropdown
v-model="filtroSetor"
rotulo="Setor"
rotulo-padrao="todos"
:opcoes="setores.map((s) => ({ value: s.sigla, label: s.nome }))"
@change="aplicarFiltros"
/>
Arquivo: src/components/base/StatCard.vue
Cartão de métrica (KPI) com ícone, valor em destaque e texto complementar opcional.
| 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.
<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>
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.
| 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.
<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>
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.
| 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 |
| 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 |
<BaseModal title="Editar usuário" :close-disabled="salvando" @close="fechar">
<form class="grid gap-4 p-5" @submit.prevent="salvar">
...
</form>
</BaseModal>
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".
| 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.
<EmptyState
:icon="History"
titulo="Nenhuma conversa ainda"
descricao="Suas conversas aparecerão aqui após a primeira mensagem."
/>
Arquivo: src/components/base/Spinner.vue
Indicador de carregamento padronizado, para substituir o texto solto "Carregando..." repetido em várias views.
| 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) |
<Spinner v-if="carregando" center label="Carregando avaliações..." />
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.
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
modelValue |
String |
"" |
Texto da busca (v-model) |
placeholder |
String |
"Buscar..." |
update:modelValue · input (a cada digitação, para debounce) · enter · limpar
<CampoBusca
v-model="filtroBusca"
placeholder="Protocolo, cliente, atendente ou data (dd/mm/aaaa)"
@input="onBuscaInput"
@enter="onBuscaEnter"
@limpar="onBuscaEnter"
/>
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.
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
page |
Number |
— | Página atual (1-based) |
totalPaginas |
Number |
— | |
desabilitado |
Boolean |
false |
Trava os botões enquanto carrega |
ir — emitido com a página destino.
<PaginacaoLista :page="page" :total-paginas="totalPaginas" :desabilitado="carregando" @ir="irParaPagina" />
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.
| 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 |
toggle e verConversa, ambos com o AtendimentoId.
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.