| .vscode | ||
| dist | ||
| src | ||
| .agent | ||
| .gitignore | ||
| IA.md | ||
| index.html | ||
| package.json | ||
| pnpm-lock.yaml | ||
| README.md | ||
| tsconfig.app.json | ||
| tsconfig.build.json | ||
| tsconfig.json | ||
| vite.config.ts | ||
eli-vue — Design System (Vue 3 + TypeScript)
Biblioteca de componentes Vue 3 (Design System) para reutilização em múltiplos projetos.
Este README foi escrito para humanos e IAs: ele descreve o objetivo do repositório, regras, estrutura, fluxo de contribuição, comandos e um roadmap de melhorias.
Fonte da verdade (regras)
As regras oficiais do repositório estão no arquivo .agent.
Antes de propor mudanças:
- leia o
.agent - procure padrões já existentes no código
- atualize a documentação correspondente (README raiz e/ou README do componente)
Objetivos
- consistência visual e comportamental
- tipagem forte (TypeScript
strict) - documentação em português
- exemplos executáveis via playground
O que NÃO entra no contexto
node_modules/: dependências (não versionar; não usar como fonte da verdade)dist/: gerado no build (não versionar)
Arquitetura do repositório
src/
componentes/
botao/
EliBotao.vue
index.ts
README.md
campo/
EliInput.vue
index.ts
README.md
indicador/
EliBadge.vue
index.ts
README.md
data_hora/
EliDataHora.vue
index.ts
README.md
tipos/
botao.ts
campo.ts
indicador.ts
index.ts
playground/
App.vue
*.playground.vue
index.ts
Convenções (nomenclatura)
- Componentes usam prefixo
Eli(ex.:EliBotao,EliInput). - Pastas preferem português (ex.:
src/componentes/botao,src/componentes/campo). - Tipos compartilhados ficam em
src/tipos/. - Sem TSX; padrão SFC:
<template>+<script lang="ts">+defineComponent. anyé proibido.
Instalação
pnpm add eli-vue
Observação:
vueevuetifysão peerDependencies.
Instalação (projeto consumidor já usa Vuetify)
Se o seu projeto já está configurado com Vuetify 3, basta instalar este pacote:
pnpm add eli-vue
Dica: mantenha
vueevuetifyatualizados dentro das faixas suportadas.
Uso
1) Registro global (plugin)
import { createApp } from "vue";
import EliVue from "eli-vue";
import App from "./App.vue";
createApp(App).use(EliVue).mount("#app");
Exemplo completo (main.ts) — com Vuetify 3
Este é o modelo recomendado para projetos consumidores (Vite + Vue 3) que já usam Vuetify 3:
import { createApp } from "vue";
import App from "./App.vue";
// Vuetify
import "vuetify/styles";
import { createVuetify } from "vuetify";
// eli-vue (Design System)
import EliVue from "eli-vue";
import "eli-vue/dist/eli-vue.css";
const vuetify = createVuetify({
// opcional: componentes/directives/tema do seu projeto
});
createApp(App)
.use(vuetify)
.use(EliVue)
.mount("#app");
Nota: o
eli-vuenão cria nem configura Vuetify; ele assume que o consumidor já tem Vuetify.
2) Importação direta de componentes
import { EliBotao, EliInput, EliBadge, EliDataHora } from "eli-vue";
Exemplos rápidos de uso
EliBotao
<template>
<EliBotao @click="salvar">Salvar</EliBotao>
</template>
EliInput (v-model)
<template>
<EliInput v-model="nome" label="Nome" placeholder="Digite seu nome" />
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
setup() {
const nome = ref("");
return { nome };
},
});
</script>
EliBadge
<template>
<EliBadge badge="3">
<v-icon>mdi-bell</v-icon>
</EliBadge>
</template>
EliDataHora
Entrada/saída sempre em ISO 8601.
- Aceita UTC absoluto (
Z) ou com offset.- Emite ISO com offset local.
<template>
<EliDataHora v-model="agendamento" rotulo="Agendamento" />
<EliDataHora v-model="nascimento" modo="data" rotulo="Nascimento" />
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import { EliDataHora } from "eli-vue";
export default defineComponent({
components: { EliDataHora },
setup() {
const agendamento = ref<string | null>("2026-01-09T16:15:00Z");
const nascimento = ref<string | null>("2026-01-09T00:00:00-03:00");
return { agendamento, nascimento };
},
});
</script>
Troubleshooting (problemas comuns)
1) "Failed to resolve component" / componente não registrado
Você provavelmente esqueceu de:
- usar o plugin:
app.use(EliVue) - ou importar e registrar o componente localmente
2) Estilos não aplicam / layout estranho
Confirme que o consumidor importou:
vuetify/styleseli-vue/dist/eli-vue.css
3) Ícones não aparecem
Alguns exemplos usam <v-icon> com Material Design Icons. O eli-vue não instala ícones no seu projeto.
- garanta que o seu projeto consumidor está configurado com o pacote de ícones desejado (ex.: MDI)
- ou substitua o conteúdo do slot por outro elemento
Exemplo de composição (pipeline estilo Trello)
O caso mais comum no gestor de oportunidades e propostas comerciais é compor UI a partir de componentes básicos. Exemplo: um pipeline em colunas (estilo Trello/Kanban) com cards de oportunidades.
Este exemplo usa Vuetify para layout/containers e o
eli-vuepara inputs, botões e indicadores.
<template>
<v-container class="py-6">
<div class="toolbar">
<h2 class="text-h6">Pipeline de Oportunidades</h2>
<EliInput
v-model="filtro"
label="Buscar"
placeholder="Cliente, proposta, valor..."
density="compact"
/>
<EliBotao @click="criarOportunidade">Nova oportunidade</EliBotao>
</div>
<div class="colunas">
<section
v-for="coluna in colunas"
:key="coluna.id"
class="coluna"
>
<header class="coluna-header">
<strong>{{ coluna.titulo }}</strong>
<EliBadge :badge="coluna.itens.length" radius="pill" />
</header>
<div class="cards">
<v-card
v-for="item in itensFiltrados(coluna.itens)"
:key="item.id"
class="card"
variant="outlined"
>
<v-card-title class="d-flex justify-space-between align-center">
<span class="text-subtitle-2">{{ item.titulo }}</span>
<EliBadge
v-if="item.alerta"
dot
color="error"
:visible="true"
>
<span />
</EliBadge>
</v-card-title>
<v-card-text class="text-body-2">
<div><strong>Cliente:</strong> {{ item.cliente }}</div>
<div><strong>Valor:</strong> {{ item.valor }}</div>
<div><strong>Vencimento:</strong> {{ item.vencimento }}</div>
</v-card-text>
<v-card-actions>
<EliBotao variant="text" @click="abrir(item)">Abrir</EliBotao>
<EliBotao variant="text" color="secondary" @click="editar(item)">
Editar
</EliBotao>
</v-card-actions>
</v-card>
</div>
</section>
</div>
</v-container>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import { EliBadge, EliBotao, EliInput } from "eli-vue";
type Oportunidade = {
id: string;
titulo: string;
cliente: string;
valor: string;
vencimento: string;
alerta?: boolean;
};
type Coluna = {
id: string;
titulo: string;
itens: Oportunidade[];
};
export default defineComponent({
name: "PipelineExemplo",
components: { EliBadge, EliBotao, EliInput },
setup() {
const filtro = ref("");
const colunas = ref<Coluna[]>([
{
id: "novo",
titulo: "Novo",
itens: [
{
id: "1",
titulo: "Proposta #1024",
cliente: "ACME Ltda",
valor: "R$ 12.500,00",
vencimento: "10/01/2026",
alerta: true,
},
],
},
{
id: "negociacao",
titulo: "Negociação",
itens: [
{
id: "2",
titulo: "Oportunidade #204",
cliente: "Empresa X",
valor: "R$ 8.000,00",
vencimento: "15/01/2026",
},
],
},
{
id: "ganho",
titulo: "Ganho",
itens: [],
},
]);
function itensFiltrados(itens: Oportunidade[]) {
const q = filtro.value.trim().toLowerCase();
if (!q) return itens;
return itens.filter((i) =>
`${i.titulo} ${i.cliente} ${i.valor}`.toLowerCase().includes(q)
);
}
function criarOportunidade() {
// aqui você abriria um modal / rota de criação
}
function abrir(item: Oportunidade) {
// aqui você navega para detalhes da oportunidade
}
function editar(item: Oportunidade) {
// aqui você abre edição
}
return {
filtro,
colunas,
itensFiltrados,
criarOportunidade,
abrir,
editar,
};
},
});
</script>
<style scoped>
.toolbar {
display: grid;
grid-template-columns: 1fr minmax(260px, 420px) auto;
gap: 12px;
align-items: center;
margin-bottom: 16px;
}
.colunas {
display: grid;
gap: 16px;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.coluna {
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 12px;
padding: 12px;
background: rgba(0, 0, 0, 0.02);
}
.coluna-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.cards {
display: grid;
gap: 12px;
}
.card {
border-radius: 12px;
}
@media (max-width: 720px) {
.toolbar {
grid-template-columns: 1fr;
}
}
</style>
Como rodar localmente
Playground
pnpm dev
O playground (src/playground) valida visualmente variações e interações.
Build da lib + geração de tipos
pnpm run build
Gera dist/ (artefatos de build) e dist/types (declarações .d.ts).
Guia rápido para IAs (antes de codar)
- Leia
.agente este README. - Busque padrões antes de criar API nova (props/emits/slots).
- Não use
any. - Centralize tipos em
src/tipos/. - Ao mudar API/comportamento:
- atualize o
README.mddo componente - atualize ou crie um
*.playground.vue
- atualize o
- Rode
pnpm run buildantes de finalizar.
Como criar/alterar um componente (checklist)
- Criar pasta em
src/componentes/<nome_em_portugues>/ - Criar
EliNomeDoComponente.vuecomdefineComponent+ comentários úteis - Criar
index.tscom re-export (ex.:export { default as EliX } from './EliX.vue') - Criar
README.mddo componente (API, exemplos, casos de borda, A11y) - Criar playground em
src/playground/<nome>.playground.vue(mín. 3 variações) - Exportar no
src/index.ts
Critérios de aceite (qualidade)
pnpm run buildpassa (incluivue-tsc)- zero
any defineComponentem todos os componentes- README do componente atualizado quando API mudar
- playground demonstrando variações + interação
Roadmap de melhorias (a aplicar)
Curto prazo (qualidade / consistência)
- Padronizar comentários úteis em todos os componentes (explicar decisões e estados)
- Tipar
emitscom validação de payload (quando houver) - Consolidar nomenclatura de props/eventos em português (avaliar breaking changes)
Médio prazo (DX + segurança)
- Adicionar ESLint + Prettier e regras (incluindo proibição de
any) - Adicionar testes unitários com Vitest + @vue/test-utils
- Criar pipeline de CI rodando
pnpm run build
Longo prazo (docs e maturidade)
- Documentação visual (Storybook ou VitePress)
- Tokens de design (cores/spacing) e guideline de acessibilidade