Documentación / Skill

supafast-ui

Construir o editar UI con el sistema de diseño "supafast" — el lenguaje visual de apps/performancetv en fenix: React 19 + Tailwind v4 (CSS-first, @theme inline) + shadcn estilo "base-nova" sobre @base-ui/react (NO Radix) + CVA + Geist + tokens oklch. Usar SIEMPRE que se cree/modifique un componente, página, formulario, tabla, nav, card, badge, botón, switch, dialog o layout en este estilo, o cuando el usuario pida algo "rápido", "limpio", "monocromo neutro" o "como performancetv". Cubre tokens de color/radio/tipografía, idioms de componentes base-ui+cva, layout/navegación y motion.

supafast-ui — sistema de diseño rápido y limpio

Lenguaje visual destilado de apps/performancetv. Objetivo: UI que se monta rápido, se ve limpia y profesional (monocromo neutro + acentos semánticos), y es consistente con el resto de fenix sin reinventar nada.

Regla de oro #1 — NO crear controles sueltos. Prohibido escribir un <button>, <input>, <select> o cualquier control con clases ad-hoc. Antes de crear CUALQUIER elemento de UI (sobre todo un botón) es OBLIGATORIO revisar el inventario de componentes (abajo) y reutilizar el que exista. Un <button className="..."> a pelo en una página es un error de revisión.

Si necesitas un botón (o control) que crees que no existe: NO lo improvises. Primero (1) confirma en el inventario y en src/shared/components/ui/ que de verdad no está; (2) mira si es una variante de uno existente (entonces se añade a su cva, no se crea nada nuevo); (3) si realmente falta, consulta antes de crearlo — propón añadirlo a ui/ siguiendo el idiom base-ui, no lo metas inline en la pantalla.

Regla de oro #2 — tokens, no valores ad-hoc. No inventes tokens, radios, sombras ni colores. Todo sale de los tokens semánticos (bg-background, text-muted-foreground, rounded-lg…). Si crees que falta uno, casi siempre ya existe el equivalente.

El stack exacto (no sustituir piezas)

  • React 19 + Vite + react-router v7 + TanStack Query + Zustand.
  • Tailwind v4 CSS-first: tokens en :root, mapeo en @theme inline dentro de src/index.css. No hay tailwind.config.js. No usar sintaxis v3.
  • shadcn estilo base-nova (ver components.json), baseColor neutral, iconos lucide-react.
  • @base-ui/react como primitiva headless — NO Radix. Esto cambia los idioms: useRender + mergeProps en vez de asChild; estados data-checked: / data-unchecked: en vez de data-[state=checked].
  • CVA (class-variance-authority) para variantes + cn() (clsx + tailwind-merge).
  • Geist Variable (sans) + Geist Mono, base font-size: 15px.

Decisiones de diseño que definen el look

Tema Decisión
Color Monocromo neutro (oklch grises). Acentos solo para significado: emerald=éxito, amber=aviso, destructive=error, rose=delta negativo/quitar, --chart-series=dato de gráfica. Fondos tenues (-50,/10) + texto saturado (-600/700). Nada de gradientes ni color de marca random. Detalle completo en references/colors.md.
Radio rounded-lg para controles (botones, inputs, nav items), pill rounded-4xl para badges, rounded-2xl para paneles. Tokens: --radius-control/-surface/-panel.
Sombras Mínimas: shadow-xs/shadow-sm solo en switch/elementos flotantes. Las superficies se separan con border border-border, no con sombra.
Tipografía Títulos de sección text-xl font-semibold; cuerpo text-sm; metadatos text-xs text-muted-foreground. Pesos font-medium/font-semibold, rara vez bold.
Foco Siempre focus-visible:ring-[3px] focus-visible:ring-ring/50 (+ focus-visible:border-ring).
Espaciado Secciones con space-y-4; grupos con gap-1.5/gap-2/gap-3. Densidad media, generoso pero no aireado.
Motion transition-colors/transition-all con duration-200 y curvas ease-out/ease-in-out. Animaciones decorativas vía keyframes en @theme (ver logo).

Inventario de componentes (CONSULTA OBLIGATORIA antes de crear nada)

Antes de maquetar cualquier control, comprueba aquí (y en src/shared/components/ui/) si ya existe. Para botones: SIEMPRE Button de @/shared/components/ui/button con su variant/size. Nunca un <button> suelto.

Primitivas @/shared/components/ui/: badge · button · calendar · chart · dialog · dropdown-menu · field · input · password-input · popover · select · separator · sheet · switch · tabs · textarea · toggle · toggle-group

Compuestos reutilizables (@/shared/components/...): data-table/EntityDataTable (tablas) · data-table/EntityTableToolbar (orden/filtros) · data-table/EntityTableSearch · SectionBlock (secciones) · Sidebar · Logo.

Mapa rápido “necesito X → usa Y”:

  • ¿un botón / CTA / acción / icon-button? → Button (variant: default/outline/secondary/ghost/destructive/link; size: xs/sm/default/lg/icon…). Polimórfico con render={<NavLink/>}.
  • ¿campo de texto? → Input; ¿multilínea? → Textarea; ¿contraseña? → PasswordInput (con ojo).
  • ¿label+control+error? → Field/FieldLabel/FieldError.
  • ¿elegir una opción / ordenar / filtrar? → menú (EntityTableToolbar o DropdownMenu), nunca <select>. Ver references/menus-selects.md.
  • ¿tabla/listado? → EntityDataTable. ¿on/off? → Switch. ¿etiqueta de estado? → Badge.
  • ¿modal? → Dialog; ¿panel lateral? → Sheet; ¿flotante? → Popover; ¿pestañas? → Tabs.

