chore: alinhar projeto às regras do agent
This commit is contained in:
parent
86d451efa1
commit
51a48eee70
36 changed files with 485 additions and 208 deletions
11
.agent
11
.agent
|
|
@ -24,8 +24,9 @@ Construir um Design System de componentes em **Vue 3** para reutilização em m
|
||||||
- **Variáveis, nomes de arquivos e nomes de pastas em português sempre que possível**
|
- **Variáveis, nomes de arquivos e nomes de pastas em português sempre que possível**
|
||||||
- Ex.: `botao`, `cartao`, `campo_texto`, `seletor_opcoes`
|
- Ex.: `botao`, `cartao`, `campo_texto`, `seletor_opcoes`
|
||||||
- Evitar abreviações confusas
|
- Evitar abreviações confusas
|
||||||
- Nomes de componentes (PascalCase) podem seguir padrão técnico, mas preferir português:
|
- Nomes de componentes (PascalCase) podem seguir padrão técnico:
|
||||||
- `BotaoPrimario.vue`, `CartaoInfo.vue`, `CampoTexto.vue`
|
- **Padrão do repositório:** componentes com prefixo `Eli` (ex.: `EliBotao`, `EliInput`).
|
||||||
|
- Pastas preferem português (ex.: `src/componentes/botao/`, `src/componentes/campo/`).
|
||||||
- Props e eventos: preferir português e sem ambiguidades:
|
- Props e eventos: preferir português e sem ambiguidades:
|
||||||
- Props: `rotulo`, `desabilitado`, `carregando`, `modeloValor`
|
- Props: `rotulo`, `desabilitado`, `carregando`, `modeloValor`
|
||||||
- Eventos: `update:modelValue`, `confirmar`, `cancelar`, `clicar`
|
- Eventos: `update:modelValue`, `confirmar`, `cancelar`, `clicar`
|
||||||
|
|
@ -45,11 +46,11 @@ Estrutura sugerida:
|
||||||
src/
|
src/
|
||||||
componentes/
|
componentes/
|
||||||
botao/
|
botao/
|
||||||
Botao.vue
|
EliBotao.vue
|
||||||
index.ts
|
index.ts
|
||||||
README.md
|
README.md
|
||||||
cartao/
|
cartao/
|
||||||
Cartao.vue
|
EliCartao.vue
|
||||||
index.ts
|
index.ts
|
||||||
README.md
|
README.md
|
||||||
playground/
|
playground/
|
||||||
|
|
@ -134,7 +135,7 @@ Evitar comentários óbvios (“isso é um botão”).
|
||||||
|
|
||||||
## Regras de exportação e reuso
|
## Regras de exportação e reuso
|
||||||
- Cada pasta do componente deve ter `index.ts` exportando o componente:
|
- Cada pasta do componente deve ter `index.ts` exportando o componente:
|
||||||
- `export { default as Botao } from "./Botao.vue"`
|
- `export { default as EliBotao } from "./EliBotao.vue"`
|
||||||
- `src/index.ts` deve exportar todos os componentes publicamente
|
- `src/index.ts` deve exportar todos os componentes publicamente
|
||||||
- Não exportar itens internos não documentados
|
- Não exportar itens internos não documentados
|
||||||
|
|
||||||
|
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
||||||
node_modules
|
node_modules
|
||||||
|
dist
|
||||||
|
|
|
||||||
64
README.md
64
README.md
|
|
@ -1,5 +1,63 @@
|
||||||
# Vue 3 + TypeScript + Vite
|
# eli-vue — Design System (Vue 3 + TypeScript)
|
||||||
|
|
||||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
Biblioteca de componentes Vue 3 (Design System) para reutilização em múltiplos projetos, com foco em:
|
||||||
|
|
||||||
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
- consistência visual e comportamental
|
||||||
|
- tipagem forte (TypeScript `strict`)
|
||||||
|
- documentação em português
|
||||||
|
- exemplos executáveis via playground
|
||||||
|
|
||||||
|
As regras do repositório estão descritas em **`.agent`**.
|
||||||
|
|
||||||
|
## Instalação
|
||||||
|
|
||||||
|
Como dependência do projeto:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm add eli-vue
|
||||||
|
```
|
||||||
|
|
||||||
|
> Observação: `vue` e `vuetify` são **peerDependencies**. Garanta que seu projeto já os tenha instalados.
|
||||||
|
|
||||||
|
## Uso
|
||||||
|
|
||||||
|
### 1) Registro global (plugin)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { createApp } from "vue";
|
||||||
|
import EliVue from "eli-vue";
|
||||||
|
|
||||||
|
import App from "./App.vue";
|
||||||
|
|
||||||
|
createApp(App).use(EliVue).mount("#app");
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2) Importação direta de componentes
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { EliBotao, EliInput, EliBadge } from "eli-vue";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Convenções do projeto
|
||||||
|
|
||||||
|
- Componentes usam **prefixo `Eli`** (ex.: `EliBotao`, `EliInput`).
|
||||||
|
- Pastas seguem **português** (ex.: `src/componentes/botao`, `src/componentes/campo`, `src/componentes/indicador`).
|
||||||
|
- Sem TSX; padrão SFC: `<template>` + `<script lang="ts">` + `defineComponent`.
|
||||||
|
- Evitar `any`.
|
||||||
|
|
||||||
|
## Como criar um novo componente (checklist)
|
||||||
|
|
||||||
|
1. Criar pasta em `src/componentes/<nome_em_portugues>/`
|
||||||
|
2. Criar `EliNomeDoComponente.vue` com `defineComponent` + comentários úteis
|
||||||
|
3. Criar `index.ts` re-exportando o componente
|
||||||
|
4. Criar `README.md` do componente (API, exemplos, casos de borda)
|
||||||
|
5. Criar playground em `src/playground/<nome>.playground.vue` (3+ variações)
|
||||||
|
6. Exportar no `src/index.ts`
|
||||||
|
|
||||||
|
## Como rodar o playground
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
O playground fica em `src/playground` e serve para validar visualmente os componentes durante o desenvolvimento.
|
||||||
|
|
|
||||||
62
dist/eli-vue.es.js
vendored
62
dist/eli-vue.es.js
vendored
|
|
@ -1,62 +0,0 @@
|
||||||
import { defineComponent as u, createBlock as i, openBlock as f, withCtx as o, createVNode as n, createTextVNode as l } from "vue";
|
|
||||||
import { VBtn as m } from "vuetify/components/VBtn";
|
|
||||||
import { VCard as s, VCardTitle as p, VCardText as c, VCardActions as _ } from "vuetify/components/VCard";
|
|
||||||
import { VContainer as x } from "vuetify/components/VGrid";
|
|
||||||
const V = u({
|
|
||||||
name: "EliOlaMundo"
|
|
||||||
}), C = (e, t) => {
|
|
||||||
const r = e.__vccOpts || e;
|
|
||||||
for (const [a, d] of t)
|
|
||||||
r[a] = d;
|
|
||||||
return r;
|
|
||||||
};
|
|
||||||
function O(e, t, r, a, d, y) {
|
|
||||||
return f(), i(x, null, {
|
|
||||||
default: o(() => [
|
|
||||||
n(s, {
|
|
||||||
class: "mx-auto",
|
|
||||||
max_width: "400"
|
|
||||||
}, {
|
|
||||||
default: o(() => [
|
|
||||||
n(p, null, {
|
|
||||||
default: o(() => [...t[0] || (t[0] = [
|
|
||||||
l("Olá Mundo!", -1)
|
|
||||||
])]),
|
|
||||||
_: 1
|
|
||||||
}),
|
|
||||||
n(c, null, {
|
|
||||||
default: o(() => [...t[1] || (t[1] = [
|
|
||||||
l(" Este é um componente de exemplo integrado com Vuetify. ", -1)
|
|
||||||
])]),
|
|
||||||
_: 1
|
|
||||||
}),
|
|
||||||
n(_, null, {
|
|
||||||
default: o(() => [
|
|
||||||
n(m, {
|
|
||||||
color: "primary",
|
|
||||||
block: ""
|
|
||||||
}, {
|
|
||||||
default: o(() => [...t[2] || (t[2] = [
|
|
||||||
l(" Botão Vuetify ", -1)
|
|
||||||
])]),
|
|
||||||
_: 1
|
|
||||||
})
|
|
||||||
]),
|
|
||||||
_: 1
|
|
||||||
})
|
|
||||||
]),
|
|
||||||
_: 1
|
|
||||||
})
|
|
||||||
]),
|
|
||||||
_: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const k = /* @__PURE__ */ C(V, [["render", O]]), T = {
|
|
||||||
install(e) {
|
|
||||||
e.component("EliOlaMundo", k);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export {
|
|
||||||
k as EliOlaMundo,
|
|
||||||
T as default
|
|
||||||
};
|
|
||||||
1
dist/eli-vue.umd.js
vendored
1
dist/eli-vue.umd.js
vendored
|
|
@ -1 +0,0 @@
|
||||||
(function(t,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue"),require("vuetify/components/VBtn"),require("vuetify/components/VCard"),require("vuetify/components/VGrid")):typeof define=="function"&&define.amd?define(["exports","vue","vuetify/components/VBtn","vuetify/components/VCard","vuetify/components/VGrid"],e):(t=typeof globalThis<"u"?globalThis:t||self,e(t.eli_vue={},t.Vue,t.VBtn,t.VCard,t.VGrid))})(this,(function(t,e,f,i,s){"use strict";const a=e.defineComponent({name:"EliOlaMundo"}),c=(o,n)=>{const d=o.__vccOpts||o;for(const[l,u]of n)d[l]=u;return d};function p(o,n,d,l,u,m){return e.openBlock(),e.createBlock(s.VContainer,null,{default:e.withCtx(()=>[e.createVNode(i.VCard,{class:"mx-auto",max_width:"400"},{default:e.withCtx(()=>[e.createVNode(i.VCardTitle,null,{default:e.withCtx(()=>[...n[0]||(n[0]=[e.createTextVNode("Olá Mundo!",-1)])]),_:1}),e.createVNode(i.VCardText,null,{default:e.withCtx(()=>[...n[1]||(n[1]=[e.createTextVNode(" Este é um componente de exemplo integrado com Vuetify. ",-1)])]),_:1}),e.createVNode(i.VCardActions,null,{default:e.withCtx(()=>[e.createVNode(f.VBtn,{color:"primary",block:""},{default:e.withCtx(()=>[...n[2]||(n[2]=[e.createTextVNode(" Botão Vuetify ",-1)])]),_:1})]),_:1})]),_:1})]),_:1})}const r=c(a,[["render",p]]),V={install(o){o.component("EliOlaMundo",r)}};t.EliOlaMundo=r,t.default=V,Object.defineProperties(t,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
import EliOlaMundo from './EliOlaMundo.vue';
|
|
||||||
export { EliOlaMundo };
|
|
||||||
export default EliOlaMundo;
|
|
||||||
7
dist/types/index.d.ts
vendored
7
dist/types/index.d.ts
vendored
|
|
@ -1,7 +0,0 @@
|
||||||
import type { App } from "vue";
|
|
||||||
import { EliOlaMundo } from './componentes/EliOlaMundo';
|
|
||||||
export { EliOlaMundo };
|
|
||||||
declare const _default: {
|
|
||||||
install(app: App): void;
|
|
||||||
};
|
|
||||||
export default _default;
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
import EliBadge from "./EliBadge.vue";
|
|
||||||
|
|
||||||
export { EliBadge };
|
|
||||||
export default EliBadge;
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
import EliBotao from "./EliBotao.vue";
|
|
||||||
|
|
||||||
export { EliBotao };
|
|
||||||
export default EliBotao;
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
import EliInput from "./EliInput.vue";
|
|
||||||
|
|
||||||
export { EliInput };
|
|
||||||
export default EliInput;
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
# EliOlaMundo (Exemplo de Estrutura)
|
|
||||||
|
|
||||||
Este componente serve como **referência oficial** para a criação de novos componentes neste Design System. Utilize esta estrutura como guia.
|
|
||||||
|
|
||||||
## 📂 Estrutura de Pastas e Arquivos
|
|
||||||
|
|
||||||
Todo componente deve seguir rigorosamente a estrutura abaixo, utilizando **PascalCase** (PrimeiraLetraMaiuscula) para pastas e arquivos.
|
|
||||||
|
|
||||||
```
|
|
||||||
src/componentes/
|
|
||||||
└── NomeDoComponente/ <-- Pasta do Componente
|
|
||||||
├── NomeDoComponente.vue <-- Lógica e Template (Vue 3 + TS)
|
|
||||||
├── index.ts <-- Ponto de entrada (Exports)
|
|
||||||
└── README.md <-- Documentação de uso (Props, Slots, Exemplos)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📝 Como Criar um Novo Componente
|
|
||||||
|
|
||||||
1. **Crie a Pasta:**
|
|
||||||
Nomeie a pasta com o nome do componente em PascalCase.
|
|
||||||
*Ex: `src/componentes/MeuBotao/`*
|
|
||||||
|
|
||||||
2. **Crie o Arquivo Vue:**
|
|
||||||
Nomeie o arquivo igual à pasta.
|
|
||||||
*Ex: `src/componentes/MeuBotao/MeuBotao.vue`*
|
|
||||||
- Utilize a Composition API com TypeScript.
|
|
||||||
- Defina sempre o `name` do componente.
|
|
||||||
|
|
||||||
3. **Crie o Index (`index.ts`):**
|
|
||||||
Este arquivo facilita a importação. Deve conter:
|
|
||||||
```typescript
|
|
||||||
import MeuBotao from './MeuBotao.vue'
|
|
||||||
|
|
||||||
export { MeuBotao }
|
|
||||||
export default MeuBotao
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Crie a Documentação (`README.md`):**
|
|
||||||
Descreva o que o componente faz, suas propriedades (`props`), eventos (`emits`) e slots.
|
|
||||||
|
|
||||||
5. **Registre na Biblioteca:**
|
|
||||||
Adicione o novo componente no arquivo principal `src/index.ts`:
|
|
||||||
```typescript
|
|
||||||
import { MeuBotao } from './componentes/MeuBotao'
|
|
||||||
// ...
|
|
||||||
export { MeuBotao }
|
|
||||||
|
|
||||||
export default {
|
|
||||||
install(app: App) {
|
|
||||||
// ...
|
|
||||||
app.component('MeuBotao', MeuBotao)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
import EliOlaMundo from './EliOlaMundo.vue'
|
|
||||||
|
|
||||||
export { EliOlaMundo }
|
|
||||||
export default EliOlaMundo
|
|
||||||
|
|
@ -116,7 +116,7 @@ Exemplos:
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref } from 'vue'
|
import { defineComponent, ref } from 'vue'
|
||||||
import EliBotao from '@/components/EliBotao.vue'
|
import EliBotao from '@/componentes/botao/EliBotao.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { EliBotao },
|
components: { EliBotao },
|
||||||
1
src/componentes/botao/index.ts
Normal file
1
src/componentes/botao/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as EliBotao } from "./EliBotao.vue";
|
||||||
|
|
@ -76,8 +76,8 @@
|
||||||
:row="row"
|
:row="row"
|
||||||
>
|
>
|
||||||
<v-radio
|
<v-radio
|
||||||
v-for="opt in options"
|
v-for="opt in computedItems"
|
||||||
:key="opt.value"
|
:key="String(opt.value)"
|
||||||
:label="opt.label"
|
:label="opt.label"
|
||||||
:value="opt.value"
|
:value="opt.value"
|
||||||
/>
|
/>
|
||||||
|
|
@ -86,8 +86,8 @@
|
||||||
<!-- CHECKBOX -->
|
<!-- CHECKBOX -->
|
||||||
<div v-else-if="type === 'checkbox'" class="checkbox-group">
|
<div v-else-if="type === 'checkbox'" class="checkbox-group">
|
||||||
<v-checkbox
|
<v-checkbox
|
||||||
v-for="opt in options"
|
v-for="opt in computedItems"
|
||||||
:key="opt.value"
|
:key="String(opt.value)"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
:label="opt.label"
|
:label="opt.label"
|
||||||
:value="opt.value"
|
:value="opt.value"
|
||||||
|
|
@ -104,12 +104,27 @@ import { formatTelefone } from "./utils/telefone";
|
||||||
import { formatarDecimal, formatarMoeda, somenteNumeros } from "./utils/numerico"
|
import { formatarDecimal, formatarMoeda, somenteNumeros } from "./utils/numerico"
|
||||||
import { formatarCep } from "./utils/cep";
|
import { formatarCep } from "./utils/cep";
|
||||||
|
|
||||||
type Option = {
|
/**
|
||||||
|
* Tipos base do EliInput.
|
||||||
|
* Mantidos aqui para evitar exports internos não documentados.
|
||||||
|
*/
|
||||||
|
type ValorCampo = string | number | boolean | null;
|
||||||
|
type ValorCampoMultiplo = ValorCampo[];
|
||||||
|
|
||||||
|
type OpcaoCampo<TValor extends ValorCampo = ValorCampo> = {
|
||||||
label: string;
|
label: string;
|
||||||
value: any;
|
value: TValor;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type OpcaoBruta<TValor extends ValorCampo = ValorCampo> =
|
||||||
|
| TValor
|
||||||
|
| {
|
||||||
|
label?: string;
|
||||||
|
value: TValor;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
type InputVariant =
|
type InputVariant =
|
||||||
| "outlined"
|
| "outlined"
|
||||||
| "filled"
|
| "filled"
|
||||||
|
|
@ -146,17 +161,34 @@ export default defineComponent({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
modelValue: { type: [String, Number, Array] as any, default: "" },
|
/**
|
||||||
|
* Aceita valor simples (text-like) ou lista de valores (checkbox/select multiple).
|
||||||
|
* O componente não converte tipos automaticamente: mantém o que receber.
|
||||||
|
*/
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number, Boolean, Array] as PropType<ValorCampo | ValorCampoMultiplo>,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
type: { type: String as PropType<InputType>, default: "text" },
|
type: { type: String as PropType<InputType>, default: "text" },
|
||||||
label: String,
|
label: String,
|
||||||
placeholder: String,
|
placeholder: String,
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
error: Boolean,
|
error: Boolean,
|
||||||
errorMessages: { type: [String, Array] as any, default: () => [] },
|
errorMessages: {
|
||||||
|
type: [String, Array] as PropType<string | string[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
hint: String,
|
hint: String,
|
||||||
persistentHint: Boolean,
|
persistentHint: Boolean,
|
||||||
rows: { type: Number, default: 4 },
|
rows: { type: Number, default: 4 },
|
||||||
options: { type: Array as PropType<Option[]>, default: () => [] },
|
/**
|
||||||
|
* Para select/radio/checkbox.
|
||||||
|
* Aceita lista já normalizada ({ label, value }) ou valores primitivos.
|
||||||
|
*/
|
||||||
|
options: {
|
||||||
|
type: Array as PropType<Array<OpcaoBruta>>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
clearable: Boolean,
|
clearable: Boolean,
|
||||||
variant: { type: String as PropType<InputVariant>, default: "outlined" },
|
variant: { type: String as PropType<InputVariant>, default: "outlined" },
|
||||||
density: { type: String as PropType<Density>, default: "comfortable" },
|
density: { type: String as PropType<Density>, default: "comfortable" },
|
||||||
|
|
@ -175,7 +207,7 @@ export default defineComponent({
|
||||||
|
|
||||||
const value = computed({
|
const value = computed({
|
||||||
get: () => props.modelValue,
|
get: () => props.modelValue,
|
||||||
set: (v) => {
|
set: (v: ValorCampo | ValorCampoMultiplo) => {
|
||||||
emit("update:modelValue", v);
|
emit("update:modelValue", v);
|
||||||
emit("change", v);
|
emit("change", v);
|
||||||
},
|
},
|
||||||
|
|
@ -255,25 +287,23 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Helpers para select / radio / checkbox (aceita objetos ou primitivos) ---
|
// --- Helpers para select / radio / checkbox (aceita objetos ou primitivos) ---
|
||||||
const computedItems = computed(() => {
|
const computedItems = computed<Array<OpcaoCampo>>(() => {
|
||||||
// Normaliza options para [{ label, value, disabled? }]
|
// Normaliza options para [{ label, value, disabled? }]
|
||||||
return (props.options || []).map((o: any) =>
|
return (props.options || []).map((o) => {
|
||||||
o && typeof o === "object" && ("label" in o || "value" in o)
|
if (o && typeof o === "object" && "value" in o) {
|
||||||
? { label: o.label ?? String(o.value), value: o.value, disabled: o.disabled }
|
const valor = o.value as ValorCampo;
|
||||||
: { label: String(o), value: o }
|
return {
|
||||||
);
|
label: o.label ?? String(valor),
|
||||||
|
value: valor,
|
||||||
|
disabled: o.disabled,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const valor = o as ValorCampo;
|
||||||
|
return { label: String(valor), value: valor };
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function optLabel(opt: any) {
|
|
||||||
if (opt && typeof opt === "object") return opt.label ?? String(opt.value);
|
|
||||||
return String(opt);
|
|
||||||
}
|
|
||||||
|
|
||||||
function optValue(opt: any) {
|
|
||||||
if (opt && typeof opt === "object") return opt.value;
|
|
||||||
return opt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
attrs,
|
attrs,
|
||||||
|
|
@ -288,8 +318,6 @@ export default defineComponent({
|
||||||
onFocus: () => emit("focus"),
|
onFocus: () => emit("focus"),
|
||||||
onBlur: () => emit("blur"),
|
onBlur: () => emit("blur"),
|
||||||
computedItems,
|
computedItems,
|
||||||
optLabel,
|
|
||||||
optValue,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -32,7 +32,8 @@ EliInput foi projetado para:
|
||||||
## Tipagem (TypeScript)
|
## Tipagem (TypeScript)
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type Option = { label: string; value: any; disabled?: boolean };
|
type ValorCampo = string | number | boolean | null;
|
||||||
|
type Option = { label: string; value: ValorCampo; disabled?: boolean };
|
||||||
|
|
||||||
type InputVariant = 'outlined' | 'filled' | 'plain' | 'solo' | 'solo-filled' | 'solo-inverted' | 'underlined';
|
type InputVariant = 'outlined' | 'filled' | 'plain' | 'solo' | 'solo-filled' | 'solo-inverted' | 'underlined';
|
||||||
type Density = 'default' | 'comfortable' | 'compact';
|
type Density = 'default' | 'comfortable' | 'compact';
|
||||||
|
|
@ -50,7 +51,7 @@ type InputType =
|
||||||
|
|
||||||
| Prop | Tipo | Default | Descrição |
|
| Prop | Tipo | Default | Descrição |
|
||||||
| ---------------- | --------------------------- | --------------- | ------------------------------------------------------ |
|
| ---------------- | --------------------------- | --------------- | ------------------------------------------------------ |
|
||||||
| `modelValue` | `string \| number \| any[]` | `""` | Valor controlado (use com `v-model`). |
|
| `modelValue` | `string \| number \| boolean \| (string \| number \| boolean \| null)[]` | `""` | Valor controlado (use com `v-model`). |
|
||||||
| `type` | `InputType` | `"text"` | Tipo do controle (ver `InputType`). |
|
| `type` | `InputType` | `"text"` | Tipo do controle (ver `InputType`). |
|
||||||
| `label` | `string` | `-` | Rótulo do campo. |
|
| `label` | `string` | `-` | Rótulo do campo. |
|
||||||
| `placeholder` | `string` | `-` | Texto exibido quando o campo está vazio. |
|
| `placeholder` | `string` | `-` | Texto exibido quando o campo está vazio. |
|
||||||
|
|
@ -113,4 +114,4 @@ type InputType =
|
||||||
## Slot
|
## Slot
|
||||||
|
|
||||||
* O componente não expõe slots customizados diretamente. Ele controla internamente o append para toggle de senha quando type === 'password' && showPasswordToggle (ícone de olho).
|
* O componente não expõe slots customizados diretamente. Ele controla internamente o append para toggle de senha quando type === 'password' && showPasswordToggle (ícone de olho).
|
||||||
* Se você precisa de slots específicos do v-text-field/v-select, considere estender o componente ou criar uma variação que exponha os slots desejados.
|
* Se você precisa de slots específicos do v-text-field/v-select, considere estender o componente ou criar uma variação que exponha os slots desejados.
|
||||||
1
src/componentes/campo/index.ts
Normal file
1
src/componentes/campo/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as EliInput } from "./EliInput.vue";
|
||||||
|
|
@ -121,8 +121,8 @@ export default defineComponent({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
::v-deep .v-badge__badge,
|
:deep(.v-badge__badge),
|
||||||
::v-deep .v-badge__content {
|
:deep(.v-badge__content) {
|
||||||
border-radius: var(--eli-badge-radius) !important;
|
border-radius: var(--eli-badge-radius) !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -177,6 +177,6 @@ Exemplo (pseudocódigo):
|
||||||
|
|
||||||
Observações sobre Vuetify
|
Observações sobre Vuetify
|
||||||
|
|
||||||
1. O EliBadge usa seletores com ::v-deep para alterar o border-radius do elemento interno do v-badge. Isso funciona para Vuetify 2 e 3, mas as classes internas podem variar entre versões. Se você atualizar o Vuetify, verifique os nomes de classe (.v-badge__badge ou .v-badge__content) e ajuste o seletor se necessário.
|
1. O EliBadge usa seletor com `:deep(...)` para alterar o border-radius do elemento interno do `v-badge`. Se você atualizar o Vuetify, verifique os nomes de classe (`.v-badge__badge` / `.v-badge__content`) e ajuste o seletor se necessário.
|
||||||
|
|
||||||
2. Prop names do v-badge (ex.: location, offset-x, offset-y, content, dot) podem variar entre versões do Vuetify — reveja a docs da versão em uso se algo não for aplicado como esperado.
|
2. Prop names do v-badge (ex.: location, offset-x, offset-y, content, dot) podem variar entre versões do Vuetify — reveja a docs da versão em uso se algo não for aplicado como esperado.
|
||||||
1
src/componentes/indicador/index.ts
Normal file
1
src/componentes/indicador/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as EliBadge } from "./EliBadge.vue";
|
||||||
|
|
@ -119,9 +119,11 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref } from "vue";
|
import { defineComponent, ref } from "vue";
|
||||||
import EliBotao from "../EliBotao/EliBotao.vue";
|
import EliBotao from "../botao/EliBotao.vue";
|
||||||
import EliBadge from "../EliBadge/EliBadge.vue";
|
import EliBadge from "../indicador/EliBadge.vue";
|
||||||
import EliInput from "../EliInput/EliInput.vue";
|
import EliInput from "../campo/EliInput.vue";
|
||||||
|
|
||||||
|
type Habilidade = "vue" | "react";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "EliOlaMundo",
|
name: "EliOlaMundo",
|
||||||
|
|
@ -132,7 +134,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const nome = ref("");
|
const nome = ref("");
|
||||||
const estado = ref([])
|
const estado = ref<string[]>([]);
|
||||||
const cep = ref("");
|
const cep = ref("");
|
||||||
const telefone = ref("");
|
const telefone = ref("");
|
||||||
const idade = ref("");
|
const idade = ref("");
|
||||||
|
|
@ -142,8 +144,8 @@ export default defineComponent({
|
||||||
const mensagem = ref("");
|
const mensagem = ref("");
|
||||||
const senha = ref("");
|
const senha = ref("");
|
||||||
const documento = ref("");
|
const documento = ref("");
|
||||||
const cor = ref(null);
|
const cor = ref<"azul" | "verde" | null>(null);
|
||||||
const habilidades = ref<any[]>([]);
|
const habilidades = ref<Habilidade[]>([]);
|
||||||
return {
|
return {
|
||||||
nome,
|
nome,
|
||||||
email,
|
email,
|
||||||
34
src/componentes/ola_mundo/README.md
Normal file
34
src/componentes/ola_mundo/README.md
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# EliOlaMundo (componente de demonstração)
|
||||||
|
|
||||||
|
O `EliOlaMundo` é um componente **de exemplo** usado para validar rapidamente o Design System no playground.
|
||||||
|
|
||||||
|
> Ele não é um componente “de produto”; ele existe para demonstrar integração com Vuetify e mostrar variações de uso de `EliInput`, `EliBotao` e `EliBadge`.
|
||||||
|
|
||||||
|
## Estrutura do repositório (padrão)
|
||||||
|
|
||||||
|
Neste Design System:
|
||||||
|
|
||||||
|
- **Pastas e arquivos** (quando aplicável) preferem português: `botao/`, `campo/`, `indicador/`, etc.
|
||||||
|
- **Componentes** mantêm prefixo técnico `Eli` (PascalCase): `EliBotao`, `EliInput`.
|
||||||
|
|
||||||
|
Exemplo:
|
||||||
|
|
||||||
|
```
|
||||||
|
src/componentes/
|
||||||
|
botao/
|
||||||
|
EliBotao.vue
|
||||||
|
index.ts
|
||||||
|
README.md
|
||||||
|
campo/
|
||||||
|
EliInput.vue
|
||||||
|
index.ts
|
||||||
|
README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Playground
|
||||||
|
|
||||||
|
O playground deve conter arquivos `*.playground.vue` para cada componente, com no mínimo:
|
||||||
|
|
||||||
|
- 3 variações visuais/estados
|
||||||
|
- interações (v-model/click)
|
||||||
|
- casos de borda relevantes
|
||||||
1
src/componentes/ola_mundo/index.ts
Normal file
1
src/componentes/ola_mundo/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as EliOlaMundo } from "./EliOlaMundo.vue";
|
||||||
14
src/index.ts
14
src/index.ts
|
|
@ -1,15 +1,15 @@
|
||||||
import type { App } from "vue";
|
import type { App, Plugin } from "vue";
|
||||||
import { EliOlaMundo } from "./componentes/EliOlaMundo";
|
import { EliOlaMundo } from "./componentes/ola_mundo";
|
||||||
import { EliBotao } from "./componentes/EliBotao";
|
import { EliBotao } from "./componentes/botao";
|
||||||
import { EliBadge } from "./componentes/EliBadge";
|
import { EliBadge } from "./componentes/indicador";
|
||||||
import { EliInput } from "./componentes/EliInput";
|
import { EliInput } from "./componentes/campo";
|
||||||
|
|
||||||
export { EliOlaMundo };
|
export { EliOlaMundo };
|
||||||
export { EliBotao };
|
export { EliBotao };
|
||||||
export { EliBadge };
|
export { EliBadge };
|
||||||
export { EliInput };
|
export { EliInput };
|
||||||
|
|
||||||
export default {
|
const EliVue: Plugin = {
|
||||||
install(app: App) {
|
install(app: App) {
|
||||||
app.component("EliOlaMundo", EliOlaMundo);
|
app.component("EliOlaMundo", EliOlaMundo);
|
||||||
app.component("EliBotao", EliBotao);
|
app.component("EliBotao", EliBotao);
|
||||||
|
|
@ -17,3 +17,5 @@ export default {
|
||||||
app.component("EliInput", EliInput);
|
app.component("EliInput", EliInput);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default EliVue;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,42 @@
|
||||||
<template>
|
<template>
|
||||||
<EliOlaMundo />
|
<v-container class="py-6">
|
||||||
|
<h1 class="text-h5 mb-4">Playground — eli-vue</h1>
|
||||||
|
|
||||||
|
<v-tabs v-model="aba" color="primary" density="comfortable">
|
||||||
|
<v-tab value="botao">Botão</v-tab>
|
||||||
|
<v-tab value="indicador">Indicador</v-tab>
|
||||||
|
<v-tab value="campo">Campo</v-tab>
|
||||||
|
<v-tab value="ola_mundo">Demo</v-tab>
|
||||||
|
</v-tabs>
|
||||||
|
|
||||||
|
<v-divider class="my-4" />
|
||||||
|
|
||||||
|
<BotaoPlayground v-if="aba === 'botao'" />
|
||||||
|
<IndicadorPlayground v-else-if="aba === 'indicador'" />
|
||||||
|
<CampoPlayground v-else-if="aba === 'campo'" />
|
||||||
|
<OlaMundoPlayground v-else />
|
||||||
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
import { EliOlaMundo } from '@/componentes/EliOlaMundo'
|
import BotaoPlayground from "./botao.playground.vue";
|
||||||
|
import IndicadorPlayground from "./indicador.playground.vue";
|
||||||
|
import CampoPlayground from "./campo.playground.vue";
|
||||||
|
import OlaMundoPlayground from "./ola_mundo.playground.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
EliOlaMundo,
|
BotaoPlayground,
|
||||||
|
IndicadorPlayground,
|
||||||
|
CampoPlayground,
|
||||||
|
OlaMundoPlayground,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
aba: "botao" as "botao" | "indicador" | "campo" | "ola_mundo",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
45
src/playground/botao.playground.vue
Normal file
45
src/playground/botao.playground.vue
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
<template>
|
||||||
|
<section class="stack">
|
||||||
|
<h2>EliBotao</h2>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<EliBotao @click="contador++">Primário (clicks: {{ contador }})</EliBotao>
|
||||||
|
<EliBotao variant="outlined">Outlined</EliBotao>
|
||||||
|
<EliBotao variant="text">Text</EliBotao>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<EliBotao :disabled="true">Desabilitado</EliBotao>
|
||||||
|
<EliBotao :loading="true">Carregando</EliBotao>
|
||||||
|
<EliBotao color="success">Success</EliBotao>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref } from "vue";
|
||||||
|
import { EliBotao } from "@/componentes/botao";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "BotaoPlayground",
|
||||||
|
components: { EliBotao },
|
||||||
|
setup() {
|
||||||
|
const contador = ref(0);
|
||||||
|
return { contador };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.stack {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
123
src/playground/campo.playground.vue
Normal file
123
src/playground/campo.playground.vue
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
<template>
|
||||||
|
<section class="stack">
|
||||||
|
<h2>EliInput (campo)</h2>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<EliInput v-model="nome" label="Nome" placeholder="Digite seu nome" />
|
||||||
|
<EliInput v-model="telefone" type="telefone" label="Telefone" />
|
||||||
|
<EliInput v-model="documento" type="cpfCnpj" label="CPF / CNPJ" />
|
||||||
|
|
||||||
|
<EliInput v-model="idade" type="numericoInteiro" label="Idade" />
|
||||||
|
<EliInput v-model="valor" type="numericoMoeda" label="Valor" />
|
||||||
|
<EliInput v-model="cep" type="cep" label="CEP" placeholder="00000-000" />
|
||||||
|
|
||||||
|
<EliInput
|
||||||
|
v-model="estado"
|
||||||
|
type="select"
|
||||||
|
label="Estado"
|
||||||
|
multiple
|
||||||
|
:options="[
|
||||||
|
{ label: 'São Paulo', value: 'SP' },
|
||||||
|
{ label: 'Rio de Janeiro', value: 'RJ' },
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<EliInput
|
||||||
|
v-model="cor"
|
||||||
|
type="radio"
|
||||||
|
label="Cor favorita"
|
||||||
|
:options="[
|
||||||
|
{ label: 'Azul', value: 'azul' },
|
||||||
|
{ label: 'Verde', value: 'verde' },
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<EliInput
|
||||||
|
v-model="habilidades"
|
||||||
|
type="checkbox"
|
||||||
|
label="Habilidades"
|
||||||
|
:options="[
|
||||||
|
{ label: 'Vue', value: 'vue' },
|
||||||
|
{ label: 'React', value: 'react' },
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<pre class="debug">{{ debug }}</pre>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, ref } from "vue";
|
||||||
|
import { EliInput } from "@/componentes/campo";
|
||||||
|
|
||||||
|
type Cor = "azul" | "verde" | null;
|
||||||
|
type Habilidade = "vue" | "react";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "CampoPlayground",
|
||||||
|
components: { EliInput },
|
||||||
|
setup() {
|
||||||
|
const nome = ref("");
|
||||||
|
const telefone = ref("");
|
||||||
|
const documento = ref("");
|
||||||
|
const idade = ref("");
|
||||||
|
const valor = ref("");
|
||||||
|
const cep = ref("");
|
||||||
|
const estado = ref<string[]>([]);
|
||||||
|
const cor = ref<Cor>(null);
|
||||||
|
const habilidades = ref<Habilidade[]>([]);
|
||||||
|
|
||||||
|
const debug = computed(() =>
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
nome: nome.value,
|
||||||
|
telefone: telefone.value,
|
||||||
|
documento: documento.value,
|
||||||
|
idade: idade.value,
|
||||||
|
valor: valor.value,
|
||||||
|
cep: cep.value,
|
||||||
|
estado: estado.value,
|
||||||
|
cor: cor.value,
|
||||||
|
habilidades: habilidades.value,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
nome,
|
||||||
|
telefone,
|
||||||
|
documento,
|
||||||
|
idade,
|
||||||
|
valor,
|
||||||
|
cep,
|
||||||
|
estado,
|
||||||
|
cor,
|
||||||
|
habilidades,
|
||||||
|
debug,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.stack {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug {
|
||||||
|
padding: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.04);
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
65
src/playground/indicador.playground.vue
Normal file
65
src/playground/indicador.playground.vue
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
<template>
|
||||||
|
<section class="stack">
|
||||||
|
<h2>EliBadge (indicador)</h2>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<EliBadge badge="3">
|
||||||
|
<v-icon>mdi-bell</v-icon>
|
||||||
|
</EliBadge>
|
||||||
|
|
||||||
|
<EliBadge badge="Novo" radius="pill" color="success">
|
||||||
|
<span class="chip">Mensagens</span>
|
||||||
|
</EliBadge>
|
||||||
|
|
||||||
|
<EliBadge dot :visible="true" color="error">
|
||||||
|
<v-icon>mdi-email</v-icon>
|
||||||
|
</EliBadge>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<EliBadge badge="99+" :visible="mostrar" radius="12px">
|
||||||
|
<span class="chip">Toggle visible</span>
|
||||||
|
</EliBadge>
|
||||||
|
|
||||||
|
<EliBotao variant="outlined" @click="mostrar = !mostrar">
|
||||||
|
Alternar visible ({{ mostrar ? "mostrando" : "oculto" }})
|
||||||
|
</EliBotao>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref } from "vue";
|
||||||
|
import { EliBadge } from "@/componentes/indicador";
|
||||||
|
import { EliBotao } from "@/componentes/botao";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "IndicadorPlayground",
|
||||||
|
components: { EliBadge, EliBotao },
|
||||||
|
setup() {
|
||||||
|
const mostrar = ref(true);
|
||||||
|
return { mostrar };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.stack {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip {
|
||||||
|
display: inline-flex;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
34
src/playground/ola_mundo.playground.vue
Normal file
34
src/playground/ola_mundo.playground.vue
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
<template>
|
||||||
|
<section class="stack">
|
||||||
|
<h2>EliOlaMundo</h2>
|
||||||
|
<p class="muted">
|
||||||
|
Demo integrada (útil para smoke-test visual). Para testes específicos,
|
||||||
|
prefira os playgrounds de <code>EliBotao</code>, <code>EliInput</code> e
|
||||||
|
<code>EliBadge</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<EliOlaMundo />
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import { EliOlaMundo } from "@/componentes/ola_mundo";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "OlaMundoPlayground",
|
||||||
|
components: { EliOlaMundo },
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.stack {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.muted {
|
||||||
|
opacity: 0.75;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
/* Tipagem */
|
/* Tipagem */
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"jsx": "preserve",
|
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
|
@ -27,6 +26,6 @@
|
||||||
/* Vue */
|
/* Vue */
|
||||||
"types": ["vite/client"]
|
"types": ["vite/client"]
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"],
|
||||||
"exclude": ["dist", "node_modules"]
|
"exclude": ["dist", "node_modules"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue