Design Tokens
Este documento é a fonte única de verdade para todos os valores de design do projeto. Qualquer cor, espaçamento, animação ou constante de negócio utilizada no código deve estar referenciada aqui.
1. O que são Design Tokens?
Design tokens são os átomos do sistema de design — pares nome/valor que representam decisões visuais e de produto de forma agnóstica à plataforma. Em vez de espalhar o valor #F4C430 por centenas de arquivos, você usa o token gold-400 em todos os lugares.
Fonte única de verdade
No projeto existem dois arquivos que devem estar sempre sincronizados:
| Arquivo | Papel |
|---|---|
tailwind.config.ts | Define os tokens como classes utilitárias Tailwind (text-gold-400, bg-primary-500, shadow-warm) |
lib/design-tokens.ts | Exporta os mesmos valores como constantes TypeScript para uso em estilos inline, lógica condicional e testes |
Regra: ao adicionar ou alterar qualquer token, ambos os arquivos devem ser atualizados na mesma PR. Ver seção Adicionando novos tokens.
Fluxo de uso
Decisão de design
↓
tailwind.config.ts ←→ lib/design-tokens.ts
↓ ↓
Classes Tailwind TypeScript / inline styles
(className="text-gold-400") (style={{ color: BRAND_COLORS.goldRadiant }})
2. Cores — Paleta Completa
Primary — Marrom Âmbar
| Nível | Hex | Uso semântico |
|---|---|---|
| 50 | #fdf8f4 | Background de seção levíssimo, hover de linha em tabelas |
| 100 | #f7e9d8 | Background de cartão sutil, chip inativo |
| 200 | #eecfaf | Bordas sutis, skeleton loading, divisores |
| 300 | #e0ad7d | Hover de bordas, ícones decorativos secundários |
| 400 | #ce8849 | Hover de elementos interativos, ícones de destaque |
| 500 | #b96828 | Cor primária — botão secundário, link ativo, anel de foco |
| 600 | #964e1a | Hover/active do botão primário âmbar |
| 700 | #773b13 | Texto âmbar de alto contraste sobre fundo claro |
| 800 | #5c2c0d | Texto de máximo contraste, cabeçalhos escuros |
| 900 | #3D2817 | Texto ultra escuro — quase equivale ao deep |
| 950 | #1A1410 | Texto ultra escuro — idêntico ao token deep |
Gold — Dourado Radiante
| Nível | Hex | Uso semântico |
|---|---|---|
| 50 | #fffef0 | Background de alerta/notificação dourado suavíssimo |
| 100 | #fefce0 | Background de badge dourado |
| 200 | #fdf5b0 | Highlight de texto, marcação de busca |
| 300 | #fce870 | Borda de alerta positivo, ícone de estrela de avaliação |
| 400 | #F4C430 | CTA principal — btn-gold, estrelas ativas, hover dourado |
| 500 | #d4a020 | Botão gold pressionado (active state), texto dourado sobre claro |
| 600 | #aa7e15 | Texto dourado de alto contraste |
| 700 | #7e5d0f | Texto dourado — máxima legibilidade |
| 800 | #5c430b | Bordas douradas escuras |
| 900 | #3f2f08 | Texto dourado de máximo contraste |
Sage — Verde Sálvia
| Nível | Hex | Uso semântico |
|---|---|---|
| 50 | #eef9f4 | Background de mensagem de sucesso |
| 100 | #d5f0e4 | Background de badge verde claro |
| 200 | #a5ddc8 | Borda de campo válido (formulário) |
| 300 | #6cc4a8 | Ícones de confirmação secundários |
| 400 | #3da887 | Ícone de sucesso, hover de elemento sage |
| 500 | #2D7A5F | Cor sage primária — badge "Em estoque", status DELIVERED/PAID |
| 600 | #226350 | Hover/active de elementos sage |
| 700 | #1a4d3e | Texto sage de alto contraste |
| 800 | #123c30 | Texto sage — máxima legibilidade |
| 900 | #0d2e25 | Texto sage de máximo contraste |
Cores funcionais da loja
| Token Tailwind | Valor hex | Uso |
|---|---|---|
cream | #FFF8E7 | Fundo principal da loja (body, hero) |
cream-dark | #F5E6C8 | Seções alternadas, fundo do footer |
cream-warm | #FDF0D5 | Hover de cards, fundo de banners de destaque |
deep | #1A1410 | Texto principal de máximo contraste |
3. Constantes de Negócio
Definidas em lib/constants.ts. Estas constantes governam regras de negócio da loja e devem ser atualizadas exclusivamente neste arquivo — nunca hardcoded em componentes.
Frete e compras
| Constante | Valor | Tipo | Onde é usado |
|---|---|---|---|
FREE_SHIPPING_THRESHOLD | 200 | number (BRL) | Cálculo do carrinho, banner de frete grátis, progresso no mini-cart |
SHIPPING_COST_DEFAULT | 19.90 | number (BRL) | Simulação de frete antes do CEP, resumo do pedido |
Estoque e catálogo
| Constante | Valor | Tipo | Onde é usado |
|---|---|---|---|
LOW_STOCK_THRESHOLD | 5 | number | Badge "Restam X unidades", alerta de estoque baixo no admin |
NEW_PRODUCT_DAYS | 30 | number (dias) | Badge "Novo" em produtos criados nos últimos N dias |
Paginação
| Constante | Valor | Tipo | Onde é usado |
|---|---|---|---|
DEFAULT_PAGE_SIZE | 20 | number | Listagem de produtos, histórico de pedidos, tabelas do admin |
MAX_PAGE_SIZE | 100 | number | Limite máximo aceito pela API em queries paginadas |
Identidade da loja
| Constante | Valor | Tipo | Onde é usado |
|---|---|---|---|
STORE_NAME | "LJ Velas & Aromas" | string | <title>, OG tags, e-mails transacionais, rodapé |
STORE_DOMAIN | "ljvelasearomas.com.br" | string | URLs canônicas, links em e-mails, sitemap |
STORE_WHATSAPP | "5513981629679" | string | Link direto wa.me/5513981629679, botão de suporte |
4. Status Maps
Definidos em lib/design-tokens.ts. Mapeiam cada valor de enum de status para um conjunto de tokens visuais (label, cor de fundo, cor de texto, cor de borda).
ORDER_STATUS_MAP — Status de Pedido
| Status | Label PT-BR | Paleta | Classe badge (exemplo) |
|---|---|---|---|
PENDING | Aguardando | Âmbar | bg-yellow-100 text-yellow-800 border-yellow-300 |
CONFIRMED | Confirmado | Azul | bg-blue-100 text-blue-800 border-blue-300 |
PROCESSING | Em preparo | Roxo | bg-purple-100 text-purple-800 border-purple-300 |
SHIPPED | Enviado | Índigo | bg-indigo-100 text-indigo-800 border-indigo-300 |
DELIVERED | Entregue | Sage | bg-sage-100 text-sage-700 border-sage-300 |
CANCELLED | Cancelado | Vermelho | bg-red-100 text-red-800 border-red-300 |
REFUNDED | Reembolsado | Cinza | bg-gray-100 text-gray-700 border-gray-300 |
PAYMENT_STATUS_MAP — Status de Pagamento
| Status | Label PT-BR | Paleta | Classe badge (exemplo) |
|---|---|---|---|
PENDING | Aguardando pagamento | Âmbar | bg-yellow-100 text-yellow-800 border-yellow-300 |
PROCESSING | Processando | Azul | bg-blue-100 text-blue-800 border-blue-300 |
PAID | Pago | Sage | bg-sage-100 text-sage-700 border-sage-300 |
FAILED | Falhou | Vermelho | bg-red-100 text-red-800 border-red-300 |
REFUNDED | Reembolsado | Cinza | bg-gray-100 text-gray-700 border-gray-300 |
CANCELLED | Cancelado | Vermelho | bg-red-100 text-red-800 border-red-300 |
Os status maps são consumidos pelos componentes
<OrderStatusBadge>e<PaymentStatusBadge>, que aceitam o enum e automaticamente aplicam o estilo correto. Não replique essa lógica em componentes individuais.
5. Animações
Definidas em tailwind.config.ts sob a chave theme.extend.animation e theme.extend.keyframes. A maioria usa tailwindcss-animate como base para as animações de acordeão.
Tabela de animações
| Nome | Classe Tailwind | Duração | Easing | Use case |
|---|---|---|---|---|
fade-in | animate-fade-in | 500ms | ease-in-out | Entrada de página, modais, skeleton → conteúdo |
slide-up | animate-slide-up | 400ms | ease-out | Cards entrando na viewport, toasts |
slide-in-r | animate-slide-in-r | 350ms | ease-out | Drawer lateral, sidebar mobile, painel de filtros |
pulse-soft | animate-pulse-soft | 2s | — (infinite) | Skeleton loading, indicadores de "ao vivo" |
shimmer | animate-shimmer | 1.5s | — (infinite) | Skeleton com gradiente deslizante — loading de cards |
float | animate-float | 3s | — (infinite) | Elemento decorativo flutuante no hero |
marquee | animate-marquee | 25s | linear (infinite) | Faixa de logos/benefícios em loop horizontal |
accordion-down | animate-accordion-down | — | — | Expansão de accordions (via tailwindcss-animate) |
accordion-up | animate-accordion-up | — | — | Colapso de accordions (via tailwindcss-animate) |
Notas de uso
shimmer: requer um gradiente definido no keyframe —background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.4) 50%, transparent 100%). Combinar combg-primary-100oubg-gray-100como base.marquee: o container pai precisa deoverflow-hidden. O conteúdo interno deve ser duplicado para criar o loop contínuo sem saltos.- Preferência por movimento reduzido: envolva animações decorativas em
@media (prefers-reduced-motion: no-preference)ou use a variantmotion-safe:animate-*do Tailwind.
6. Como Usar Tokens em Código
6.1 Em classes Tailwind (JSX)
A forma mais comum — use diretamente nos atributos className:
// Cor de texto primária
<p className="text-primary-700">Descrição do produto</p>
// Background dourado com texto escuro
<button className="bg-gold-400 text-deep rounded-btn px-8 py-4 font-montserrat font-semibold shadow-gold">
Adicionar ao Carrinho
</button>
// Badge de status com paleta sage
<span className="bg-sage-100 text-sage-700 border border-sage-300 rounded-pill px-3 py-1 text-sm">
Em estoque
</span>
// Card de produto
<div className="bg-white rounded-card shadow-warm hover:shadow-warm-lg transition-shadow">
{/* conteúdo do card */}
</div>
// Animação de entrada
<section className="animate-fade-in">
{/* conteúdo */}
</section>
6.2 Em TypeScript — importando design-tokens.ts
Use quando precisar dos valores em lógica de negócio, testes ou configurações de bibliotecas externas (ex: Chart.js, React Native, e-mail HTML):
import { colors, BRAND_COLORS, ORDER_STATUS_MAP, PAYMENT_STATUS_MAP } from '@/lib/design-tokens'
// Acessando uma cor da paleta
const primaryColor = colors.primary[500] // "#b96828"
const goldCTA = colors.gold[400] // "#F4C430"
const sageSuccess = colors.sage[500] // "#2D7A5F"
// Usando BRAND_COLORS para valores semânticos nomeados
const brandGold = BRAND_COLORS.goldRadiant // "#F4C430"
const brandDeep = BRAND_COLORS.deep // "#1A1410"
const brandCream = BRAND_COLORS.cream // "#FFF8E7"
// Resolvendo status de pedido dinamicamente
const statusConfig = ORDER_STATUS_MAP['DELIVERED']
// → { label: 'Entregue', bgClass: 'bg-sage-100', textClass: 'text-sage-700', ... }
6.3 Em estilos inline
Necessário quando uma biblioteca de terceiros não aceita classes Tailwind (ex: componentes de gráfico, mapas, editores rich-text):
import { BRAND_COLORS } from '@/lib/design-tokens'
// Em um componente com estilo inline
<div style={{ backgroundColor: BRAND_COLORS.cream, color: BRAND_COLORS.deep }}>
Conteúdo
</div>
// Em configuração de biblioteca (ex: Chart.js)
const chartOptions = {
plugins: {
legend: {
labels: {
color: BRAND_COLORS.deep,
font: { family: 'Montserrat' }
}
}
},
scales: {
x: { grid: { color: colors.primary[100] } },
y: { grid: { color: colors.primary[100] } }
}
}
6.4 Em CSS/SCSS (admin)
As variáveis do admin são usadas diretamente em CSS:
.admin-card {
background-color: var(--admin-surface);
border: 1px solid var(--admin-border);
color: var(--admin-text);
}
.admin-sidebar-item:hover {
background-color: var(--admin-accent-subtle);
color: var(--admin-sidebar-active-text);
}
7. Adicionando Novos Tokens
Ao adicionar qualquer novo token de design, siga obrigatoriamente os passos abaixo:
Passo 1 — tailwind.config.ts
Adicione o novo token na seção theme.extend correspondente:
// tailwind.config.ts
theme: {
extend: {
colors: {
// nova paleta ou nível
primary: { 975: '#0F0C0A' }
},
boxShadow: {
'nova-sombra': '0 8px 32px -4px rgba(61,40,23,0.16)'
},
borderRadius: {
'novo-radius': '2rem'
}
}
}
Passo 2 — lib/design-tokens.ts
Adicione o mesmo valor como constante TypeScript, espelhando o que foi definido no Tailwind:
// lib/design-tokens.ts
export const colors = {
primary: {
// ...valores existentes...
975: '#0F0C0A', // ← novo nível
}
}
export const shadows = {
// ...sombras existentes...
novaSombra: '0 8px 32px -4px rgba(61,40,23,0.16)', // ← nova sombra
}
Passo 3 — Documentar aqui
Adicione o novo token na tabela correspondente deste documento (docs/design/tokens.md), incluindo:
- Nome do token (classe Tailwind e/ou constante TypeScript)
- Valor (hex, px, string CSS)
- Uso semântico — onde e quando deve ser usado
Regras de nomeação
- Nomes de token devem ser descritivos do uso, não do valor. ✅
shadow-warm— não ❌shadow-brown-12. - Novas paletas de cor devem seguir o padrão de escala 50–950.
- Constantes de negócio devem estar em
SCREAMING_SNAKE_CASE. - Tokens TypeScript de cor devem estar em
camelCase.
8. Tokens do Admin
O admin usa CSS custom properties em vez de classes Tailwind de cor, permitindo troca de tema via JavaScript ou CSS sem recompilar.
Variáveis CSS — valores padrão (tema claro)
| Variável CSS | Valor padrão | Propósito |
|---|---|---|
--admin-bg | #f9fafb (gray-50) | Fundo geral da página do admin |
--admin-surface | #ffffff | Superfície de cards, formulários, tabelas |
--admin-surface-raised | #ffffff com sombra | Modais, popovers — elevação visual via sombra |
--admin-border | #e5e7eb (gray-200) | Bordas padrão — inputs, separadores, linhas de tabela |
--admin-border-strong | #d1d5db (gray-300) | Bordas de ênfase — foco de input, alertas |
--admin-text | #111827 (gray-900) | Texto primário — labels, valores de célula |
--admin-text-secondary | #6b7280 (gray-500) | Texto secundário — descrições, metadados, placeholders |
--admin-text-disabled | #9ca3af (gray-400) | Texto desabilitado — campos readonly, botões inativos |
--admin-accent | #2563eb (blue-600) | Acento principal — botões primários, links ativos |
--admin-accent-hover | #1d4ed8 (blue-700) | Hover do botão primário do admin |
--admin-accent-subtle | #eff6ff (blue-50) | Background de item selecionado, highlight de linha |
--admin-sidebar-bg | #1e293b (slate-800) | Fundo da barra lateral |
--admin-sidebar-text | #cbd5e1 (slate-300) | Texto de item de menu inativo |
--admin-sidebar-muted | #64748b (slate-500) | Ícones e texto secundário da sidebar |
--admin-sidebar-active-bg | #2563eb (blue-600) | Background do item de menu ativo |
--admin-sidebar-active-text | #ffffff | Texto do item de menu ativo |
--admin-sidebar-border | #334155 (slate-700) | Linha divisória interna da sidebar |
Sombras do admin
| Variável / Token | Valor CSS | Propósito |
|---|---|---|
shadow-admin | 0 1px 3px 0 rgba(0,0,0,0.10), 0 1px 2px -1px rgba(0,0,0,0.10) | Containers, cards base do admin |
shadow-admin-md | 0 4px 6px -1px rgba(0,0,0,0.10), 0 2px 4px -2px rgba(0,0,0,0.10) | Cards com maior elevação, sidepanels |
shadow-admin-lg | 0 10px 15px -3px rgba(0,0,0,0.10), 0 4px 6px -4px rgba(0,0,0,0.10) | Modais, drawers, overlays do admin |
Preparação para dark mode
Para ativar um tema escuro no admin, basta sobrescrever as variáveis CSS em um seletor de tema:
/* globals.css ou admin-theme.css */
[data-theme="dark"] .admin-layout,
.admin-layout.dark {
--admin-bg: #0f172a; /* slate-900 */
--admin-surface: #1e293b; /* slate-800 */
--admin-surface-raised: #334155; /* slate-700 */
--admin-border: #334155;
--admin-border-strong: #475569;
--admin-text: #f1f5f9;
--admin-text-secondary: #94a3b8;
--admin-text-disabled: #475569;
/* demais variáveis... */
}
Nenhum componente React precisa ser alterado — eles já usam as variáveis CSS e herdarão os novos valores automaticamente.