Cómo trabajar (flujo)

  1. PARA. Consulta el inventario de arriba. ¿Existe el componente? → reúsalo tal cual. Esto es obligatorio antes de escribir una sola etiqueta de UI; vale especialmente para botones.
  2. ¿Existe pero te falta un look? → es una variante: añádela al cva(...) del componente (p.ej. buttonVariants), nunca clases sueltas en el call site ni un control nuevo a pelo.
  3. ¿De verdad no existe? → no lo improvises inline. Consúltalo / propón crearlo en ui/ siguiendo el idiom de @base-ui/react (useRender+mergeProps) — ver references/components.md. Sin Radix.
  4. Usa siempre tokens semánticos y cn() para componer clases. Nunca colores hex inline si hay token.
  5. Lucide para iconos, tamaño size-4 por defecto (size-3 dentro de badges).

Sub-skills (referencias — léelas según la tarea)

Esta master enruta a fichas especializadas. Carga solo la que toque:

  • references/stack.md — stack tecnológico completo: versiones exactas (React 19, Vite 6, Tailwind v4, @base-ui, React Query, Zustand…), scripts, alias @/, config de Vite y organización del código. Léela al configurar deps, añadir librerías o dudar de qué pieza usar.
  • references/base-components.md — ⭐ la base: código fuente verbatim de Button, Input, Textarea, PasswordInput (con ojo) y Field + ejemplos de uso (botones, campos de formulario, estados de error). Empieza aquí al construir botones, inputs o formularios; cópialos y extiéndelos.
  • references/tables.md — ⭐ tablas con EntityDataTable (dirigido por columnas), código verbatim, render por celda, hover/selección, vacío, skeleton. Léela al montar cualquier tabla/listado.
  • references/detail-popover.md — ⭐ ampliar detalle: cuando quieres expandir algo resumido (celda de tabla, valor truncado) NO se abre un modal, se despliega un Popover anclado al elemento, con tarjeta key-value (labels en mayúsculas, valores mono, secretos enmascarados, botón Copiar). Código verbatim (ObjectiveTechnicalCredentialsCell, CopyValueButton, Popover). Léela para “ver detalle” desde una tabla o cualquier resumen clave→valor copiable.
  • references/colors.md — ⭐ cómo se aplica el color: roles semánticos (emerald=éxito, amber=aviso, destructive=error, rose=delta negativo/quitar, --chart-series=dato) con uso real y tabla de decisión. Léela siempre que vayas a colorear algo (estados, deltas, badges, charts).
  • references/tokens.md — paleta oklch cruda, escala de radios, tipografía Geist, el bloque @theme inline. Léela al tocar index.css, declarar tokens o radios.
  • references/menus-selects.md — ⭐ NO usamos <select> nativo: para elegir opciones se usa un menú (trigger Button outline + chevron + ítems con check). Código verbatim del “Ordenar” (EntityTableToolbar) y del DropdownMenu base-ui. Léela al hacer selects, orden, filtros o menús de acciones.
  • references/interaction-patterns.md — ⭐ idioms transversales que el usuario corrige siempre a la misma forma: pills de filtro/vista sueltas estilo Linear (activa secondary / inactiva ghost, rounded-full, bajo el titular, sin track), ⓘ + Tooltip en cards (el absolute va en el wrapper del Tooltip), alturas fijas (dialog fijo + invisible para reservar hueco), iconos de estado solo cuando comunican, segmented control w-fit, CTA de crear primary, y toasts con «Deshacer» en acciones reversibles. Léela al montar filtros, vistas, cards, toasts o menús de acciones.
  • references/components.md — el idiom base-ui (useRender/mergeProps), patrón CVA, anatomía de button/badge/switch, estados data-checked, focus rings. Léela al crear/editar cualquier componente de ui/.
  • references/layout.md — sidebar colapsable, NavLink activo/inactivo, SectionBlock, cards con borde, grids y densidad. Léela al montar páginas, navegación o estructura.
  • references/motion.md — transiciones, duraciones, keyframes en @theme, animaciones de logo/shimmer. Léela al animar algo.

Anti-patrones (no hacer)

  • Botones/controles sueltos: <button className="…"> o <input> a pelo en una pantalla. Usa Button/Input/etc. del inventario. Si falta algo, consulta antes de crearlo, no lo improvises inline.
  • ❌ Radix (@radix-ui/*), asChild, data-[state=...]. Aquí es base-ui.
  • tailwind.config.js o sintaxis Tailwind v3.
  • ❌ Colores de marca, gradientes, sombras grandes, glassmorphism. Esto es sobrio y neutro.
  • ❌ Clases sueltas repetidas en vez de extender el cva del componente.
  • ❌ Hex inline (#3080ff) cuando existe el token (text-blue-500/semántico).
  • ❌ Tamaños de fuente arbitrarios; usa la escala (text-xs/sm/base/lg/xl).
  • <select> nativo o el Select de shadcn por defecto para elegir opciones → usa un menú (trigger outline + ítems con check). Ver references/menus-selects.md.
  • ❌ Escribir <table>/<thead> a mano por pantalla → usa EntityDataTable + columnas. Ver references/tables.md.
  • <Input type="password"> pelado → usa PasswordInput (lleva el toggle del ojo). Ver references/base-components.md.

Exportar Skill

Descarga los archivos de esta skill para integrarlos en tu entorno local.