894 lines
25 KiB
Markdown
894 lines
25 KiB
Markdown
# Padrões de Estilo - Course Platform
|
|
|
|
Este documento define os padrões de estilo unificados para todo o sistema, garantindo consistência visual e facilidade de manutenção.
|
|
|
|
## Índice
|
|
|
|
- [Princípios Fundamentais](#princípios-fundamentais)
|
|
- [Cores e Tema](#cores-e-tema)
|
|
- [Tipografia](#tipografia)
|
|
- [Espaçamento](#espaçamento)
|
|
- [Badges e Labels](#badges-e-labels)
|
|
- [Componentes](#componentes)
|
|
- [Transições e Animações](#transições-e-animações)
|
|
- [Regras CSS Globais](#regras-css-globais)
|
|
|
|
---
|
|
|
|
## Princípios Fundamentais
|
|
|
|
1. **Usar CSS Variables** para cores, backgrounds e bordas (definidas em `:root` e `.dark`)
|
|
2. **Padronizar em `neutral-*`** em vez de `gray-*` para consistência
|
|
3. **Usar `blue-600`** como cor primária para botões de ação principal
|
|
4. **Manter border-radius de 8px** (`rounded-lg` ou `rounded-xl`)
|
|
5. **Usar sombras sutis**: `shadow-sm` padrão, `shadow-md` no hover
|
|
6. **Evitar regras CSS globais com `!important`** que sobrescrevem classes Tailwind
|
|
|
|
---
|
|
|
|
## Cores e Tema
|
|
|
|
### CSS Variables (Definidas em `globals.css`)
|
|
|
|
```css
|
|
/* Tema Claro (:root) */
|
|
--background: #ffffff;
|
|
--foreground: #09090b;
|
|
--card: #ffffff;
|
|
--card-foreground: #09090b;
|
|
--primary: #18181b;
|
|
--primary-foreground: #fafafa;
|
|
--secondary: #f4f4f5;
|
|
--secondary-foreground: #18181b;
|
|
--muted: #f4f4f5;
|
|
--muted-foreground: #71717a;
|
|
--accent: #f4f4f5;
|
|
--accent-foreground: #18181b;
|
|
--destructive: #ef4444;
|
|
--destructive-foreground: #fafafa;
|
|
--border: #e4e4e7;
|
|
--input: #e4e4e7;
|
|
--ring: #18181b;
|
|
--radius: 0.5rem;
|
|
|
|
/* Tema Escuro (.dark) */
|
|
--background: #09090b;
|
|
--foreground: #fafafa;
|
|
--card: #09090b;
|
|
--card-foreground: #fafafa;
|
|
--primary: #fafafa;
|
|
--primary-foreground: #18181b;
|
|
--secondary: #27272a;
|
|
--secondary-foreground: #fafafa;
|
|
--muted: #27272a;
|
|
--muted-foreground: #a1a1aa;
|
|
--accent: #27272a;
|
|
--accent-foreground: #fafafa;
|
|
--destructive: #7f1d1d;
|
|
--destructive-foreground: #fafafa;
|
|
--border: #27272a;
|
|
--input: #27272a;
|
|
--ring: #d4d4d8;
|
|
```
|
|
|
|
### Cores Semânticas (Tailwind)
|
|
|
|
| Propósito | Light Mode | Dark Mode |
|
|
|-----------|------------|-----------|
|
|
| Primary (Ação principal) | `blue-600` | `blue-500` |
|
|
| Primary Hover | `blue-700` | `blue-600` |
|
|
| Success | `green-600` | `green-500` |
|
|
| Success Hover | `green-700` | `green-600` |
|
|
| Warning | `yellow-500` | `yellow-400` |
|
|
| Warning Hover | `yellow-600` | `yellow-500` |
|
|
| Error/Destructive | `red-600` | `red-500` |
|
|
| Error Hover | `red-700` | `red-600` |
|
|
| Info | `blue-600` | `blue-500` |
|
|
|
|
### Cores Neutras (Padrão)
|
|
|
|
**Use sempre `neutral-*` em vez de `gray-*` para consistência:**
|
|
|
|
| Escala | Light Mode | Dark Mode |
|
|
|--------|------------|-----------|
|
|
| 50 | `#fafafa` | `#18181b` |
|
|
| 100 | `#f5f5f5` | `#27272a` |
|
|
| 200 | `#e5e5e5` | `#3f3f46` |
|
|
| 300 | `#d4d4d4` | `#52525b` |
|
|
| 400 | `#a3a3a3` | `#71717a` |
|
|
| 500 | `#737373` | `#a1a1aa` |
|
|
| 600 | `#525252` | `#d4d4d8` |
|
|
| 700 | `#404040` | `#e4e4e7` |
|
|
| 800 | `#262626` | `#f4f4f5` |
|
|
| 900 | `#171717` | `#fafafa` |
|
|
| 950 | `#0a0a0a` | `#fafafa` |
|
|
|
|
---
|
|
|
|
## Tipografia
|
|
|
|
### Fonte
|
|
|
|
- **Fonte Principal**: Geist Sans (Google Fonts)
|
|
- **Fonte Monospace**: Geist Mono (Google Fonts)
|
|
|
|
### Tamanhos e Pesos
|
|
|
|
| Elemento | Classe Tailwind | Uso |
|
|
|----------|-----------------|-----|
|
|
| Título Principal | `text-2xl md:text-3xl font-semibold` | Títulos de página |
|
|
| Título de Seção | `text-lg font-semibold` | Títulos de seção |
|
|
| Subtítulo | `text-base font-medium` | Subtítulos |
|
|
| Texto Normal | `text-sm` | Texto de conteúdo |
|
|
| Texto Secundário | `text-sm text-muted-foreground` | Texto de apoio |
|
|
| Label | `text-sm font-medium` | Labels de formulário |
|
|
| Caption/Small | `text-xs` | Textos pequenos |
|
|
|
|
### Exemplos
|
|
|
|
```jsx
|
|
// Título de Página
|
|
<h1 className="text-2xl md:text-3xl font-semibold text-foreground">
|
|
Título da Página
|
|
</h1>
|
|
|
|
// Título de Seção
|
|
<h2 className="text-lg font-semibold text-foreground">
|
|
Título da Seção
|
|
</h2>
|
|
|
|
// Subtítulo
|
|
<p className="text-sm text-muted-foreground">
|
|
Descrição ou subtítulo
|
|
</p>
|
|
|
|
// Label
|
|
<label className="text-sm font-medium leading-none">
|
|
Nome do Campo
|
|
</label>
|
|
```
|
|
|
|
---
|
|
|
|
## Espaçamento
|
|
|
|
### Padrões de Padding
|
|
|
|
| Elemento | Padding/Margin |
|
|
|----------|----------------|
|
|
| Card padding | `p-5` |
|
|
| Card padding (compacto) | `p-4` |
|
|
| Button padding | `px-4 py-2` |
|
|
| Input padding | `px-3 py-2` |
|
|
| Table cell padding | `px-6 py-4` |
|
|
| Section gap | `gap-3` ou `gap-4` |
|
|
| Vertical spacing entre elementos | `space-y-4` |
|
|
| Horizontal spacing entre elementos | `space-x-3` |
|
|
|
|
### Exemplos
|
|
|
|
```jsx
|
|
// Card
|
|
<div className="border rounded-xl p-5 shadow-sm bg-card">
|
|
{/* conteúdo */}
|
|
</div>
|
|
|
|
// Formulário com espaçamento vertical
|
|
<form className="space-y-4">
|
|
{/* campos */}
|
|
</form>
|
|
|
|
// Botões com espaçamento horizontal
|
|
<div className="flex gap-3">
|
|
<button>Cancelar</button>
|
|
<button>Salvar</button>
|
|
</div>
|
|
```
|
|
|
|
---
|
|
|
|
## Badges e Labels
|
|
|
|
Badges são pequenos labels coloridos usados para indicar status, categorias ou outros metadados. Devem ser usados consistentemente em toda a aplicação.
|
|
|
|
### Estrutura Base
|
|
|
|
```jsx
|
|
<span className="text-xs px-2 py-1 rounded-full border [badge-classes]">
|
|
Label Text
|
|
</span>
|
|
```
|
|
|
|
### Padrões de Cores
|
|
|
|
#### Success/Green (Disponível, Pago, Ativo, Presente)
|
|
|
|
**Tema Claro:** `bg-emerald-100 text-emerald-700 border-emerald-200`
|
|
**Tema Escuro:** `dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800`
|
|
|
|
```jsx
|
|
<span className="text-xs px-2 py-1 rounded-full border bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800">
|
|
Disponível
|
|
</span>
|
|
```
|
|
|
|
**Casos de Uso:**
|
|
- "Disponível" (Available)
|
|
- "Pago" (Paid)
|
|
- "Ativa" (Active)
|
|
- "Presente" (Present)
|
|
- Status "Verified"
|
|
|
|
---
|
|
|
|
#### Info/Blue (Em breve, Aguardando Verificação, Justificado)
|
|
|
|
**Tema Claro:** `bg-blue-100 text-blue-700 border-blue-200`
|
|
**Tema Escuro:** `dark:bg-blue-900/20 dark:text-blue-300 dark:border-blue-800`
|
|
|
|
```jsx
|
|
<span className="text-xs px-2 py-1 rounded-full border bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-900/20 dark:text-blue-300 dark:border-blue-800">
|
|
Em breve
|
|
</span>
|
|
```
|
|
|
|
**Casos de Uso:**
|
|
- "Em breve" (Upcoming)
|
|
- "Aguardando Verificação" (Pending Verification)
|
|
- "Justificado" (Excused)
|
|
- Templates "Public"
|
|
|
|
---
|
|
|
|
#### Danger/Red (Encerrada, Rejeitado, Ausente)
|
|
|
|
**Tema Claro:** `bg-red-100 text-red-700 border-red-200`
|
|
**Tema Escuro:** `dark:bg-red-900/20 dark:text-red-300 dark:border-red-800`
|
|
|
|
```jsx
|
|
<span className="text-xs px-2 py-1 rounded-full border bg-red-100 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800">
|
|
Encerrada
|
|
</span>
|
|
```
|
|
|
|
**Casos de Uso:**
|
|
- "Encerrada" (Expired)
|
|
- "Rejeitado" (Rejected)
|
|
- "Ausente" (Absent)
|
|
- Status "Rejected"
|
|
|
|
---
|
|
|
|
#### Warning/Amber (Aguardando Pagamento, Atrasado, Arquivada)
|
|
|
|
**Tema Claro:** `bg-amber-100 text-amber-700 border-amber-200`
|
|
**Tema Escuro:** `dark:bg-amber-900/20 dark:text-amber-300 dark:border-amber-800`
|
|
|
|
```jsx
|
|
<span className="text-xs px-2 py-1 rounded-full border bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-900/20 dark:text-amber-300 dark:border-amber-800">
|
|
Aguardando Pagamento
|
|
</span>
|
|
```
|
|
|
|
**Casos de Uso:**
|
|
- "Aguardando Pagamento" (Pending Payment)
|
|
- "Atrasado" (Late)
|
|
- "Arquivada" (Archived)
|
|
- Status "Pending"
|
|
|
|
---
|
|
|
|
#### Warning/Yellow (Obrigações)
|
|
|
|
**Tema Claro:** `bg-yellow-100 text-yellow-800 border-yellow-300`
|
|
**Tema Escuro:** `dark:bg-yellow-900/50 dark:text-yellow-200 dark:border-yellow-700`
|
|
|
|
```jsx
|
|
<span className="text-xs px-2 py-1 rounded-full border bg-yellow-100 text-yellow-800 border-yellow-300 dark:bg-yellow-900/50 dark:text-yellow-200 dark:border-yellow-700">
|
|
Obrigação
|
|
</span>
|
|
```
|
|
|
|
**Casos de Uso:**
|
|
- Obrigações de pagamento
|
|
- "Obrigação" (Obligation)
|
|
|
|
---
|
|
|
|
#### Purple (Leitura)
|
|
|
|
**Tema Claro:** `bg-purple-100 text-purple-700 border-purple-200`
|
|
**Tema Escuro:** `dark:bg-purple-900/20 dark:text-purple-300 dark:border-purple-800`
|
|
|
|
```jsx
|
|
<span className="text-xs px-2 py-1 rounded-full border bg-purple-100 text-purple-700 border-purple-200 dark:bg-purple-900/20 dark:text-purple-300 dark:border-purple-800">
|
|
Leitura
|
|
</span>
|
|
```
|
|
|
|
**Casos de Uso:**
|
|
- "Leitura" (Reading)
|
|
- Categoria "Indigo"
|
|
|
|
---
|
|
|
|
#### Indigo (Trabalhos)
|
|
|
|
**Tema Claro:** `bg-indigo-100 text-indigo-700 border-indigo-200`
|
|
**Tema Escuro:** `dark:bg-indigo-900/20 dark:text-indigo-300 dark:border-indigo-800`
|
|
|
|
```jsx
|
|
<span className="text-xs px-2 py-1 rounded-full border bg-indigo-100 text-indigo-700 border-indigo-200 dark:bg-indigo-900/20 dark:text-indigo-300 dark:border-indigo-800">
|
|
Trabalhos
|
|
</span>
|
|
```
|
|
|
|
**Casos de Uso:**
|
|
- "Trabalhos" (Homework)
|
|
- Itens relacionados a assignments
|
|
|
|
---
|
|
|
|
#### Neutral/Gray (Outros, Padrão)
|
|
|
|
**Tema Claro:** `bg-gray-100 text-gray-700 border-gray-200`
|
|
**Tema Escuro:** `dark:bg-gray-800 dark:text-gray-300 dark:border-gray-700`
|
|
|
|
```jsx
|
|
<span className="text-xs px-2 py-1 rounded-full border bg-gray-100 text-gray-700 border-gray-200 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-700">
|
|
Outros
|
|
</span>
|
|
```
|
|
|
|
**Casos de Uso:**
|
|
- "Outros" (Other)
|
|
- Categorias padrão/desconhecidas
|
|
- Status neutro
|
|
|
|
### Badges por Categoria
|
|
|
|
#### Categorias de Arquivos
|
|
|
|
| Categoria | Cor |
|
|
|-----------|-----|
|
|
| Slides | Blue |
|
|
| Exercícios | Green |
|
|
| Leitura | Purple |
|
|
| Vídeos | Red |
|
|
| Áudio | Yellow |
|
|
| Trabalhos | Indigo |
|
|
| Outros | Gray |
|
|
|
|
#### Status de Presença
|
|
|
|
| Status | Cor |
|
|
|--------|-----|
|
|
| Presente | Green |
|
|
| Ausente | Red |
|
|
| Atrasado | Amber |
|
|
| Justificado | Blue |
|
|
|
|
#### Status de Pagamento
|
|
|
|
| Status | Cor |
|
|
|--------|-----|
|
|
| Pago | Green |
|
|
| Aguardando Verificação | Blue |
|
|
| Rejeitado | Red |
|
|
| Aguardando Pagamento | Amber |
|
|
| Obrigação | Yellow |
|
|
|
|
#### Status de Provas
|
|
|
|
| Status | Cor |
|
|
|--------|-----|
|
|
| Disponível | Green |
|
|
| Em breve | Blue |
|
|
| Encerrada | Red |
|
|
|
|
#### Status de Turma
|
|
|
|
| Status | Cor |
|
|
|--------|-----|
|
|
| Ativa | Green |
|
|
| Arquivada | Amber |
|
|
|
|
### Exemplo de Implementação
|
|
|
|
```jsx
|
|
const categoryColors = {
|
|
'Slides': 'text-xs px-2 py-1 rounded-full border bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-900/20 dark:text-blue-300 dark:border-blue-800',
|
|
'Exercícios': 'text-xs px-2 py-1 rounded-full border bg-green-100 text-green-700 border-green-200 dark:bg-green-900/20 dark:text-green-300 dark:border-green-800',
|
|
'Leitura': 'text-xs px-2 py-1 rounded-full border bg-purple-100 text-purple-700 border-purple-200 dark:bg-purple-900/20 dark:text-purple-300 dark:border-purple-800',
|
|
'Vídeos': 'text-xs px-2 py-1 rounded-full border bg-red-100 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800',
|
|
'Áudio': 'text-xs px-2 py-1 rounded-full border bg-yellow-100 text-yellow-700 border-yellow-200 dark:bg-yellow-900/20 dark:text-yellow-300 dark:border-yellow-800',
|
|
'Trabalhos': 'text-xs px-2 py-1 rounded-full border bg-indigo-100 text-indigo-700 border-indigo-200 dark:bg-indigo-900/20 dark:text-indigo-300 dark:border-indigo-800',
|
|
'Outros': 'text-xs px-2 py-1 rounded-full border bg-gray-100 text-gray-700 border-gray-200 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-700'
|
|
};
|
|
|
|
<span className={categoryColors[category] || categoryColors['Outros']}>
|
|
{category}
|
|
</span>
|
|
```
|
|
|
|
### Notas Importantes
|
|
|
|
1. **Consistência**: Sempre use a string de classes completa incluindo variantes de tema claro e escuro
|
|
2. **Acessibilidade**: As combinações de cores fornecem contraste suficiente para ambos os temas
|
|
3. **Opacidade**: O tema escuro usa `/20` de opacidade para a maioria das cores (exceto yellow que usa `/50`)
|
|
4. **Borda**: Sempre inclua borda para melhor separação visual
|
|
5. **Arredondamento**: Use `rounded-full` para badges em formato de pílula
|
|
6. **Tamanho**: Use `text-xs` para badges pequenos, `text-sm` para badges maiores se necessário
|
|
|
|
---
|
|
|
|
## Componentes
|
|
|
|
### Cards
|
|
|
|
**Padrão Unificado:**
|
|
|
|
```jsx
|
|
<div className="border rounded-xl p-5 shadow-sm bg-card dark:bg-card dark:border-border hover:shadow-md hover:border-neutral-300 dark:hover:border-neutral-700 transition-all">
|
|
{/* conteúdo */}
|
|
</div>
|
|
```
|
|
|
|
**Card com Link:**
|
|
|
|
```jsx
|
|
<Link href="/path" className="block no-underline">
|
|
<div className="border rounded-xl p-5 shadow-sm bg-card hover:shadow-md transition-all">
|
|
{/* conteúdo */}
|
|
</div>
|
|
</Link>
|
|
```
|
|
|
|
### Botões
|
|
|
|
**Primary (Ação Principal):**
|
|
|
|
```jsx
|
|
<button
|
|
type="submit"
|
|
className="inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium bg-blue-600 hover:bg-blue-700 text-white h-10 px-4 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
|
>
|
|
Salvar
|
|
</button>
|
|
```
|
|
|
|
**Secondary (Ação Secundária):**
|
|
|
|
```jsx
|
|
<button
|
|
type="button"
|
|
className="inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
|
>
|
|
Cancelar
|
|
</button>
|
|
```
|
|
|
|
**Destructive (Ação de Exclusão):**
|
|
|
|
```jsx
|
|
<button
|
|
type="button"
|
|
className="inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium bg-red-600 hover:bg-red-700 text-white h-10 px-4 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
|
>
|
|
Excluir
|
|
</button>
|
|
```
|
|
|
|
**Botão com Ícone:**
|
|
|
|
```jsx
|
|
<button className="inline-flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium shadow-sm hover:shadow transition-shadow">
|
|
<Icon className="w-4 h-4" />
|
|
<span>Texto do Botão</span>
|
|
</button>
|
|
```
|
|
|
|
### Inputs
|
|
|
|
**Input de Texto:**
|
|
|
|
```jsx
|
|
<input
|
|
type="text"
|
|
className="flex h-10 w-full rounded-lg border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
placeholder="Digite aqui..."
|
|
/>
|
|
```
|
|
|
|
**Select:**
|
|
|
|
```jsx
|
|
<div className="relative">
|
|
<select
|
|
className="flex h-10 w-full rounded-lg border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 appearance-none"
|
|
>
|
|
<option value="">Selecione...</option>
|
|
{/* opções */}
|
|
</select>
|
|
<svg className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-5 w-5 text-muted-foreground">
|
|
{/* ícone de seta */}
|
|
</svg>
|
|
</div>
|
|
```
|
|
|
|
**Textarea:**
|
|
|
|
```jsx
|
|
<textarea
|
|
className="flex min-h-[80px] w-full rounded-lg border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
placeholder="Digite sua mensagem..."
|
|
rows={4}
|
|
/>
|
|
```
|
|
|
|
### Tabelas
|
|
|
|
**Tabela Padrão:**
|
|
|
|
```jsx
|
|
<div className="w-full overflow-x-auto rounded-xl border border-border bg-card shadow-sm">
|
|
<table className="w-full text-sm text-left">
|
|
<thead className="bg-muted text-muted-foreground font-semibold uppercase text-xs">
|
|
<tr>
|
|
<th className="px-6 py-4 border-b border-border">Coluna 1</th>
|
|
<th className="px-6 py-4 border-b border-border">Coluna 2</th>
|
|
<th className="px-6 py-4 border-b border-border text-right">Ações</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y divide-border">
|
|
<tr className="hover:bg-accent transition-colors">
|
|
<td className="px-6 py-4 text-foreground">Valor 1</td>
|
|
<td className="px-6 py-4 text-foreground">Valor 2</td>
|
|
<td className="px-6 py-4 text-right">
|
|
{/* ações */}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
```
|
|
|
|
### Badges
|
|
|
|
**Status Badges:**
|
|
|
|
```jsx
|
|
// Success (Pago)
|
|
<span className="px-2 py-1 rounded-full text-xs font-medium border bg-green-100 dark:bg-green-900/50 text-green-800 dark:text-green-200 border-green-300 dark:border-green-700">
|
|
Pago
|
|
</span>
|
|
|
|
// Warning (Pendente)
|
|
<span className="px-2 py-1 rounded-full text-xs font-medium border bg-yellow-100 dark:bg-yellow-900/50 text-yellow-800 dark:text-yellow-200 border-yellow-300 dark:border-yellow-700">
|
|
Pendente
|
|
</span>
|
|
|
|
// Error (Rejeitado)
|
|
<span className="px-2 py-1 rounded-full text-xs font-medium border bg-red-100 dark:bg-red-900/50 text-red-800 dark:text-red-200 border-red-300 dark:border-red-700">
|
|
Rejeitado
|
|
</span>
|
|
|
|
// Info (Aguardando Verificação)
|
|
<span className="px-2 py-1 rounded-full text-xs font-medium border bg-blue-100 dark:bg-blue-900/50 text-blue-800 dark:text-blue-200 border-blue-300 dark:border-blue-700">
|
|
Aguardando Verificação
|
|
</span>
|
|
|
|
// Neutral (Não Pago)
|
|
<span className="px-2 py-1 rounded-full text-xs font-medium border bg-neutral-100 dark:bg-neutral-700 text-neutral-800 dark:text-neutral-200 border-neutral-300 dark:border-neutral-600">
|
|
Não Pago
|
|
</span>
|
|
```
|
|
|
|
### Flash Messages
|
|
|
|
```jsx
|
|
// Success
|
|
<div className="px-4 py-3 rounded relative mb-4 text-green-700 dark:text-green-300 bg-green-100 dark:bg-green-900/50 border border-green-400 dark:border-green-700">
|
|
<div className="flex items-center">
|
|
<strong className="font-bold mr-1">Sucesso:</strong>
|
|
<span className="block sm:inline">Mensagem de sucesso</span>
|
|
</div>
|
|
</div>
|
|
|
|
// Error
|
|
<div className="px-4 py-3 rounded relative mb-4 text-red-700 dark:text-red-300 bg-red-100 dark:bg-red-900/50 border border-red-400 dark:border-red-700">
|
|
<div className="flex items-center">
|
|
<strong className="font-bold mr-1">Erro:</strong>
|
|
<span className="block sm:inline">Mensagem de erro</span>
|
|
</div>
|
|
</div>
|
|
|
|
// Warning
|
|
<div className="px-4 py-3 rounded relative mb-4 text-yellow-700 dark:text-yellow-300 bg-yellow-100 dark:bg-yellow-900/50 border border-yellow-400 dark:border-yellow-700">
|
|
<div className="flex items-center">
|
|
<strong className="font-bold mr-1">Aviso:</strong>
|
|
<span className="block sm:inline">Mensagem de aviso</span>
|
|
</div>
|
|
</div>
|
|
|
|
// Info
|
|
<div className="px-4 py-3 rounded relative mb-4 text-blue-700 dark:text-blue-300 bg-blue-100 dark:bg-blue-900/50 border border-blue-400 dark:border-blue-700">
|
|
<div className="flex items-center">
|
|
<strong className="font-bold mr-1">Info:</strong>
|
|
<span className="block sm:inline">Mensagem informativa</span>
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
### Sidebar Navigation
|
|
|
|
```jsx
|
|
<aside className="w-64 flex-shrink-0 border-r border-neutral-200 dark:border-neutral-800 p-4 bg-white dark:bg-neutral-950">
|
|
<nav className="mt-2">
|
|
<ul className="space-y-1">
|
|
{/* itens de navegação */}
|
|
</ul>
|
|
</nav>
|
|
</aside>
|
|
```
|
|
|
|
### Stats Cards
|
|
|
|
```jsx
|
|
<div className="rounded-lg border border-neutral-200 dark:border-neutral-800 p-3 bg-neutral-50 dark:bg-neutral-800/40">
|
|
<p className="text-xs text-neutral-700 dark:text-neutral-300 font-medium">Label</p>
|
|
<p className="mt-1 text-lg font-semibold text-neutral-900 dark:text-neutral-100">Valor</p>
|
|
</div>
|
|
```
|
|
|
|
---
|
|
|
|
## Transições e Animações
|
|
|
|
### Padrões de Transição
|
|
|
|
```jsx
|
|
// Transição suave para todas as propriedades
|
|
className="transition-all duration-200"
|
|
|
|
// Transição apenas para cores
|
|
className="transition-colors"
|
|
|
|
// Transição para sombra
|
|
className="transition-shadow"
|
|
|
|
// Transição para transformações
|
|
className="transition-transform"
|
|
```
|
|
|
|
### Hover Effects
|
|
|
|
```jsx
|
|
// Card hover
|
|
<div className="hover:shadow-md hover:border-neutral-300 dark:hover:border-neutral-700 transition-all">
|
|
|
|
// Button hover
|
|
<button className="hover:bg-blue-700 transition-colors">
|
|
|
|
// Link hover
|
|
<a className="hover:text-blue-600 transition-colors">
|
|
```
|
|
|
|
---
|
|
|
|
## Regras CSS Globais
|
|
|
|
### Importante: Evitar `!important` em regras globais
|
|
|
|
**NÃO FAÇA:**
|
|
|
|
```css
|
|
button[type="submit"] {
|
|
background-color: var(--primary) !important;
|
|
color: var(--primary-foreground) !important;
|
|
}
|
|
```
|
|
|
|
Isso sobrescreve todas as classes Tailwind e causa problemas de manutenção.
|
|
|
|
**FAÇA:**
|
|
|
|
Deixe cada componente definir seu próprio estilo usando classes Tailwind ou CSS variables sem `!important`.
|
|
|
|
### Estilos Base (Definidos em `globals.css`)
|
|
|
|
```css
|
|
/* Form elements */
|
|
input, select, textarea {
|
|
border: 1px solid var(--input);
|
|
background-color: var(--background);
|
|
border-radius: var(--radius);
|
|
padding: 0.5rem 0.75rem;
|
|
font-size: 0.875rem;
|
|
color: var(--foreground);
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
input:focus, select:focus, textarea:focus {
|
|
outline: none;
|
|
border-color: var(--ring);
|
|
box-shadow: 0 0 0 2px var(--background), 0 0 0 4px var(--ring);
|
|
}
|
|
|
|
/* Tables */
|
|
table {
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
thead {
|
|
background-color: var(--muted);
|
|
}
|
|
|
|
tbody tr {
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
tbody tr:hover {
|
|
background-color: var(--accent);
|
|
}
|
|
|
|
th {
|
|
text-align: left;
|
|
font-weight: 500;
|
|
color: var(--muted-foreground);
|
|
padding: 0.75rem 1rem;
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
td {
|
|
padding: 1rem;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
/* Cards */
|
|
.card {
|
|
background-color: var(--card);
|
|
color: var(--card-foreground);
|
|
border-radius: var(--radius);
|
|
border: 1px solid var(--border);
|
|
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
|
}
|
|
|
|
/* Badges */
|
|
.badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
border-radius: 9999px;
|
|
padding: 0.125rem 0.625rem;
|
|
font-size: 0.75rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Links */
|
|
a {
|
|
color: var(--primary);
|
|
text-decoration: none;
|
|
}
|
|
|
|
a:hover,
|
|
a:focus,
|
|
a:active {
|
|
text-decoration: none !important;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Checklist de Implementação
|
|
|
|
Ao criar ou modificar componentes, verifique:
|
|
|
|
- [ ] Usar CSS variables (`bg-card`, `text-foreground`, `border-border`)
|
|
- [ ] Usar `neutral-*` em vez de `gray-*`
|
|
- [ ] Usar `blue-600` para botões primary
|
|
- [ ] Usar `rounded-lg` ou `rounded-xl` para border-radius
|
|
- [ ] Adicionar `transition-colors` ou `transition-all` para elementos interativos
|
|
- [ ] Testar em tema claro e escuro
|
|
- [ ] Verificar contraste de cores
|
|
- [ ] Usar classes Tailwind em vez de CSS customizado quando possível
|
|
- [ ] Evitar `!important` em regras CSS
|
|
|
|
---
|
|
|
|
## Exemplos de Componentes Completos
|
|
|
|
### Formulário Padrão
|
|
|
|
```jsx
|
|
function StandardForm({ onSubmit, onCancel }) {
|
|
return (
|
|
<form onSubmit={onSubmit} className="bg-card text-card-foreground rounded-xl border shadow-sm p-6 max-w-lg mx-auto space-y-4">
|
|
<div className="space-y-2">
|
|
<label htmlFor="name" className="text-sm font-medium leading-none">
|
|
Nome
|
|
</label>
|
|
<input
|
|
id="name"
|
|
name="name"
|
|
className="flex h-10 w-full rounded-lg border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
placeholder="Digite o nome"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<label htmlFor="email" className="text-sm font-medium leading-none">
|
|
Email
|
|
</label>
|
|
<input
|
|
id="email"
|
|
name="email"
|
|
type="email"
|
|
className="flex h-10 w-full rounded-lg border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
placeholder="Digite o email"
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex gap-3 mt-6">
|
|
<button
|
|
type="submit"
|
|
className="inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium bg-blue-600 hover:bg-blue-700 text-white h-10 px-4 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 flex-1"
|
|
>
|
|
Salvar
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={onCancel}
|
|
className="inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 flex-1"
|
|
>
|
|
Cancelar
|
|
</button>
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Card de Dashboard
|
|
|
|
```jsx
|
|
function DashboardCard({ title, description, buttonText, link, icon: Icon }) {
|
|
return (
|
|
<Link href={link} className="block no-underline">
|
|
<div className="h-full border rounded-xl p-5 shadow-sm bg-card dark:bg-card dark:border-border hover:shadow-md hover:border-neutral-300 dark:hover:border-neutral-700 transition-all">
|
|
<div className="flex items-start gap-4">
|
|
{Icon && (
|
|
<div className="p-2.5 rounded-lg bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300">
|
|
<Icon className="w-5 h-5" />
|
|
</div>
|
|
)}
|
|
<div className="flex-1">
|
|
<h3 className="text-lg font-semibold text-foreground mb-2">{title}</h3>
|
|
<p className="text-sm text-muted-foreground mb-4">{description}</p>
|
|
<span className="inline-flex justify-center text-white text-sm font-medium py-2 px-6 rounded-lg transition-colors bg-blue-600 hover:bg-blue-700">
|
|
{buttonText}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Conclusão
|
|
|
|
Seguir estes padrões garantirá:
|
|
|
|
✅ **Consistência visual** em todo o sistema
|
|
✅ **Manutenção mais fácil** com código previsível
|
|
✅ **Melhor suporte** a tema claro/escuro
|
|
✅ **Código mais limpo** e organizado
|
|
✅ **Experiência do usuário** mais coesa
|
|
|
|
Para dúvidas ou sugestões de melhoria, consulte a equipe de desenvolvimento.
|