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/BaseInput.vue
Campo de texto com suporte a label, hint e mensagem de erro. Compatível com v-model.
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
modelValue |
String |
"" |
Valor do campo (use com v-model) |
label |
String |
"" |
Rótulo exibido acima do input |
hint |
String |
"" |
Texto de ajuda abaixo do campo |
error |
String |
"" |
Mensagem de erro (substitui hint quando preenchida) |
id |
String |
"" |
ID do input; gerado automaticamente se omitido |
Aceita todos os atributos HTML nativos de <input> via v-bind="$attrs" (ex: placeholder, type, autocomplete).
<BaseInput v-model="nome" label="Nome completo" placeholder="Ex: João Silva" />
<BaseInput
v-model="email"
label="E-mail"
type="email"
hint="Usado para login no sistema"
:error="erros.email"
/>
<BaseInput v-model="senha" label="Senha" type="password" />
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..." />
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.