Desenvolver
Usando os tokens
Tutorial passo a passo — do zero até o primeiro botão Sinapse rodando no seu stack (React, Vue 3, Nuxt 4 ou Astro).
Tutorial · ~10 min
O caminho mais curto pro Sinapse rodar
- 1. Pré-requisito: Tailwind v4
- 2. Instalar
@itps/styles - 3. Importar no CSS entry
- 4. Validar — primeiro botão
- 5. Snippets prontos (Button/Card/Banner/Form)
- 6. Adaptar pro seu framework
- 7. Componentes interativos
1 · Pré-requisito
Tailwind v4 configurado
O Sinapse depende de Tailwind v4 — os @theme inline mappings e @utility helpers
são features novas da v4. Se ainda não tem, siga o guia oficial do Tailwind pro seu framework antes de continuar.
Verificação rápida
# package.json deve listar:
"tailwindcss": "^4.0.0" 2 · Copiar os arquivos .css
Copie e cole os 3 arquivos abaixo no seu projeto
Sem npm, sem git clone, sem submodule. Crie a pasta src/assets/styles/sinapse/ (ou equivalente) no seu projeto e
copie o conteúdo dos 3 blocos abaixo em arquivos com os mesmos nomes.
Estrutura final no seu projeto
src/
└── assets/
└── styles/
└── sinapse/
├── tokens.css ← cole o conteúdo do bloco abaixo
├── components.css ← cole o conteúdo do bloco abaixo
└── index.css ← cole o conteúdo do bloco abaixo Copie os 3. Não tem decisão a tomar — funciona pra qualquer caminho (snippets do /componentes, shadcn-vue, shadcn, Preline ou Tailwind direto).
Arquivo 1 de 3 tokens.css 444 linhas
Paleta OKLCH (coral, azul, neutros, feedback), tokens semantic (--primary, --background, etc), dark mode, e Tailwind utilities (bg-primary, text-foreground).
/* ==========================================================================
0. DARK VARIANT — Tailwind v4
--------------------------------------------------------------------------
Registra `.dark` como seletor pro variant `dark:` do Tailwind v4
(default seria prefers-color-scheme). Necessário pra permitir toggle
manual via classe .dark no <html>.
========================================================================== */
@custom-variant dark (&:where(.dark, .dark *));
/* ==========================================================================
1. PRIMITIVE TOKENS
--------------------------------------------------------------------------
Paleta crua. Espelha 1:1 a estrutura do Figma do DS ITpS.
NÃO usar diretamente em componentes — sempre via semantic tokens.
========================================================================== */
:root {
/* --- Base scale (neutros) --- */
--itps-base-0: oklch(1.0000 0.0000 0); /* #FFFFFF */
--itps-base-50: oklch(0.9851 0.0000 0); /* #FAFAFA */
--itps-base-100: oklch(0.9551 0.0000 0); /* #F0F0F0 */
--itps-base-200: oklch(0.8452 0.0000 0); /* #CCCCCC */
--itps-base-300: oklch(0.7668 0.0000 0); /* #B3B3B3 */
--itps-base-400: oklch(0.6830 0.0000 0); /* #999999 */
--itps-base-500: oklch(0.5999 0.0000 0); /* #808080 */
--itps-base-600: oklch(0.5658 0.0000 0); /* #767676 - accessible-min */
--itps-base-700: oklch(0.4202 0.0000 0); /* #4D4D4D */
--itps-base-800: oklch(0.3211 0.0000 0); /* #333333 */
--itps-base-900: oklch(0.2178 0.0000 0); /* #1A1A1A */
--itps-base-950: oklch(0.0000 0.0000 0); /* #000000 */
/* --- Primary (coral) --- */
--itps-primary-50: oklch(0.9808 0.0064 17.27); /* #FDF7F7 */
--itps-primary-100: oklch(0.9613 0.0131 23.19); /* #FBEFEE */
--itps-primary-200: oklch(0.9198 0.0345 20.01); /* #FBDCDB */
--itps-primary-300: oklch(0.8699 0.0573 20.99); /* #F8C6C4 */
--itps-primary-400: oklch(0.8519 0.0661 22.01); /* #F7BEBB */
--itps-primary-500: oklch(0.8211 0.0813 21.79); /* #F5B0AD */
--itps-primary-600: oklch(0.7849 0.1010 22.60); /* #F39F9B */
--itps-primary-700: oklch(0.7322 0.1319 24.17); /* #F0857F */
--itps-primary-800: oklch(0.6987 0.1531 24.63); /* #EE736D */
--itps-primary-900: oklch(0.6619 0.1762 25.88); /* #EB5E57 - default */
--itps-primary-950: oklch(0.5602 0.2076 25.22); /* #D3242D */
/* --- Secondary (azul institucional) --- */
--itps-secondary-25: oklch(0.9906 0.0017 247.84); /* #FBFCFD */
--itps-secondary-50: oklch(0.9842 0.0034 247.86); /* #F8FAFC */
--itps-secondary-100: oklch(0.9428 0.0121 247.95); /* #E6EDF4 */
--itps-secondary-200: oklch(0.9108 0.0191 248.04); /* #D8E3EE */
--itps-secondary-300: oklch(0.8481 0.0389 248.29); /* #BAD0E6 */
--itps-secondary-400: oklch(0.7469 0.0778 250.66); /* #88B1DD */
--itps-secondary-500: oklch(0.6882 0.0970 250.73); /* #6C9FD5 */
--itps-secondary-600: oklch(0.6218 0.1189 251.92); /* #4D8ACC */
--itps-secondary-700: oklch(0.5811 0.1320 252.46); /* #397DC6 */
--itps-secondary-800: oklch(0.5306 0.1200 252.60); /* #326EAF */
--itps-secondary-900: oklch(0.4911 0.1378 253.53); /* #1961AC - default */
--itps-secondary-950: oklch(0.4298 0.1197 253.56); /* #14508F */
/* --- Terciary (neutro esverdeado) ---
Escala parcial: 50, 100, 300, 500. Steps faltantes serão adicionados sob demanda. */
--itps-terciary-50: oklch(0.9776 0.0021 197.12); /* #F6F8F8 */
--itps-terciary-100: oklch(0.9219 0.0086 197.01); /* #DFE7E7 */
--itps-terciary-300: oklch(0.8940 0.0132 185.06); /* #D3DFDD */
--itps-terciary-500: oklch(0.8425 0.0122 170.20); /* #C4CECA */
/* --- Feedback / alert (amarelo) ---
Namespace da designer: feedback/alert/<step>. Steps especiais formalizados:
- 950 (min-graphics): mínimo p/ ícone/linha sobre branco passar WCAG
- 1000 (min-text): mínimo p/ TEXTO sobre branco passar WCAG */
--itps-alert-100: oklch(0.9857 0.0126 86.83); /* #FEFAF1 */
--itps-alert-200: oklch(0.9587 0.0382 90.65); /* #FBF1D5 */
--itps-alert-600: oklch(0.9109 0.0841 90.31); /* #F7E0A1 */
--itps-alert-800: oklch(0.8766 0.1128 89.25); /* #F4D37C */
--itps-alert-900: oklch(0.8423 0.1392 88.83); /* #F0C653 */
--itps-alert-950: oklch(0.6677 0.1288 86.51); /* #B78E1D — min-graphics */
--itps-alert-1000: oklch(0.5680 0.1168 82.85); /* #986F00 — min-text */
/* --- Feedback: success (verde) --- */
--itps-success-100: oklch(0.9820 0.0084 168.76); /* #F4FBF8 */
--itps-success-200: oklch(0.9291 0.0368 168.35); /* #D1F0E3 */
--itps-success-600: oklch(0.7980 0.1004 166.59); /* #79D2AF */
--itps-success-800: oklch(0.6503 0.1523 157.35); /* #09AA69 */
--itps-success-900: oklch(0.5280 0.1253 157.19); /* #00804D */
/* Destructive: coral (--itps-primary-*) é single source of truth para danger/feedback. */
}
/* ==========================================================================
2. SEMANTIC TOKENS — shadcn-vue
--------------------------------------------------------------------------
Tokens que os componentes shadcn esperam.
Cada um aponta pra um primitive da camada 1.
Trocando o valor aqui, o look-and-feel do app inteiro muda.
========================================================================== */
:root {
/* === ARQUITETURA ===
Camada 1: Primitives (--itps-*) — paleta crua OKLCH.
Camada 2: Semantic shadcn (--background, --foreground, --primary, --destructive, etc) — CANONICAL.
Componentes consomem APENAS camada 2 via utility (bg-background, text-foreground, etc).
DARK MODE: redefinir camada 2 dentro de .dark { ... }. */
/* --- Surfaces & containers (canonical shadcn) --- */
--background: var(--itps-base-0); /* #FFFFFF — canvas */
--foreground: var(--itps-base-950); /* #000000 — text principal */
--card: var(--itps-base-50); /* #FAFAFA — canvas elevado */
--card-foreground: var(--itps-base-950);
--popover: var(--itps-base-0);
--popover-foreground: var(--itps-base-950);
--muted: var(--itps-base-100); /* #F0F0F0 — container interativo */
--muted-foreground: var(--itps-base-700); /* #5C5C5C — 5.87:1 sobre muted (AA) */
/* --- Brand semantic — primitives diretos --- */
/* Primary (coral - identidade ITpS)
fg=base-950 sobre coral = 6.27:1 (AA). White seria 3.35 (FAIL AA-text). */
--primary: var(--itps-primary-900); /* #EB5E57 */
--primary-foreground: var(--itps-base-950); /* #000000 */
/* Secondary (azul institucional — tinted surface) */
--secondary: var(--itps-secondary-100);
--secondary-foreground: var(--itps-secondary-950);
/* Accent (terciary tinted surface) */
--accent: var(--itps-terciary-100);
--accent-foreground: var(--itps-base-950);
/* Destructive (= feedback/danger = coral) */
--destructive: var(--itps-primary-900);
--destructive-foreground: var(--itps-base-950); /* preto sobre coral = 6.27:1 AA */
/* --- Borders & inputs --- */
--border: var(--itps-base-100);
--input: var(--itps-base-100);
--ring: var(--itps-primary-900);
/* --- Feedback semantic (extensão shadcn — não-padrão mas comum) --- */
/* Danger alias (= destructive) */
--danger: var(--itps-primary-900);
--danger-foreground: var(--itps-base-950); /* preto sobre coral = 6.27:1 AA */
/* Success (estado de sucesso) */
--success: var(--itps-success-900);
--success-foreground: var(--itps-base-0);
/* Warning (atenção, não-crítico)
fg=base-950 (preto) sobre alert-900 (#F0C653) = 12.91:1 AAA.
alert-1000 é mustard escuro pra texto sobre branco — falha sobre alert-900. */
--warning: var(--itps-alert-900);
--warning-foreground: var(--itps-base-950);
/* Info (mensagens informativas) */
--info: var(--itps-secondary-900);
--info-foreground: var(--itps-base-0);
/* --- Radius ---
Escala Tailwind v4 default + 3 tokens semânticos por uso.
- card (12px) = containers, cards, panels
- form (999px) = buttons em formato pill
- circle (999px) = avatares, badges circulares, dots */
--radius: 0.5rem; /* shadcn alias — 8px */
--rounded-card: 0.75rem; /* 12px */
--rounded-form: 9999px; /* pill */
--rounded-circle: 9999px; /* circle / pill */
/* --- Charts (5 slots pra séries categóricas — vírus, regiões, períodos) ---
Paleta inicial mapeada pra primitives. Refinar quando dashboards forem implementados. */
--chart-1: var(--itps-secondary-900); /* azul */
--chart-2: var(--itps-success-800); /* verde */
--chart-3: var(--itps-alert-900); /* amarelo */
--chart-4: var(--itps-primary-900); /* coral */
--chart-5: var(--itps-secondary-500); /* azul claro */
/* --- Effects (shadows + blur) ---
Sombras tintadas azul institucional (#14508F com 10% alpha).
Hierarquia: medium=cards, large=overlays, extra-large=pop-ups.
2-layer composition (sharp close + soft distant). */
--shadow-medium:
0 1px 2px 0 rgb(20 80 143 / 0.10),
0 4px 6px -1px rgb(20 80 143 / 0.10);
--shadow-large:
0 4px 6px -4px rgb(20 80 143 / 0.10),
0 10px 15px -3px rgb(20 80 143 / 0.10);
--shadow-extra-large:
0 8px 10px -6px rgb(20 80 143 / 0.10),
0 20px 25px -5px rgb(20 80 143 / 0.10);
--blur-small: 4px;
/* --- 2k. Typography (font-family) ---
Open Sans single-family. Aliases font-heading/font-body deixam porta aberta
pra dual-font futuro sem refactor de componentes.
DECISÃO: Tailwind defaults canonical para text-*, tracking-*, etc.
Escala documentada em /estilos/tipografia mas NÃO sobrescreve Tailwind
globalmente — preserva a11y (rem) e evita
redimensionamento automático mobile que quebraria componentes não previstos. */
--font-sans: 'Open Sans', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-heading: var(--font-sans);
--font-body: var(--font-sans);
--font-mono: ui-monospace, SFMono-Regular, 'JetBrains Mono', 'Roboto Mono', Menlo, Consolas, monospace;
}
/* ==========================================================================
2z. DARK MODE
--------------------------------------------------------------------------
Estratégia: redefinir Layer 2 (state-aware) dentro de .dark.
Layer 3 (shadcn aliases) cascateia automático — referenciam Layer 2.
Primitives Layer 1 NÃO mudam.
Princípios:
- bg-default-1 = base-900 (#1A1A1A) — não puro black, mais elegante
- bg-default-2 = base-800 — leve elevação
- Surfaces ficam mais claros que canvas (oposto do light)
- Texto principal = base-50 (off-white, evita brilho excessivo)
- Borders mais sutis (base-800) pra não criar grade agressiva
- Brand primary mantém saturação (OKLCH 0.66 lightness funciona em dark)
- Feedbacks bg-default migram pra steps escuros tinted (saturação baixa)
========================================================================== */
.dark {
color-scheme: dark;
/* --- shadcn semantic (canonical) --- */
--background: var(--itps-base-900); /* #1A1A1A canvas */
--foreground: var(--itps-base-50); /* #FAFAFA texto principal */
--card: var(--itps-base-800); /* #333333 elevado */
--card-foreground: var(--itps-base-50);
--popover: var(--itps-base-800);
--popover-foreground: var(--itps-base-50);
--muted: var(--itps-base-800); /* container interativo */
--muted-foreground: var(--itps-base-300); /* WCAG AA em dark */
--primary-foreground: var(--itps-base-950); /* preto sobre coral = 6.27:1 AA */
--secondary: oklch(0.28 0.05 252); /* dark blue tinted */
--secondary-foreground: var(--itps-secondary-300); /* light blue text */
--accent: oklch(0.30 0.01 197); /* dark teal tinted */
--accent-foreground: var(--itps-base-50);
--destructive-foreground: var(--itps-base-950); /* preto sobre coral = 6.27:1 AA */
--border: var(--itps-base-800);
--input: var(--itps-base-800);
/* Feedback semantic em dark — usar primitives mais claros para contraste */
--success: var(--itps-success-600); /* #79D2AF claro em dark */
--success-foreground: var(--itps-base-950); /* black sobre verde claro */
--warning: var(--itps-alert-900); /* #F0C653 claro */
--warning-foreground: var(--itps-base-950); /* preto sobre amarelo = 12.91:1 AAA */
--info: var(--itps-secondary-400); /* #88B1DD claro em dark */
--info-foreground: var(--itps-base-950);
--danger-foreground: var(--itps-base-950); /* preto sobre coral = 6.27:1 AA */
/* --- SHADOWS — em dark, sombras tintadas viram inúteis. Override pra darken via overlay-black --- */
--shadow-medium:
0 1px 2px 0 rgb(0 0 0 / 0.20),
0 4px 6px -1px rgb(0 0 0 / 0.20);
--shadow-large:
0 4px 6px -4px rgb(0 0 0 / 0.20),
0 10px 15px -3px rgb(0 0 0 / 0.20);
--shadow-extra-large:
0 8px 10px -6px rgb(0 0 0 / 0.20),
0 20px 25px -5px rgb(0 0 0 / 0.20);
}
/* ==========================================================================
3. THEME MAPPING — Tailwind v4 @theme inline
--------------------------------------------------------------------------
Expõe os semantic tokens como utilitários: bg-primary, text-foreground, etc.
`inline` é importante: sem ele, perde o suporte a opacity modifiers
(ex: bg-primary/50).
========================================================================== */
@theme inline {
/* Surfaces */
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
/* Brand */
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
/* Neutral helpers */
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
/* Semantic states */
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-danger: var(--danger);
--color-danger-foreground: var(--danger-foreground);
--color-success: var(--success);
--color-success-foreground: var(--success-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
--color-info: var(--info);
--color-info-foreground: var(--info-foreground);
/* Borders / inputs */
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
/* State-aware semantic tokens são expostos via @utility blocks abaixo
(property-scoped — bg-disabled e border-disabled podem ter valores distintos). */
/* Charts */
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
/* Radius - shadcn-vue espera essas variantes calculadas a partir de --radius */
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
/* --- Brand scales (escalas completas como utilitários) ---
Permite bg-primary-50, text-secondary-300, hover:bg-primary-100 etc.
Dark mode futuro: redefinir os primitives `--itps-*` em .dark — utilitários
se adaptam automaticamente sem tocar em nenhuma classe. */
--color-base-0: var(--itps-base-0);
--color-base-50: var(--itps-base-50);
--color-base-100: var(--itps-base-100);
--color-base-200: var(--itps-base-200);
--color-base-300: var(--itps-base-300);
--color-base-400: var(--itps-base-400);
--color-base-500: var(--itps-base-500);
--color-base-600: var(--itps-base-600);
--color-base-700: var(--itps-base-700);
--color-base-800: var(--itps-base-800);
--color-base-900: var(--itps-base-900);
--color-base-950: var(--itps-base-950);
--color-primary-50: var(--itps-primary-50);
--color-primary-100: var(--itps-primary-100);
--color-primary-200: var(--itps-primary-200);
--color-primary-300: var(--itps-primary-300);
--color-primary-400: var(--itps-primary-400);
--color-primary-500: var(--itps-primary-500);
--color-primary-600: var(--itps-primary-600);
--color-primary-700: var(--itps-primary-700);
--color-primary-800: var(--itps-primary-800);
--color-primary-900: var(--itps-primary-900);
--color-primary-950: var(--itps-primary-950);
--color-secondary-25: var(--itps-secondary-25);
--color-secondary-50: var(--itps-secondary-50);
--color-secondary-100: var(--itps-secondary-100);
--color-secondary-200: var(--itps-secondary-200);
--color-secondary-300: var(--itps-secondary-300);
--color-secondary-400: var(--itps-secondary-400);
--color-secondary-500: var(--itps-secondary-500);
--color-secondary-600: var(--itps-secondary-600);
--color-secondary-700: var(--itps-secondary-700);
--color-secondary-800: var(--itps-secondary-800);
--color-secondary-900: var(--itps-secondary-900);
--color-secondary-950: var(--itps-secondary-950);
--color-terciary-50: var(--itps-terciary-50);
--color-terciary-100: var(--itps-terciary-100);
--color-terciary-300: var(--itps-terciary-300);
--color-terciary-500: var(--itps-terciary-500);
--color-alert-100: var(--itps-alert-100);
--color-alert-200: var(--itps-alert-200);
--color-alert-600: var(--itps-alert-600);
--color-alert-800: var(--itps-alert-800);
--color-alert-900: var(--itps-alert-900);
--color-alert-950: var(--itps-alert-950);
--color-alert-1000: var(--itps-alert-1000);
--color-success-100: var(--itps-success-100);
--color-success-200: var(--itps-success-200);
--color-success-600: var(--itps-success-600);
--color-success-800: var(--itps-success-800);
--color-success-900: var(--itps-success-900);
/* --- Typography (font-family) ---
Expõe font-sans/font-heading/font-body como utilitários Tailwind.
`font-mono` mantido p/ blocos de código.
Sizes/tracking permanecem Tailwind defaults — não sobrescrevemos aqui. */
--font-sans: var(--font-sans);
--font-heading: var(--font-heading);
--font-body: var(--font-body);
--font-mono: var(--font-mono);
}
/* ==========================================================================
4. UTILITIES — radius, shadows, blur, typography
--------------------------------------------------------------------------
Utilities customizadas que não são geradas automaticamente por @theme.
========================================================================== */
/* --- RADIUS semantic group ---
Use no lugar de rounded-* arbitrário. Cada role tem propósito explícito. */
@utility rounded-card { border-radius: var(--rounded-card); }
@utility rounded-form { border-radius: var(--rounded-form); }
@utility rounded-circle { border-radius: var(--rounded-circle); }
/* --- EFFECTS (sombras + blur) ---
Sombras tintadas azul institucional (#14508F com 10% alpha).
Hierarquia: medium=cards, large=overlays, extra-large=pop-ups. */
@utility shadow-medium { box-shadow: var(--shadow-medium); }
@utility shadow-large { box-shadow: var(--shadow-large); }
@utility shadow-extra-large { box-shadow: var(--shadow-extra-large); }
/* Aliases por use-case */
@utility shadow-card { box-shadow: var(--shadow-medium); }
@utility shadow-overlay { box-shadow: var(--shadow-large); }
@utility shadow-popup { box-shadow: var(--shadow-extra-large); }
@utility backdrop-blur-small { backdrop-filter: blur(var(--blur-small)); }
/* --- TYPOGRAPHY: italic combos + body/heading shortcuts ---
Designer nomeia presets compostos: italic-semibold (italic+600), italic-bold (italic+700).
Reproduz como @utility pra evitar repetir `italic font-semibold` em componentes. */
@utility italic-semibold {
font-style: italic;
font-weight: 600;
}
@utility italic-bold {
font-style: italic;
font-weight: 700;
} Arquivo 2 de 3 components.css 174 linhas
Classes prontas .itps-btn, .itps-card, .itps-chip, .itps-input, .itps-callout — atalhos usados pelos snippets do /componentes.
/* ==========================================================================
@itps/styles — Component classes
--------------------------------------------------------------------------
Framework-agnostic. Each app (Astro / Vue / React / Nuxt) writes a thin
markup wrapper that just applies these classes — zero JS variant engine,
zero runtime, zero per-framework lib to publish.
Naming: BEM-ish with `itps-` prefix to avoid collisions.
.itps-btn ← base
.itps-btn--primary ← variant
.itps-btn--sm ← size
.itps-btn.is-loading ← state (use `is-*` for boolean states)
Implementation: Tailwind v4 `@layer components` so consumers can still
override with utilities at the call site.
Tokens used (CANONICAL Layer 3 — shadcn aliases):
bg-background, bg-card, bg-muted, bg-popover, bg-accent
text-foreground, text-muted-foreground, text-card-foreground
bg-primary, text-primary-foreground
bg-secondary, text-secondary-foreground
bg-destructive, text-destructive-foreground
border-border, border-input, ring-ring
Feedback tinted utilities:
bg-success-default, text-success-default, bg-alert-default, etc
========================================================================== */
@layer components {
/* --- Button -------------------------------------------------------------- */
/* Sizes alinham com form-height tokens do DS:
sm = 40px, md = 48px (default), lg = 56px. */
.itps-btn {
@apply inline-flex items-center justify-center gap-2 select-none whitespace-nowrap
h-12 px-5
rounded-form
text-base font-semibold leading-none
transition-colors duration-150
focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-ring
disabled:cursor-not-allowed;
}
/* Primary — spec Figma "action / button / primary":
default = outline coral + texto azul institucional + ícones coral,
hover = filled coral + texto branco + ícones brancos,
disabled = muted cinza (sem borda visível). */
.itps-btn--primary {
@apply bg-transparent text-info
border border-primary
hover:bg-primary hover:text-white hover:border-primary
active:bg-primary-950 active:text-white
disabled:bg-muted disabled:text-muted-foreground disabled:border-transparent
disabled:hover:bg-muted disabled:hover:text-muted-foreground;
}
.itps-btn--primary > .material-symbols-outlined { color: var(--primary); }
.itps-btn--primary:hover:not(:disabled) > .material-symbols-outlined,
.itps-btn--primary:active:not(:disabled) > .material-symbols-outlined { color: #fff; }
.itps-btn--primary:disabled > .material-symbols-outlined,
.itps-btn--primary[aria-disabled="true"] > .material-symbols-outlined { color: var(--muted-foreground); }
/* Outline = alias do primary (mantém retrocompat com snippets antigos). */
.itps-btn--outline {
@apply bg-transparent text-info
border border-primary
hover:bg-primary hover:text-white hover:border-primary
active:bg-primary-950 active:text-white
disabled:bg-muted disabled:text-muted-foreground disabled:border-transparent
disabled:hover:bg-muted disabled:hover:text-muted-foreground;
}
.itps-btn--outline > .material-symbols-outlined { color: var(--primary); }
.itps-btn--outline:hover:not(:disabled) > .material-symbols-outlined,
.itps-btn--outline:active:not(:disabled) > .material-symbols-outlined { color: #fff; }
.itps-btn--outline:disabled > .material-symbols-outlined,
.itps-btn--outline[aria-disabled="true"] > .material-symbols-outlined { color: var(--muted-foreground); }
.itps-btn--secondary {
@apply bg-secondary text-secondary-foreground
hover:bg-secondary-200
active:bg-secondary-300
disabled:bg-muted disabled:text-muted-foreground;
}
.itps-btn--ghost {
@apply bg-transparent text-foreground
hover:bg-accent
active:bg-muted
disabled:text-muted-foreground disabled:hover:bg-transparent;
}
.itps-btn--sm { @apply h-10 px-4 text-sm; }
.itps-btn--lg { @apply h-14 px-6 text-xl; }
.itps-btn--icon { @apply w-12 px-0; }
.itps-btn--icon.itps-btn--sm { @apply w-10; }
.itps-btn--icon.itps-btn--lg { @apply w-14; }
/* --- Card ---------------------------------------------------------------- */
.itps-card {
@apply rounded-card border border-border bg-card text-card-foreground p-6;
}
.itps-card--elevated {
@apply border-transparent shadow-card;
}
/* --- Field (form row) ---------------------------------------------------- */
.itps-field {
@apply flex flex-col gap-1.5;
}
.itps-field__label {
@apply text-sm font-medium text-foreground;
}
.itps-field__hint {
@apply text-xs text-muted-foreground;
}
.itps-field__error {
@apply text-xs text-destructive;
}
/* --- Input --------------------------------------------------------------- */
.itps-input {
@apply w-full h-10 px-3
rounded-form
border border-input bg-background
text-sm text-foreground
placeholder:text-muted-foreground
transition-colors
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring
disabled:cursor-not-allowed disabled:bg-muted disabled:opacity-60;
}
.itps-input--error {
@apply border-destructive focus-visible:ring-destructive;
}
/* --- Chip / Badge -------------------------------------------------------- */
.itps-chip {
@apply inline-flex items-center gap-1
h-6 px-2
rounded-full
text-xs font-medium
bg-secondary text-secondary-foreground;
}
.itps-chip--primary { @apply bg-primary-100 text-primary-900; }
/* Feedback chips — shadcn pattern com opacity modifier para tinted bg */
.itps-chip--success { @apply bg-success/15 text-success; }
.itps-chip--warning { @apply bg-warning/20 text-warning-foreground; }
.itps-chip--danger { @apply bg-destructive/15 text-destructive; }
/* --- Link ---------------------------------------------------------------- */
.itps-link {
@apply text-foreground underline-offset-4
hover:underline hover:text-primary
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:rounded-sm;
}
/* --- Callout ------------------------------------------------------------- */
.itps-callout {
@apply flex gap-3
rounded-card border border-border
p-4
bg-card text-card-foreground;
}
/* Feedback callouts — shadcn pattern com opacity modifier */
.itps-callout--info { @apply border-info/30 bg-info/10 text-foreground; }
.itps-callout--success { @apply border-success/30 bg-success/10 text-foreground; }
.itps-callout--warning { @apply border-warning/30 bg-warning/15 text-foreground; }
.itps-callout--danger { @apply border-destructive/30 bg-destructive/10 text-foreground; }
}
Arquivo 3 de 3 index.css 18 linhas
Entry curtinho que importa os 2 acima. É o arquivo que você vai referenciar no passo 3.
/* ==========================================================================
@itps/styles — Entry point
--------------------------------------------------------------------------
Consumer must import "tailwindcss" (and optionally "tw-animate-css") BEFORE
this file, e.g.:
@import "tailwindcss";
@import "tw-animate-css";
@import "@itps/styles";
Or import parts only:
@import "@itps/styles/tokens.css";
@import "@itps/styles/components.css";
========================================================================== */
@import "./tokens.css";
@import "./components.css";
3 · Importar
Criar / editar o CSS entry do seu projeto
Crie (ou edite) o arquivo CSS principal do seu framework e adicione 2 @import — Tailwind primeiro, Sinapse depois.
O caminho do Sinapse aponta pros arquivos que você copiou no passo 2.
Astro
Crie: src/styles/global.css
@import "tailwindcss";
@import "../assets/styles/sinapse/index.css"; No src/layouts/BaseLayout.astro adicione: import '../styles/global.css'
Vue 3 (Vite)
Crie: src/assets/main.css
@import "tailwindcss";
@import "./styles/sinapse/index.css"; No src/main.ts: import './assets/main.css'
Nuxt 4
Crie: app/assets/css/main.css
@import "tailwindcss";
@import "../styles/sinapse/index.css"; No nuxt.config.ts: css: ['~/assets/css/main.css']
React / Next
Crie ou edite: app/globals.css (Next) ou src/index.css (Vite)
@import "tailwindcss";
@import "./styles/sinapse/index.css"; Next App Router já importa globals.css no app/layout.tsx. Vite: import './index.css' no main.tsx.
Variação dos caminhos
O @import do Sinapse usa caminho relativo à pasta do .css que está importando.
Se você copiou pra src/assets/styles/sinapse/, ajuste ./, ../ conforme onde o seu CSS entry mora.
Submodule (Modo B): @import "../../../vendor/sinapse/packages/styles/index.css"; — depende de profundidade.
4 · Validar
Primeiro botão — coral Sinapse
Cole esse HTML em qualquer página/componente. Se aparecer botão coral arredondado em pill, install funcionou.
<button type="button" class="inline-flex items-center gap-2 rounded-form
bg-primary px-5 py-3 text-sm font-medium
text-primary-foreground transition-colors
hover:bg-primary-800">
Sinapse rodando
<span class="material-symbols-outlined text-[18px]">check_circle</span>
</button>
✗ Sem cor coral? Verifique: (1) ordem do @import — Tailwind antes do Sinapse, (2) caminho do arquivo CSS no entry do framework, (3) Tailwind v4 instalado (não v3).
5 · Snippets prontos
Padrões core — Button, Card, Banner, Form
HTML + classes Tailwind. Cole no seu template e adapte só a sintaxe de class binding do seu framework (passo 6).
Card
Indicador epidemiológico
Casos confirmados nos últimos 7 dias.
<div class="rounded-card border border-border bg-card p-6 shadow-medium">
<h4 class="text-base font-semibold text-foreground">Título</h4>
<p class="mt-1 text-sm text-muted-foreground">Body</p>
</div> Banner (success)
Backup configurado
Backups diários às 02h.
<div class="flex items-start gap-3 rounded-card border border-success/30
bg-success/10 p-4 text-foreground">
<span class="material-symbols-outlined shrink-0 text-success"
style="font-size: 20px">check_circle</span>
<div class="flex flex-col gap-0.5">
<p class="text-sm font-medium text-foreground">Backup configurado</p>
<p class="text-[13px] text-muted-foreground">Backups diários às 02h.</p>
</div>
</div> Form field (label + input + helper)
Usamos somente para envio de releases internos.
<div class="flex flex-col gap-1.5">
<label for="email" class="text-sm font-medium text-foreground">Email</label>
<input type="email" id="email" placeholder="..."
class="rounded-form border border-input bg-background px-4 py-3
text-sm text-foreground placeholder:text-muted-foreground
focus:border-ring focus:outline-none focus:ring-2 focus:ring-ring/30" />
<p class="text-[13px] text-muted-foreground">Helper text</p>
</div> 6 · Adaptar pro framework
Mesmo HTML, sintaxes diferentes
Pegue qualquer snippet acima e adapte só duas coisas: como você escreve class e como você compõe o template.
Astro
---
const { label } = Astro.props;
---
<button class="bg-primary ...">
{label}
</button> Vue 3 / Nuxt 4 SFC
<script setup lang="ts">
defineProps<{ label: string }>()
</script>
<template>
<button class="bg-primary ...">
{{ label }}
</button>
</template> React / Next.js
export function Button({ label }: { label: string }) {
return (
<button className="bg-primary ...">
{label}
</button>
);
} HTML puro
<button class="bg-primary ...">
Click
</button> 7 · Interatividade
Modal, dropdown, tabs — engine headless do seu stack
Componentes interativos precisam de JavaScript. O Sinapse não distribui plugin JS ainda — use o engine headless padrão do seu framework e aplique as classes Sinapse aos primitives. Cada caminho tem guia dedicado:
Próximos passos