ITpS

Desenvolver

Com shadcn-vue

Como usar Sinapse + shadcn-vue em Vue 3 / Nuxt. Tokens semantic compatíveis — componentes shadcn-vue ficam Sinapse-coral automático.

Por que funciona

shadcn-vue usa os mesmos semantic tokens que a Sinapse @itps/styles: --primary, --background, --card, etc. Carregando nossa CSS entry, os componentes shadcn-vue viram coral Sinapse automaticamente — sem fork, sem patch.

1 · Setup

Instalar tudo

Terminal

# 1. Tailwind v4 (se ainda não tem)
pnpm add tailwindcss

# 2. shadcn-vue init (cria components.json, alias, etc)
pnpm dlx shadcn-vue@latest init

# 3. Sinapse tokens — workspace OU copy
#    workspace: pnpm add @itps/styles --workspace
#    copy:       cp <repo-sinapse>/packages/styles/*.css ./assets/styles/

2 · CSS entry

Importar Sinapse no main.css

shadcn-vue cria por default um app/assets/index.css com os semantic vars. Substitua por @itps/styles:

app/assets/index.css

@import "tailwindcss";
@import "@itps/styles";  /* nossa CSS — sobrescreve defaults shadcn-vue */

3 · Adicionar componentes

CLI shadcn-vue

pnpm dlx shadcn-vue@latest add button
pnpm dlx shadcn-vue@latest add card
pnpm dlx shadcn-vue@latest add dialog    # Modal
pnpm dlx shadcn-vue@latest add tabs
pnpm dlx shadcn-vue@latest add select
# ... etc — veja shadcn-vue.com/docs/components

Componentes Vue ficam em app/components/ui/. Use direto:

<script setup>
import { Button } from '@/components/ui/button'
</script>

<template>
  <Button>Salvar</Button>           <!-- coral Sinapse -->
  <Button variant="outline">Cancelar</Button>
</template>

4 · Componentes Sinapse drop-in

Substitua os gerados pra ficar 1:1 com o DS

O Button.vue que a CLI shadcn-vue gera tem styling próprio (radius, altura, hover) — coral mas não idêntico ao Sinapse. Substitua o conteúdo de cada arquivo em app/components/ui/ pelos snippets abaixo. Wrappers finos que usam .itps-* — um source of truth (components.css).

Button.vue

app/components/ui/button/Button.vue

<script setup lang="ts">
defineProps<{
  variant?: 'primary' | 'secondary' | 'ghost' | 'outline'
  size?: 'sm' | 'md' | 'lg'
}>()
</script>

<template>
  <button
    :class="[
      'itps-btn',
      `itps-btn--${$props.variant ?? 'primary'}`,
      $props.size && $props.size !== 'md' && `itps-btn--${$props.size}`,
    ]"
  >
    <slot />
  </button>
</template>

Card.vue

app/components/ui/card/Card.vue

<script setup lang="ts">
defineProps<{ elevated?: boolean }>()
</script>

<template>
  <div :class="['itps-card', $props.elevated && 'itps-card--elevated']">
    <slot />
  </div>
</template>

Chip.vue

app/components/ui/chip/Chip.vue

<script setup lang="ts">
defineProps<{
  variant?: 'default' | 'primary' | 'success' | 'warning' | 'danger'
}>()
</script>

<template>
  <span
    :class="[
      'itps-chip',
      $props.variant && $props.variant !== 'default' && `itps-chip--${$props.variant}`,
    ]"
  >
    <slot />
  </span>
</template>

Callout.vue

app/components/ui/callout/Callout.vue

<script setup lang="ts">
defineProps<{
  variant?: 'default' | 'info' | 'success' | 'warning' | 'danger'
}>()
</script>

<template>
  <div
    :class="[
      'itps-callout',
      $props.variant && $props.variant !== 'default' && `itps-callout--${$props.variant}`,
    ]"
  >
    <slot />
  </div>
</template>

Input.vue

app/components/ui/input/Input.vue

<script setup lang="ts">
defineProps<{ error?: boolean }>()
const model = defineModel<string>()
</script>

<template>
  <input
    v-model="model"
    :class="['itps-input', $props.error && 'itps-input--error']"
  />
</template>

Field.vue

app/components/ui/field/Field.vue

<script setup lang="ts">
defineProps<{
  label?: string
  hint?: string
  error?: string
  id?: string
}>()
</script>

<template>
  <div class="itps-field">
    <label v-if="label" :for="id" class="itps-field__label">{{ label }}</label>
    <slot :id="id" />
    <p v-if="error" class="itps-field__error">{{ error }}</p>
    <p v-else-if="hint" class="itps-field__hint">{{ hint }}</p>
  </div>
</template>

5 · Componentes Sinapse-only

RiskClassification, DataOverlay, FeedbackIcon

Estes 3 componentes não existem em shadcn-vue (são domain-specific de saúde pública). Pegue o HTML+classes da página de cada um em /componentes e converta pra Vue SFC manualmente.

Próximos passos

Onde ir