@unozero-ai/design-tokens
v0.3.0
Published
Tokens de diseño Unozero (marca + semánticos) para Tailwind v4 — fuente de verdad compartida entre chatbook/frontend-v2, Billia y futuros productos.
Readme
@unozero-ai/design-tokens
Este paquete es la autoridad. Cualquier token de marca o semántico que un producto necesite se define aquí primero y se consume por import. Un token declarado solo en el
globals.cssde una app es deriva, no una excepción: pórtalo antes de mergear (pnpm verify:paritylo detecta).
Tokens de diseño de Unozero (marca + semánticos) para Tailwind v4. Fuente de verdad única, compartible con cualquier producto Next.js del grupo (chatbook frontend-v2, Billia) que quiera la misma identidad visual.
Qué incluye
tokens.css— capa de marca (whitelabel), capa semántica (claro/oscuro), escala tipográfica, radios, sombras, easings, keyframes y utilidades de marca (bg-brand-gradient,scrollbar-thin, ...). Tailwind v4 puro (@theme inline), sin JS. Incluye la densidad:data-density="cozy"en<html>(o en un subárbol) escala todo el espaciado y el texto pequeño de la UI, de panel (36 px) a cómoda (48 px), sin props en los componentes.base.css— reglas de página que consumen esos tokens (tipografía de títulos, focus ring, selección). Opcional: una landing puede preferir su propio reset y solo tomartokens.css.channels.css— lienzos de canales de terceros (hoy WhatsApp:--wa-canvas,--wa-bubble-out,--wa-link, …) para previsualizar dentro del producto qué verá el huésped. Opt-in a propósito: no son marca, y un producto que no dibuja previews de WhatsApp no debería heredarlos como si fueran paleta disponible.fonts.ts— las 3 fuentes de marca (IBM Plex Sans, Manrope, JetBrains Mono) cargadas víanext/font/google, con los mismos nombres de variable CSS que esperatokens.css. Antes cada app redefinía estas llamadas por su cuenta, con riesgo de que divergieran (otro subset, otro peso, otrodisplay); ahora se importan ya configuradas.presets.ts— White Label: datos (presets de paleta) y funciones puras (sin React) para leer/aplicar/resetear la tríada de marca (--brand-cyan/blue/purple/dark) en el DOM. Cualquier producto arma su propia pantalla de ajustes de tenant reusando estas funciones — la UI de referencia vive enapps/showcase.
Qué NO incluye (a propósito)
- Componentes React (Button, Modal, DataTable…) — viven en
@unozero-ai/ui, que va encima de este paquete. Solo para productos "de trabajo" (apps funcionales); las landings consumen únicamente estos tokens y arman sus propios componentes de presentación.
Uso en una app Next.js + Tailwind v4
En app/globals.css de la app consumidora:
@import "tailwindcss";
@import "@unozero-ai/design-tokens/tokens.css";
@import "@unozero-ai/design-tokens/base.css"; /* opcional */En app/layout.tsx:
import { brandFontVariables } from "@unozero-ai/design-tokens/fonts";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="es" className={`${brandFontVariables} h-full`}>
<body className="font-sans antialiased">{children}</body>
</html>
);
}Y en next.config.ts de la app consumidora, agregar el paquete a
transpilePackages (se distribuye como fuente TS/CSS, sin build propio):
const nextConfig: NextConfig = {
transpilePackages: ["@unozero-ai/design-tokens"],
};Ver todos los tokens en acción
apps/showcase (en este mismo repo) es la página viva de referencia —
White Label (presets + edición color por color), tipografía, colores,
radios, sombras, easings y animaciones, al estilo del showcase de
PrimeFaces. pnpm --filter showcase dev y abrir localhost:3200.
Estado actual
v0.3.0 suma la densidad de toda la UI, las curvas de movimiento
(--ease-out, --ease-in-out, --ease-drawer) y overflow-x: clip en
base.css, que con hidden rompía todo position: sticky.
v0.2.0 — paridad total con chatbook/frontend-v2. El
paquete nació el 27-jul-2026 como extracción de frontend-v2/app/globals.css y
quedó dos commits por detrás: --grid-line (31-jul) y los ocho --wa-* (4-ago,
en un fix de la preview de WhatsApp). Ambos están portados —los --wa-* en
channels.css— y pnpm verify:parity confirma 248 declaraciones a cada lado,
cero divergencias de valor.
Público, y por qué
Se publica en el npm público bajo el scope @unozero-ai, no en un registry
privado. La razón no es abrir el código: es que un paquete privado obliga a
repartir credenciales de GCP por cada sitio que instale — el Dockerfile de cada
producto, cada CI, y cualquier host fuera de GCP (Vercel, Netlify) donde el
token de una hora de Artifact Registry no sirve como variable de entorno. Lo que
hay dentro son colores, radios, tipografías y presets de paleta; nada que la
política de caja negra proteja, y nada que la web pública del producto no diga
ya.
license: UNLICENSED es deliberado: el paquete es visible, no es software
libre. Se publica para poder instalarlo sin credenciales, no para cederlo.
Lo que falta
- Publicar ya no es a mano: cada push a
mainque suba la versión de un paquete lo publica.github/workflows/publish.yml. - En
frontend-v2:pnpm add @unozero-ai/design-tokens, añadirtranspilePackages: ["@unozero-ai/design-tokens"]ennext.config.ts, y dejarglobals.cssen sus imports + el bloque de Quill (que es de un editor de terceros, no del sistema). Verificar con un diff degetComputedStyleantes/después, no con capturas. - Borrar
scripts/verify-parity.mjs: cuando la app no declare tokens propios, deja de tener sentido.
Después de eso, el segundo consumidor (Billia) es lo que prueba de verdad que el paquete es reutilizable y no solo un archivo mudado de sitio.
