feat(cartao): adicionar cards com status e playground tipo trello

This commit is contained in:
Luiz Silva 2026-01-02 21:48:24 -03:00
parent ab15c51a1b
commit 5bb6732b81
8 changed files with 438 additions and 2 deletions

View file

@ -0,0 +1,148 @@
<template>
<v-card
class="eli-cartao"
:variant="variant"
:class="classeStatus"
v-bind="$attrs"
>
<v-card-title class="eli-cartao__titulo">
<div class="eli-cartao__titulo-texto">
<slot name="titulo">
{{ titulo }}
</slot>
</div>
<!-- Indicador de status (badge) padronizado pelo design system -->
<div class="eli-cartao__status">
<EliBadge
:badge="rotuloStatus"
radius="pill"
:color="corStatus"
>
<span />
</EliBadge>
</div>
</v-card-title>
<v-card-text class="eli-cartao__conteudo">
<slot />
</v-card-text>
<v-card-actions v-if="$slots.acoes" class="eli-cartao__acoes">
<slot name="acoes" />
</v-card-actions>
</v-card>
</template>
<script lang="ts">
import { computed, defineComponent, PropType } from "vue";
import type { CartaoStatus } from "../../tipos";
import { EliBadge } from "../indicador";
type CartaoVariante = "outlined" | "flat" | "elevated" | "tonal";
/**
* EliCartao
*
* Um cartão de domínio para listas/pipelines (ex.: oportunidades/propostas) com:
* - título
* - status padronizado (novo/rascunho/vendido/cancelado)
* - slot padrão para conteúdo
* - slot opcional para ações
*/
export default defineComponent({
name: "EliCartao",
components: { EliBadge },
inheritAttrs: false,
props: {
/** Título de fallback caso o slot `titulo` não seja usado. */
titulo: {
type: String,
default: "",
},
/**
* Status semântico do cartão.
* Usado para cor/label e para permitir filtros por status.
*/
status: {
type: String as PropType<CartaoStatus>,
required: true,
},
/** Variante visual do v-card (Vuetify). */
variant: {
type: String as PropType<CartaoVariante>,
default: "outlined",
},
},
emits: {
/** Emit opcional para padronizar clique no cartão. */
clicar: (_status: CartaoStatus) => true,
},
setup(props, { emit }) {
const rotuloStatus = computed(() => {
// Mantém label em PT-BR (não abreviar)
return props.status;
});
const corStatus = computed(() => {
// Cor neutra por padrão e semântica por status
switch (props.status) {
case "novo":
return "primary";
case "rascunho":
return "secondary";
case "vendido":
return "success";
case "cancelado":
return "error";
}
});
const classeStatus = computed(() => `eli-cartao--${props.status}`);
function onClick() {
emit("clicar", props.status);
}
return {
rotuloStatus,
corStatus,
classeStatus,
onClick,
};
},
});
</script>
<style scoped>
.eli-cartao {
border-radius: 12px;
}
.eli-cartao__titulo {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.eli-cartao__titulo-texto {
min-width: 0;
}
.eli-cartao__conteudo {
padding-top: 8px;
}
.eli-cartao__acoes {
padding-top: 0;
}
/* Hooks visuais por status (sem forçar cor, deixa o tema do Vuetify fazer o trabalho) */
.eli-cartao--cancelado {
opacity: 0.85;
}
</style>

View file

@ -0,0 +1,71 @@
# EliCartao
O `EliCartao` é um componente de cartão focado em **listas/pipelines** (ex.: oportunidades e propostas comerciais), com um **status semântico** padronizado.
Ele encapsula o `v-card` (Vuetify) e adiciona:
- Área de **título**
- **Badge de status** padronizado (`novo`, `rascunho`, `vendido`, `cancelado`)
- Slot de **conteúdo**
- Slot opcional de **ações**
## API
### Props
| Prop | Tipo | Padrão | Descrição |
|----------|--------------------------------------------------|--------------|-----------|
| `titulo` | `string` | `""` | Título de fallback (se o slot `titulo` não for usado). |
| `status` | `"novo" \| "rascunho" \| "vendido" \| "cancelado"` | *(obrigatório)* | Status semântico do cartão. Controla label/cor do badge e classes. |
| `variant`| `"outlined" \| "flat" \| "elevated" \| "tonal"` | `"outlined"` | Variante do `v-card` (Vuetify). |
### Emits
| Evento | Payload | Quando dispara |
|----------|-------------------------|----------------|
| `clicar` | `(status: CartaoStatus)`| Quando o cartão for clicado (opcional; útil para padronizar navegação). |
> Observação: o componente deixa `v-bind="$attrs"` para você passar `class`, `style`, `to`, `href`, etc.
## Slots
| Slot | Objetivo |
|----------|----------|
| `titulo` | Conteúdo customizado do título (override do `titulo`). |
| `default`| Corpo do cartão. |
| `acoes` | Rodapé de ações (botões/links). |
## Exemplos
### 1) Cartão simples
```vue
<EliCartao titulo="Proposta #1024" status="novo">
<div><strong>Cliente:</strong> ACME Ltda</div>
<div><strong>Valor:</strong> R$ 12.500,00</div>
</EliCartao>
```
### 2) Título via slot + ações
```vue
<EliCartao status="vendido">
<template #titulo>
<span>Oportunidade #204</span>
</template>
<div>Cliente: Empresa X</div>
<template #acoes>
<EliBotao variant="text">Abrir</EliBotao>
<EliBotao variant="text" color="secondary">Editar</EliBotao>
</template>
</EliCartao>
```
## Casos de borda / comportamento esperado
- `status` é obrigatório e sempre deve ser um valor suportado.
- Status `cancelado` aplica leve redução de opacidade via classe CSS.
- A renderização de ações só ocorre se o slot `acoes` existir.

View file

@ -0,0 +1,2 @@
export { default as EliCartao } from "./EliCartao.vue";