4. Design System
Este documento define o sistema de design para soluções web desenvolvidas com Astro 5, estabelecendo padrões visuais consistentes e componentes reutilizáveis.
Tokens de Design
Os tokens de design são valores fundamentais que definem a aparência visual da aplicação. Eles são implementados através da configuração do Tailwind CSS.
Cores
// tailwind.config.js (trecho)module.exports = { theme: { extend: { colors: { // Cores primárias primary: { 50: '#f0f7ff', 100: '#e0effe', 200: '#bae0fd', 300: '#90cafc', 400: '#5eaef8', 500: '#3b91f2', 600: '#2574e7', 700: '#1d5cd4', 800: '#1e4bab', 900: '#1e4285', 950: '#162a54', }, // Cores secundárias secondary: { 50: '#f5f7fa', 100: '#ebeef3', 200: '#d2dae5', 300: '#acbcce', 400: '#8098b2', 500: '#5f7b98', 600: '#4a637e', 700: '#3d5267', 800: '#354557', 900: '#2f3c4a', 950: '#1e2631', }, // Cores de feedback success: { 50: '#f0fdf4', 500: '#22c55e', 700: '#15803d', }, warning: { 50: '#fffbeb', 500: '#f59e0b', 700: '#b45309', }, error: { 50: '#fef2f2', 500: '#ef4444', 700: '#b91c1c', }, info: { 50: '#f0f9ff', 500: '#0ea5e9', 700: '#0369a1', }, // Tons neutros neutral: { 50: '#f9fafb', 100: '#f3f4f6', 200: '#e5e7eb', 300: '#d1d5db', 400: '#9ca3af', 500: '#6b7280', 600: '#4b5563', 700: '#374151', 800: '#1f2937', 900: '#111827', 950: '#030712', }, }, }, },};Uso de Cores
- Cores primárias: Usadas para elementos principais, CTA e branding
- Cores secundárias: Usadas para elementos complementares e acentos
- Cores de feedback: Usadas para mensagens de sucesso, erro, alerta e informação
- Tons neutros: Usados para texto, fundos e elementos estruturais
Tipografia
// tailwind.config.js (trecho)const defaultTheme = require('tailwindcss/defaultTheme');
module.exports = { theme: { extend: { fontFamily: { sans: ['Inter var', ...defaultTheme.fontFamily.sans], display: ['Lexend', ...defaultTheme.fontFamily.sans], mono: ['JetBrains Mono', ...defaultTheme.fontFamily.mono], }, fontSize: { xs: ['0.75rem', { lineHeight: '1rem' }], sm: ['0.875rem', { lineHeight: '1.25rem' }], base: ['1rem', { lineHeight: '1.5rem' }], lg: ['1.125rem', { lineHeight: '1.75rem' }], xl: ['1.25rem', { lineHeight: '1.75rem' }], '2xl': ['1.5rem', { lineHeight: '2rem' }], '3xl': ['1.875rem', { lineHeight: '2.25rem' }], '4xl': ['2.25rem', { lineHeight: '2.5rem' }], '5xl': ['3rem', { lineHeight: '1' }], '6xl': ['3.75rem', { lineHeight: '1' }], }, fontWeight: { thin: '100', extralight: '200', light: '300', normal: '400', medium: '500', semibold: '600', bold: '700', extrabold: '800', black: '900', }, }, },};Hierarquia Tipográfica
| Elemento | Classe | Uso |
|---|---|---|
| Heading 1 | text-4xl font-bold text-neutral-900 | Títulos principais de página |
| Heading 2 | text-3xl font-bold text-neutral-900 | Seções principais |
| Heading 3 | text-2xl font-semibold text-neutral-800 | Subseções |
| Heading 4 | text-xl font-semibold text-neutral-800 | Grupos de conteúdo |
| Heading 5 | text-lg font-medium text-neutral-800 | Títulos menores |
| Heading 6 | text-base font-medium text-neutral-800 | Subtítulos menores |
| Body | text-base text-neutral-700 | Texto principal |
| Small | text-sm text-neutral-600 | Texto secundário, legendas |
| XSmall | text-xs text-neutral-500 | Metadados, notas de rodapé |
Espaçamento
O sistema de espaçamento segue uma escala consistente, implementada através das classes de espaçamento do Tailwind:
// tailwind.config.js (trecho)module.exports = { theme: { extend: { spacing: { // Valores personalizados adicionais, se necessário '4.5': '1.125rem', // 18px '13': '3.25rem', // 52px '15': '3.75rem', // 60px }, }, },};Escala de Espaçamento
| Tamanho | Valor | Uso |
|---|---|---|
| 0 | 0px | Sem espaçamento |
| px | 1px | Bordas finas |
| 0.5 | 0.125rem (2px) | Espaçamento mínimo |
| 1 | 0.25rem (4px) | Espaçamento muito pequeno |
| 2 | 0.5rem (8px) | Espaçamento pequeno |
| 3 | 0.75rem (12px) | Espaçamento médio-pequeno |
| 4 | 1rem (16px) | Espaçamento base |
| 6 | 1.5rem (24px) | Espaçamento médio |
| 8 | 2rem (32px) | Espaçamento grande |
| 12 | 3rem (48px) | Espaçamento muito grande |
| 16 | 4rem (64px) | Espaçamento extra grande |
| 20 | 5rem (80px) | Espaçamento 2x extra grande |
| 24 | 6rem (96px) | Espaçamento 3x extra grande |
Componentes Base
Botões
Os botões seguem uma hierarquia visual clara para indicar importância e função:
---const { variant = 'primary', size = 'md', class: className, disabled = false, type = 'button', ...props} = Astro.props;
const variantClasses = { primary: 'bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500', secondary: 'bg-secondary-100 text-secondary-700 hover:bg-secondary-200 focus:ring-secondary-500', outline: 'bg-white border border-neutral-300 text-neutral-700 hover:bg-neutral-50 focus:ring-primary-500', ghost: 'text-neutral-700 hover:bg-neutral-100 focus:ring-neutral-500', danger: 'bg-error-600 text-white hover:bg-error-700 focus:ring-error-500',};
const sizeClasses = { sm: 'px-2.5 py-1.5 text-xs', md: 'px-4 py-2 text-sm', lg: 'px-5 py-2.5 text-base', xl: 'px-6 py-3 text-base',};
const baseClasses = 'inline-flex items-center justify-center font-medium rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed';const classes = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${className || ''}`;---
<button type={type} disabled={disabled} class={classes} {...props}> <slot /></button>Uso dos Botões
<Button>Botão Padrão</Button><Button variant="secondary">Botão Secundário</Button><Button variant="outline">Botão Outline</Button><Button variant="ghost">Botão Ghost</Button><Button variant="danger">Botão de Perigo</Button>
<Button size="sm">Pequeno</Button><Button size="md">Médio</Button><Button size="lg">Grande</Button><Button size="xl">Extra Grande</Button>
<Button disabled>Botão Desabilitado</Button>
<Button> <Icon name="plus" class="w-4 h-4 mr-2" /> Com Ícone</Button>Cards
Cards são contêineres versáteis para agrupar conteúdo relacionado:
---const { padding = 'normal', shadow = 'md', border = false, hover = false, class: className, ...props} = Astro.props;
const paddingClasses = { none: '', small: 'p-3', normal: 'p-4', large: 'p-6',};
const shadowClasses = { none: '', sm: 'shadow-sm', md: 'shadow', lg: 'shadow-lg',};
const borderClass = border ? 'border border-neutral-200' : '';const hoverClass = hover ? 'transition-all hover:shadow-lg' : '';
const classes = `bg-white rounded-lg ${paddingClasses[padding]} ${shadowClasses[shadow]} ${borderClass} ${hoverClass} ${className || ''}`;---
<div class={classes} {...props}> <slot /></div>Uso dos Cards
<Card> <h3 class="text-xl font-semibold mb-2">Título do Card</h3> <p>Conteúdo do card com texto informativo.</p></Card>
<Card padding="large" shadow="lg" border={true} hover={true}> <h3 class="text-xl font-semibold mb-2">Card com Opções</h3> <p>Card com padding grande, sombra grande, borda e efeito hover.</p></Card>
<Card padding="none" class="overflow-hidden"> <img src="/images/example.jpg" alt="Exemplo" class="w-full h-48 object-cover" /> <div class="p-4"> <h3 class="text-xl font-semibold mb-2">Card com Imagem</h3> <p>Card com imagem e conteúdo.</p> </div></Card>Formulários
Componentes de formulário com estilo consistente e acessível:
---const { id, label, type = 'text', placeholder, required = false, disabled = false, error, helpText, class: className, ...props} = Astro.props;
const baseClasses = 'block w-full rounded-md shadow-sm focus:ring-primary-500 focus:border-primary-500 sm:text-sm';const stateClasses = error ? 'border-error-300 text-error-900 placeholder-error-300' : 'border-neutral-300 placeholder-neutral-400';const disabledClasses = disabled ? 'bg-neutral-100 cursor-not-allowed' : '';const classes = `${baseClasses} ${stateClasses} ${disabledClasses} ${className || ''}`;---
<div class="mb-4"> {label && ( <label for={id} class="block text-sm font-medium text-neutral-700 mb-1"> {label} {required && <span class="text-error-500">*</span>} </label> )}
<input id={id} type={type} placeholder={placeholder} required={required} disabled={disabled} class={classes} aria-invalid={error ? 'true' : 'false'} aria-describedby={error ? `${id}-error` : helpText ? `${id}-description` : undefined} {...props} />
{error && ( <p id={`${id}-error`} class="mt-1 text-sm text-error-600"> {error} </p> )}
{helpText && !error && ( <p id={`${id}-description`} class="mt-1 text-sm text-neutral-500"> {helpText} </p> )}</div>Outros Componentes de Formulário
Seguindo o mesmo padrão, crie componentes para:
- Select
- Checkbox
- Radio
- Textarea
- Toggle
- DatePicker
- FileUpload
Sistema de Grid e Layout
Container
---const { size = 'default', class: className, ...props} = Astro.props;
const sizeClasses = { sm: 'max-w-3xl', default: 'max-w-5xl', lg: 'max-w-7xl', xl: 'max-w-[90rem]', full: 'max-w-none',};
const classes = `mx-auto px-4 sm:px-6 lg:px-8 ${sizeClasses[size]} ${className || ''}`;---
<div class={classes} {...props}> <slot /></div>Grid
Utilize as classes de grid do Tailwind:
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6"> <Card>Item 1</Card> <Card>Item 2</Card> <Card>Item 3</Card> <!-- ... --></div>Seções
---const { spacing = 'default', background = 'white', class: className, ...props} = Astro.props;
const spacingClasses = { small: 'py-4 md:py-6', default: 'py-8 md:py-12', large: 'py-12 md:py-16', xl: 'py-16 md:py-24',};
const backgroundClasses = { white: 'bg-white', light: 'bg-neutral-50', dark: 'bg-neutral-900 text-white', primary: 'bg-primary-50', secondary: 'bg-secondary-50',};
const classes = `${spacingClasses[spacing]} ${backgroundClasses[background]} ${className || ''}`;---
<section class={classes} {...props}> <slot /></section>Responsividade e Acessibilidade
Breakpoints
Seguimos os breakpoints padrão do Tailwind:
| Breakpoint | Tamanho | Descrição |
|---|---|---|
sm | 640px | Dispositivos pequenos (smartphones em paisagem) |
md | 768px | Tablets |
lg | 1024px | Laptops/Desktops pequenos |
xl | 1280px | Desktops |
2xl | 1536px | Telas grandes |
Diretrizes de Acessibilidade
-
Contraste de Cores
- Texto: Relação de contraste mínima de 4.5:1
- Elementos grandes e cabeçalhos: Relação de contraste mínima de 3:1
-
Foco Visível
- Todos os elementos interativos devem ter um estado de foco visível
- Use
focus:ring-2 focus:ring-offset-2 focus:ring-primary-500
-
Semântica HTML
- Use tags HTML semânticas (
<button>,<nav>,<main>, etc.) - Estruture o conteúdo com hierarquia adequada de cabeçalhos
- Use tags HTML semânticas (
-
Atributos ARIA
- Use atributos ARIA apenas quando necessário
- Exemplos:
aria-label,aria-expanded,aria-controls
-
Tamanho de Toque
- Elementos interativos devem ter pelo menos 44x44px em dispositivos móveis
Implementação no Tailwind
Configure o arquivo tailwind.config.js para implementar o design system:
const defaultTheme = require('tailwindcss/defaultTheme');
module.exports = { content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], theme: { extend: { colors: { // Cores do design system (conforme definido acima) }, fontFamily: { // Famílias de fontes (conforme definido acima) }, fontSize: { // Tamanhos de fonte (conforme definido acima) }, spacing: { // Espaçamentos personalizados (conforme definido acima) }, borderRadius: { 'sm': '0.125rem', DEFAULT: '0.25rem', 'md': '0.375rem', 'lg': '0.5rem', 'xl': '0.75rem', '2xl': '1rem', '3xl': '1.5rem', 'full': '9999px', }, boxShadow: { sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)', DEFAULT: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)', md: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)', lg: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)', xl: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)', '2xl': '0 25px 50px -12px rgb(0 0 0 / 0.25)', inner: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)', none: 'none', }, }, }, plugins: [ require('@tailwindcss/forms'), require('@tailwindcss/typography'), require('@tailwindcss/aspect-ratio'), ],};Conclusão
Este design system fornece uma base sólida para criar interfaces consistentes, acessíveis e visualmente atraentes. Ele deve evoluir com o projeto, mantendo a documentação atualizada conforme novos componentes e padrões são adicionados.
Os próximos documentos detalharão outros aspectos do desenvolvimento:
- Componentes: Biblioteca de componentes reutilizáveis
- Integração com Astro: Recursos específicos do Astro
- Otimizações de Performance: Estratégias para melhorar a performance
Última atualização: 21 de março de 2025