Tokens de marca
Cuatro hex y un gradiente derivan todo el CSS por color-mix; cambiar la paleta es editar un bloque.
Empezar
Fundamentos
Componentes
Convenciones
Changelog
La guía del starter EchoSistema: cómo correrlo, dónde vive cada cosa y cómo usar los tokens y componentes del sistema.
Starter Nuxt de los sitios de plataforma del grupo: el Liquid Glass entero parametrizado por cuatro tokens de marca.
Cuatro hex y un gradiente derivan todo el CSS por color-mix; cambiar la paleta es editar un bloque.
Paridad automática: todo valor tematizable tiene gemelo dark, y el tema correcto pinta antes del primer paint.
Español canónico en la raíz, pt-BR e inglés con prefijo, catálogo único y locales en lockstep.
Dialog, details y selects del navegador vestidos por el sistema: accesibilidad gratis.
pnpm instala, corre y valida. Los mismos scripts del package.json, sin pasos escondidos.
| Comando | Papel |
|---|---|
pnpm dev | Servidor de desarrollo con hot reload. |
pnpm build | Build de producción (SSR). |
pnpm generate | Sitio estático prerenderizado. |
pnpm preview | Sirve el build de producción localmente. |
pnpm lint | ESLint en todo el proyecto. |
pnpm typecheck | vue-tsc sobre la app y la configuración. |
Layout estándar de Nuxt 4: app/ es el sitio, i18n/ los textos, shared/ lo que servidor y cliente comparten.
app/ assets/css/main.css components/ composables/ data/ layouts/ pages/ plugins/ utils/ i18n/locales/ shared/ nuxt.config.ts
main.css es el único punto de entrada de estilo: los .vue no cargan style. El catálogo de idiomas vive en shared/languages.ts y la navegación en app/data/nav.ts.
El bloque MARCA al tope del main.css es el único lugar con hex de marca.
Fondos, textos, vidrio, botones y el panel de código derivan de estos cuatro tokens vía color-mix, con paridad claro/oscuro automática. Para rebautizar un sitio derivado, cambia este bloque y nada más; las paletas agro y consumer quedan comentadas en el archivo como ejemplo.
:root {
--brand-1: #426ab2;
--brand-2: #40c1c3;
--brand-deep: #040b2d;
--brand-link: #3d91cf;
}El tema gira en html[data-theme]; el idioma es dueño de la URL.
data-theme
Un script pre-paint en el head lee la preferencia guardada (o la del sistema) y define data-theme antes del primer paint: sin flash de tema equivocado. El cambio en runtime es el mismo atributo.
prefix_except_default
El español canónico vive sin prefijo; /pt-BR y /en prefijan las demás rutas. Agregar un idioma es una entrada en el catálogo de shared/languages.ts más el archivo de locale correspondiente.
El contenido semántico se viste por el contenedor: .es-prose estiliza los elementos de adentro.
Títulos, párrafos, citas, código y los demás elementos de texto ganan el estilo del sistema al entrar en una .es-prose, sin utility por elemento. Las familias cargadas son Manrope, Montserrat y JetBrains Mono.
<div class="es-prose">
<h2>…</h2>
<p>…</p>
<blockquote>…</blockquote>
</div>Los 41 componentes de app/components/echo, por papel. Cada uno viste un elemento nativo cuando existe: de ahí vienen teclado, foco y anuncio, sin reimplementación.
Button · Chip · Badge · Pill · Dropdown · Pagination · Breadcrumb · Tabs
Input · Textarea · Select · SearchSelect · TagsInput · Checkbox · Radio · Switch · Slider · Rating · FileButton · Dropzone
Alert · Modal · Drawer · Toaster · Block · Skeleton · Spinner · Progress · Ring
Card · List · ListItem · DataTable · Avatar · Gallery · Tree · Timeline · Collapse · Divider · Stat · Player
Dos ejes que nunca se combinan a mano: .es-i--* da el color, la variante lo consume.
Diez intenciones definen tokens locales (--i, --i-on, --i-grad y derivados) que las cuatro familias de etiqueta y el modal consumen. Las variantes (filled, gradient, outline, glass, ghost) se escriben una sola vez.
<echo-button variant="filled" intent="danger">…</echo-button>
<echo-chip variant="soft" intent="info">…</echo-chip>
<echo-badge variant="filled" intent="success">…</echo-badge>
<echo-pill variant="outline" intent="caution">…</echo-pill>Ocho tonos sobre la misma paleta, con la cuña de acento en el borde.
Cuatro semánticos de estado (info, success, warn, danger) y cuatro tonales nombrados (caution, steel-blue, navy-blue, dark). El texto queda en los grises del tema; el acento entra en el ícono, el título y la cuña.
<echo-alert tone="success" title="…">
…
</echo-alert>El dialog nativo: foco atrapado, Esc, fondo inerte y borroso.
Superficie opaca del tema, cuña de intención como en los alerts, fondo ilegible por el blur mientras está abierto y scroll trabado. El clic afuera no cierra; cierran el Esc, el cerrar del encabezado y las acciones del pie. El ancho sigue la escala sm, md, lg, xl y xxl.
<echo-modal ref="modal" title-id="…"
intent="warning" size="lg">
<template #title>…</template>
…
<template #footer>…</template>
</echo-modal>
modal.value?.open()Entrar, crear cuenta, recuperar y cambiar la contraseña, y la sesión bloqueada. Cinco componentes listos en app/components/auth/, sobre el mismo echo-modal.
Los cinco siguen el mismo contrato: open() y close() expuestos por ref, un submit con los datos, y nada de red por dentro. Quien sabe la URL, el token y qué hacer con la respuesta es la aplicación — el componente solo recoge, valida lo que no depende del servidor y devuelve.
<auth-login-modal
ref="login"
:pending="sending"
:error="failure"
logo="/img/minha-marca.svg"
title="Entrar no painel"
@submit="signIn"
@forgot="forgot?.open()"
@register="register?.open()"
/>
login.value?.open()El submit sale en el vocabulario de la API, no en el de las variables internas: mandar el payload directo al endpoint es el caso común, y traducir nombres de campo en cada sitio derivado sería el mismo de-para escrito muchas veces.
| Componente | Campos del submit | Eventos |
|---|---|---|
<auth-login-modal> | email, password, remember | @submit @forgot @register |
<auth-register-modal> | name, email, gender (m|f|o), birth_date (yyyy-mm-dd), password, password_confirmation, terms (1|0) | @submit @login |
<auth-forgot-password-modal> | email | @submit @login |
<auth-update-password-modal> | password, password_confirmation | @submit |
<auth-lock-modal> | password | @submit @sign-out |
Las props son las mismas en los cinco, con dos excepciones anotadas. Todas son opcionales.
logo
Arte del encabezado, cuando el modal representa otra marca que no es la del sitio. Sin ella, el logo del sitio.
title
Título propio en lugar del texto estándar del flujo.
pending
Bloquea los campos y cambia la etiqueta del botón mientras corre su llamada.
error
Mensaje del servidor, mostrado en una alerta sobre el formulario. Quien lo limpia es quien lo pasó.
sent
Solo en el de recuperación: cambia el formulario por la confirmación de envío. Es del llamador, porque quien sabe que el pedido llegó es quien lo hizo.
name / avatar
Solo en el de bloqueo: nombre y retrato de quien tiene la sesión trabada.
Campos sobre la tinta de la lente y el details nativo de tarjeta.
es-input sirve para input y textarea; es-select es el select nativo con la misma tinta. El es-collapse viste el details del navegador: abre, cierra y es accesible sin una línea de JS.
<echo-input v-model="email" type="email" />
<echo-textarea v-model="message" rows="3" />
<echo-select v-model="topic">…</echo-select>
<echo-collapse>
<template #summary>…</template>
…
</echo-collapse>Las convenciones que valen para todo sitio derivado.
Ningún bloque style en .vue: utility en el template y el resto en main.css.
Hex crudo en template es hallazgo; la marca entera vive en el bloque MARCA.
Toda clase componente y token del sistema usa el prefijo, renombrable en un replace global.
Todo texto verificado contra el campo real; color de acento no es color de texto.
prefers-reduced-motion y prefers-reduced-transparency respetados por toda animación y vidrio.
Español canónico; toda string de interfaz vía t(), los contratos quedan literales.
¿Una duda que la documentación no cubre?
Habla con el grupo EchoSistema en echosistema.online.
Lo que cambió en el template, de lo más reciente hacia atrás.