Docs: Crear documentación definitiva del sistema de temas
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 52s

- Crear THEME_SYSTEM.md como documento único y completo
- Eliminar DEVELOPER_GUIDE.md y THEME_CUSTOMIZATION.md (desactualizados)
- Actualizar README.md con referencia al nuevo documento
- Incluye arquitectura, variables, reglas, ejemplos y troubleshooting
- Documentación clara para usuarios y desarrolladores
This commit is contained in:
2025-10-30 17:18:32 -06:00
parent 5500c83f9f
commit bc02bc6bde
4 changed files with 672 additions and 798 deletions

View File

@@ -1,419 +0,0 @@
# Guía de Desarrollo - Sistema de Temas
## Introducción
Esta guía está dirigida a desarrolladores que trabajan en Analítica Núcleo y necesitan entender cómo funciona el sistema de temas y cómo mantener la consistencia visual en toda la aplicación.
## Principios Fundamentales
### 1. Siempre Usa Variables CSS
**✅ CORRECTO:**
```vue
<div class="bg-[var(--brand-surface)] border-[var(--brand-border)] text-[var(--brand-text)]">
Contenido
</div>
```
**❌ INCORRECTO:**
```vue
<div class="bg-[#1f180f] border-[#3a2a16] text-[#fef9f0]">
Contenido
</div>
```
**❌ INCORRECTO:**
```vue
<div class="bg-gray-900 border-gray-800 text-white">
Contenido
</div>
```
### 2. Usa las Clases Utilitarias de Marca
Para elementos comunes, usa las clases predefinidas en lugar de duplicar estilos:
```vue
<!-- CORRECTO -->
<div class="brand-card">
<h2 class="brand-section-title">Título</h2>
<div class="brand-divider"></div>
</div>
<!-- INCORRECTO -->
<div class="rounded-lg bg-gradient-to-br from-[#1f180f] to-[#14100b] border border-[#3a2a16]">
<h2 class="text-lg font-semibold text-[#e0c080]">Título</h2>
<div class="h-px bg-[#3a2a16] my-4"></div>
</div>
```
## Variables de Tema Disponibles
| Variable CSS | Uso | Ejemplo |
|--------------|-----|---------|
| `--brand-bg` | Fondo principal de la aplicación | `bg-[var(--brand-bg)]` |
| `--brand-surface` | Fondos de elementos elevados (cards, modales) | `bg-[var(--brand-surface)]` |
| `--brand-border` | Bordes de elementos | `border-[var(--brand-border)]` |
| `--brand-primary` | Color principal (enlaces, botones) | `text-[var(--brand-primary)]` |
| `--brand-primary-strong` | Variante más intensa del primario | `bg-[var(--brand-primary-strong)]` |
| `--brand-accent` | Color de acento para highlights | `text-[var(--brand-accent)]` |
| `--brand-text` | Texto principal | `text-[var(--brand-text)]` |
| `--brand-text-muted` | Texto secundario/menos prominente | `text-[var(--brand-text-muted)]` |
## Clases Utilitarias de Marca
### `.brand-shell`
Contenedor principal para layouts con gradiente radial.
```vue
<div class="brand-shell">
<!-- Contenido de la página -->
</div>
```
### `.brand-card`
Tarjetas con estilos consistentes.
```vue
<div class="brand-card">
<h3>Título de la Card</h3>
<p>Contenido</p>
</div>
```
### `.brand-divider`
Divisor horizontal decorativo.
```vue
<div class="brand-divider"></div>
```
### `.brand-chip` y `.brand-pill`
Para pequeños tags o badges.
```vue
<span class="brand-chip">Estado</span>
<span class="brand-pill">Badge</span>
```
### `.brand-table`
Estilos para tablas.
```vue
<table class="brand-table">
<!-- ... -->
</table>
```
## Patrones de Uso Común
### Cards con Bordes y Sombras
```vue
<UCard class="brand-card border border-transparent">
<template #header>
<div class="flex items-center gap-2">
<UIcon name="i-lucide-star" class="size-5 text-[var(--brand-accent)]" />
<h3 class="text-[var(--brand-text)]">Título</h3>
</div>
</template>
<p class="text-[var(--brand-text-muted)]">
Descripción del contenido
</p>
</UCard>
```
### Botones con Hover Personalizado
```vue
<button class="px-4 py-2 rounded-lg bg-[var(--brand-surface)] border border-[var(--brand-border)] text-[var(--brand-text)] hover:bg-[var(--brand-primary)]/10 hover:border-[var(--brand-primary)] transition-colors">
Botón
</button>
```
### Inputs y Formularios
```vue
<UInput
v-model="value"
placeholder="Ingresa un valor"
:ui="{
base: 'bg-[var(--brand-surface)] border-[var(--brand-border)] text-[var(--brand-text)]',
placeholder: 'placeholder:text-[var(--brand-text-muted)]'
}"
/>
```
### Links con Hover
```vue
<NuxtLink
to="/perfil"
class="text-[var(--brand-accent)] hover:text-[var(--brand-primary)] hover:underline transition-colors"
>
Ver perfil
</NuxtLink>
```
### Personalización de Componentes Nuxt UI
Muchos componentes de Nuxt UI aceptan la prop `:ui` para personalización:
```vue
<UButton
:ui="{
base: 'bg-[var(--brand-surface)] hover:bg-[var(--brand-primary)]/10',
padding: { sm: 'px-2.5 py-2' }
}"
>
Botón Personalizado
</UButton>
```
## Composable `useTheme()`
Para manipular el tema programáticamente, usa el composable `useTheme()`:
```vue
<script setup lang="ts">
const { theme, applyTheme, saveTheme, resetTheme, exportTheme, importTheme } = useTheme()
// Modificar un color
theme.value.primary = '#ff5733'
// Aplicar cambios
applyTheme()
// Guardar en localStorage
saveTheme()
// Resetear a valores por defecto
resetTheme()
// Exportar tema como JSON
const jsonTheme = exportTheme()
// Importar tema desde JSON
const success = importTheme(jsonString, true) // true = guardar automáticamente
</script>
```
## Checklist Pre-Commit
Antes de hacer commit de tu código, verifica:
- [ ] **No hay colores hardcoded** (`#ffffff`, `#000000`, etc.)
- [ ] **No hay clases gray-scale genéricas** (`bg-gray-900`, `text-gray-500`, etc.)
- [ ] **Todos los fondos usan** `--brand-bg` o `--brand-surface`
- [ ] **Todos los bordes usan** `--brand-border`
- [ ] **Todo el texto usa** `--brand-text` o `--brand-text-muted`
- [ ] **Los elementos interactivos usan** `--brand-primary` o `--brand-accent`
- [ ] **Los hover states usan transparencias** (ej: `hover:bg-[var(--brand-primary)]/10`)
- [ ] **Se usan clases utilitarias** cuando sea posible (`.brand-card`, `.brand-shell`, etc.)
## Casos Especiales
### Colores Semánticos (Success, Error, Warning)
Para colores que NO son parte del tema (éxito, error, advertencia), puedes usar colores de Tailwind:
```vue
<!-- Estados semánticos - OK usar colores fijos -->
<div class="text-green-400">Éxito</div>
<div class="text-red-400">Error</div>
<div class="text-yellow-400">Advertencia</div>
<div class="text-blue-400">Info</div>
<!-- Pero el fondo y borde deben respetar el tema -->
<div class="bg-[var(--brand-surface)] border-green-600/30 text-green-400">
Operación exitosa
</div>
```
### Iconos
Los iconos deben usar colores del tema:
```vue
<!-- CORRECTO -->
<UIcon name="i-lucide-star" class="size-5 text-[var(--brand-primary)]" />
<UIcon name="i-lucide-info" class="size-4 text-[var(--brand-accent)]" />
<UIcon name="i-lucide-chevron-right" class="size-4 text-[var(--brand-text-muted)]" />
<!-- INCORRECTO -->
<UIcon name="i-lucide-star" class="size-5 text-amber-500" />
<UIcon name="i-lucide-info" class="size-4 text-blue-400" />
```
### Imágenes y Avatares con Bordes
```vue
<img
src="/logo.png"
class="rounded-full border-2 border-[var(--brand-accent)]/40 shadow-lg shadow-[var(--brand-primary-strong)]/25"
/>
<UAvatar
src="https://example.com/avatar.jpg"
:ui="{
wrapper: 'ring-2 ring-[var(--brand-primary)]/40'
}"
/>
```
### Hover y Focus States
Siempre usa transparencias para hover states para que funcionen con cualquier tema:
```vue
<!-- CORRECTO - Usa transparencia -->
<button class="hover:bg-[var(--brand-primary)]/10 focus:ring-2 focus:ring-[var(--brand-primary)]/50">
Botón
</button>
<!-- INCORRECTO - Color sólido -->
<button class="hover:bg-[#e0c080] focus:ring-2 focus:ring-[#c08040]">
Botón
</button>
```
## Ejemplos de Migración
### Antes (Incorrecto)
```vue
<template>
<div class="bg-gray-900 border border-gray-800">
<h2 class="text-white font-bold">Título</h2>
<p class="text-gray-400 mt-2">
Descripción
</p>
<button class="mt-4 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg">
Acción
</button>
</div>
</template>
```
### Después (Correcto)
```vue
<template>
<div class="bg-[var(--brand-surface)] border border-[var(--brand-border)]">
<h2 class="text-[var(--brand-text)] font-bold">Título</h2>
<p class="text-[var(--brand-text-muted)] mt-2">
Descripción
</p>
<UButton
class="mt-4"
:ui="{
base: 'bg-[var(--brand-primary)] hover:bg-[var(--brand-primary-strong)]'
}"
>
Acción
</UButton>
</div>
</template>
```
## Errores Comunes y Soluciones
### Error 1: Mezclar Variables con Hardcoded Colors
**❌ No hagas esto:**
```vue
<div class="bg-[#1f180f] text-[var(--brand-text)]">
Contenido
</div>
```
**✅ Haz esto:**
```vue
<div class="bg-[var(--brand-surface)] text-[var(--brand-text)]">
Contenido
</div>
```
### Error 2: No Considerar el Contraste
Asegúrate de que el texto tenga suficiente contraste sobre su fondo:
**❌ Mal contraste:**
```vue
<div class="bg-[var(--brand-surface)]">
<span class="text-[var(--brand-text-muted)]">Texto importante</span>
</div>
```
**✅ Buen contraste:**
```vue
<div class="bg-[var(--brand-surface)]">
<span class="text-[var(--brand-text)]">Texto importante</span>
</div>
```
### Error 3: Duplicar Estilos en Lugar de Usar Clases
**❌ Duplicación:**
```vue
<div class="rounded-lg bg-gradient-to-br from-[var(--brand-surface)] to-[var(--brand-bg)] border border-[var(--brand-border)] p-6 shadow-xl">
Card 1
</div>
<div class="rounded-lg bg-gradient-to-br from-[var(--brand-surface)] to-[var(--brand-bg)] border border-[var(--brand-border)] p-6 shadow-xl">
Card 2
</div>
```
**✅ Reutilización:**
```vue
<div class="brand-card">Card 1</div>
<div class="brand-card">Card 2</div>
```
## Testing del Tema
Para probar que tu componente respeta el tema:
1. Ve a `/settings`
2. Cambia el tema a "Azul Corporativo" o "Verde Natural"
3. Navega a tu componente
4. Verifica que todos los colores cambien correctamente
5. Verifica que no haya elementos con colores hardcoded que no cambiaron
## Recursos Adicionales
- **Documentación del usuario:** `THEME_CUSTOMIZATION.md`
- **Composable de temas:** `app/composables/useTheme.ts`
- **Variables CSS:** `app/assets/css/main.css`
- **Configuración de Nuxt UI:** `app.config.ts`
## Preguntas Frecuentes
### ¿Puedo usar colores de Tailwind como `bg-blue-500`?
Solo para estados semánticos (éxito, error, advertencia) que NO forman parte del tema. Para todo lo demás, usa las variables de tema.
### ¿Cómo personalizo un componente de Nuxt UI?
Usa la prop `:ui` con las variables de tema:
```vue
<UCard :ui="{ base: 'bg-[var(--brand-surface)]' }">
Contenido
</UCard>
```
### ¿Qué hago si necesito un color que no está en el tema?
Primero pregunta: ¿realmente necesito un color nuevo, o puedo usar uno existente? Si es absolutamente necesario, propón agregar una nueva variable al sistema de temas en lugar de hardcodear el color.
### ¿Cómo manejo dark mode?
No necesitas manejarlo manualmente. Las variables CSS ya están optimizadas para dark mode. Solo usa las variables y funcionará automáticamente.
---
**Última actualización:** 2025-10-30
**Mantenedor:** Claude Code para Núcleo Río Frío
**Versión:** 1.0.0

View File

@@ -1,368 +0,0 @@
# Sistema de Colores Personalizables - Analítica Núcleo
## Introducción
Analítica Núcleo cuenta con un sistema de temas completamente personalizable que permite ajustar los colores de la interfaz según tus preferencias. El sistema está basado en variables CSS que se pueden modificar desde la página de Configuración.
## Acceso al Configurador de Tema
1. Navega a **Configuración** desde el sidebar
2. O accede directamente a: `https://analitica.nucleoriofrio.com/settings`
3. Busca la sección **"Tema y Apariencia"**
## Variables de Color Disponibles
El sistema utiliza 8 variables CSS principales que controlan toda la apariencia de la aplicación:
### 1. **Fondo Principal** (`--brand-bg`)
- **Default:** `#14100b`
- **Uso:** Color de fondo principal de toda la aplicación
- **Afecta:** Fondo del body, áreas principales de contenido
- **Recomendación:** Debe ser el color más oscuro del tema para dark mode
### 2. **Fondo Secundario / Surface** (`--brand-surface`)
- **Default:** `#1f180f`
- **Uso:** Color de fondo para elementos elevados (cards, sidebar, modales)
- **Afecta:** Sidebar, tarjetas, paneles, scrollbar
- **Recomendación:** Ligeramente más claro que el fondo principal (5-10% más luminoso)
### 3. **Color de Bordes** (`--brand-border`)
- **Default:** `#3a2a16`
- **Uso:** Bordes de elementos, separadores, divisores
- **Afecta:** Bordes de inputs, cards, tablas, divisores
- **Recomendación:** Debe tener suficiente contraste con surface pero no ser demasiado agresivo
### 4. **Color Primario** (`--brand-primary`)
- **Default:** `#e0c080`
- **Uso:** Color principal de la marca, elementos interactivos en estado normal
- **Afecta:** Botones primarios, enlaces, iconos destacados, texto de navegación activa
- **Recomendación:** Color distintivo de tu marca, debe tener buen contraste sobre fondos oscuros
### 5. **Color Primario Fuerte** (`--brand-primary-strong`)
- **Default:** `#c08040`
- **Uso:** Variante más intensa del color primario
- **Afecta:** Scrollbar thumb, elementos en estado hover/focus
- **Recomendación:** Versión más saturada o más oscura del color primario (15-20% más oscuro)
### 6. **Color de Acento** (`--brand-accent`)
- **Default:** `#ffe0a0`
- **Uso:** Color para llamar la atención, notificaciones, badges
- **Afecta:** Badges, notificaciones, elementos con alta prioridad visual
- **Recomendación:** Color brillante y distintivo, versión más clara del primario
### 7. **Color de Texto** (`--brand-text`)
- **Default:** `#fef9f0`
- **Uso:** Color principal del texto
- **Afecta:** Todo el texto de la aplicación (títulos, párrafos, labels)
- **Recomendación:** Debe tener excelente contraste con el fondo (ratio WCAG AA mínimo 4.5:1)
### 8. **Color de Texto Secundario** (`--brand-text-muted`)
- **Default:** `#d8c7a6`
- **Uso:** Texto de menor jerarquía, descripciones, placeholders
- **Afecta:** Texto secundario, descripciones, hints, placeholders
- **Recomendación:** Versión menos prominente del texto principal (20-30% menos luminosidad)
## Cómo Personalizar el Tema
### Método 1: Interfaz Gráfica (Recomendado)
1. **Accede a Configuración** → Tema y Apariencia
2. **Modifica los colores:**
- Usa el **color picker** (selector de color) para elegir visualmente
- O ingresa el **código hexadecimal** manualmente (ej: `#ff5733`)
3. **Activa "Vista previa en vivo"** (opcional) para ver cambios en tiempo real
4. **Revisa la vista previa** de los colores en la sección inferior
5. **Haz clic en "Guardar cambios"** para aplicar y persistir la configuración
### Método 2: Edición Manual (Avanzado)
Si eres desarrollador, puedes editar directamente el archivo CSS:
```css
/* Archivo: nuxt4-app/app/assets/css/main.css */
:root {
--brand-bg: #tu-color-aqui;
--brand-surface: #tu-color-aqui;
--brand-border: #tu-color-aqui;
--brand-primary: #tu-color-aqui;
--brand-primary-strong: #tu-color-aqui;
--brand-accent: #tu-color-aqui;
--brand-text: #tu-color-aqui;
--brand-text-muted: #tu-color-aqui;
}
```
**Nota:** Los cambios manuales requieren rebuild y despliegue de la aplicación.
## Guía de Buenas Prácticas
### 1. Mantén la Jerarquía de Luminosidad
Para un tema oscuro coherente, sigue este orden de luminosidad:
```
--brand-bg (más oscuro)
--brand-surface
--brand-border
--brand-primary-strong
--brand-primary
--brand-text-muted
--brand-accent
--brand-text (más claro)
```
### 2. Asegura el Contraste de Accesibilidad
**Mínimo WCAG AA:**
- Texto normal: ratio de contraste ≥ 4.5:1
- Texto grande: ratio de contraste ≥ 3:1
**Recomendado WCAG AAA:**
- Texto normal: ratio de contraste ≥ 7:1
- Texto grande: ratio de contraste ≥ 4.5:1
**Herramientas útiles:**
- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
- [Coolors Contrast Checker](https://coolors.co/contrast-checker)
### 3. Mantén la Coherencia Cromática
**Opción A: Monocromático**
- Usa diferentes tonos del mismo color base
- Ejemplo: Tema café actual (variaciones de marrón/beige)
**Opción B: Análogo**
- Usa colores adyacentes en la rueda cromática
- Ejemplo: Azul + Turquesa + Verde
**Opción C: Complementario**
- Color primario + su complementario como acento
- Ejemplo: Azul oscuro + Naranja para acentos
### 4. Prueba en Diferentes Condiciones
Después de personalizar, verifica:
- ✅ Legibilidad en diferentes páginas
- ✅ Contraste de botones y enlaces
- ✅ Visibilidad de bordes y separadores
- ✅ Claridad de la navegación activa
- ✅ Apariencia de modales y overlays
## Casos de Uso Comunes
### Tema "Noche Profunda" (Azul Oscuro)
```
Fondo Principal: #0a0e1a
Surface: #151a28
Bordes: #2d3748
Primario: #60a5fa
Primario Fuerte: #3b82f6
Acento: #93c5fd
Texto: #f0f4f8
Texto Muted: #cbd5e1
```
### Tema "Bosque" (Verde Oscuro)
```
Fondo Principal: #0f1a14
Surface: #1a2820
Bordes: #2d4033
Primario: #86efac
Primario Fuerte: #4ade80
Acento: #bbf7d0
Texto: #f0fdf4
Texto Muted: #d1fae5
```
### Tema "Carbón" (Gris Neutro)
```
Fondo Principal: #0f0f0f
Surface: #1a1a1a
Bordes: #333333
Primario: #a3a3a3
Primario Fuerte: #737373
Acento: #d4d4d4
Texto: #fafafa
Texto Muted: #d4d4d4
```
## Restaurar Tema por Defecto
Si no te gusta la personalización o algo sale mal:
1. Ve a **Configuración** → Tema y Apariencia
2. Haz clic en **"Restaurar por defecto"**
3. Los colores volverán al tema café original
Esto también limpia la configuración guardada en localStorage.
## Persistencia y Almacenamiento
### ¿Dónde se guarda mi tema personalizado?
Los cambios se guardan en el **localStorage del navegador**, lo que significa:
**Se mantiene entre sesiones** - No necesitas reconfigurar cada vez
**Es por navegador** - Cada navegador tiene su propia configuración
**Es local** - No se sincroniza entre dispositivos
### ¿Qué pasa si limpio el caché?
Si limpias los datos del navegador (cookies, localStorage), el tema volverá a los valores por defecto.
### ¿Cómo uso el mismo tema en múltiples navegadores?
**Opción 1 (Manual):**
1. Anota los códigos hexadecimales de tu tema personalizado
2. Configúralos manualmente en cada navegador
**Opción 2 (Futuro - Sincronización con Cuenta):**
En una futura versión, los temas se podrán guardar en el servidor vinculados a tu cuenta de usuario.
## Integración con Componentes
### Usar las variables en tu código
Si eres desarrollador y estás creando nuevos componentes, usa las variables CSS:
```vue
<template>
<div class="mi-componente">
<h1>Título con color de marca</h1>
<p>Texto secundario</p>
</div>
</template>
<style scoped>
.mi-componente {
background: var(--brand-surface);
border: 1px solid var(--brand-border);
color: var(--brand-text);
}
h1 {
color: var(--brand-primary);
}
p {
color: var(--brand-text-muted);
}
</style>
```
### Clases de Tailwind con variables
```vue
<div class="bg-[var(--brand-surface)] border-[var(--brand-border)] text-[var(--brand-text)]">
Contenido
</div>
```
## Solución de Problemas
### Los cambios no se aplican
1. **Verifica que hiciste clic en "Guardar cambios"**
2. Recarga la página (F5 o Ctrl+R)
3. Si persiste, abre la consola del navegador (F12) y busca errores
### Los colores se ven mal después de cambiarlos
1. Haz clic en **"Restaurar por defecto"**
2. Revisa las [guías de buenas prácticas](#guía-de-buenas-prácticas)
3. Asegúrate de que el contraste sea suficiente
### El tema no se guarda entre sesiones
1. Verifica que tu navegador permite localStorage
2. Revisa que no estés en modo incógnito/privado
3. Verifica que no tengas extensiones que bloqueen localStorage
### Vista previa en vivo no funciona
1. Desactiva y reactiva el toggle
2. Si persiste, guarda los cambios manualmente
3. La vista previa es opcional, no afecta la funcionalidad principal
## Arquitectura Técnica
### Variables CSS y su Mapeo
El sistema usa dos capas de variables:
**1. Variables de Marca (`--brand-*`):** Definidas por el usuario
**2. Variables de Nuxt UI (`--ui-color-neutral-*`):** Mapeadas automáticamente
```css
/* Definición en main.css */
:root {
--brand-primary: #e0c080;
/* Mapeo automático a Nuxt UI */
--ui-color-neutral-500: var(--color-coffee-500);
}
```
### Flujo de Aplicación
```
1. Usuario modifica color en UI
2. JavaScript actualiza theme.value
3. (Opcional) Vista previa en vivo → applyTheme()
4. Usuario hace clic en "Guardar"
5. localStorage.setItem('custom-theme', JSON.stringify(theme))
6. applyTheme() → document.documentElement.style.setProperty()
7. CSS variables actualizadas en :root
8. Toda la UI se re-renderiza con nuevos colores
```
### Compatibilidad
- ✅ Chrome 49+
- ✅ Firefox 31+
- ✅ Safari 9.1+
- ✅ Edge 15+
- ✅ Opera 36+
## Roadmap Futuro
Funcionalidades planeadas:
- 🔄 Sincronización de tema con cuenta de usuario
- 🎨 Galería de temas predefinidos
- 📤 Exportar/Importar configuración de tema (JSON)
- 🌗 Soporte para modo claro (light mode)
- 🎯 Presets por categoría (Profesional, Creativo, Minimalista)
- 🔍 Vista previa de tema en todas las páginas
- 📊 Análisis automático de contraste y accesibilidad
## Soporte
Si tienes problemas o sugerencias:
1. **Documentación:** Revisa este documento primero
2. **Issues:** Reporta problemas en el repositorio de Gitea
3. **Contacto:** Contacta al administrador del sistema
---
**Última actualización:** 2025-10-30
**Versión del sistema:** 1.0.0
**Autor:** Claude Code para Núcleo Río Frío

View File

@@ -0,0 +1,655 @@
# Sistema de Temas - Analítica Núcleo
> **Documentación definitiva del sistema de temas personalizable**
> Versión: 2.0 | Última actualización: 2025-10-30
## Índice
1. [Introducción](#introducción)
2. [Arquitectura del Sistema](#arquitectura-del-sistema)
3. [Variables CSS Disponibles](#variables-css-disponibles)
4. [Reglas de Uso Obligatorias](#reglas-de-uso-obligatorias)
5. [Clases Utilitarias](#clases-utilitarias)
6. [Composable useTheme()](#composable-usetheme)
7. [Ejemplos de Uso](#ejemplos-de-uso)
8. [Integración con Nuxt UI](#integración-con-nuxt-ui)
9. [Casos Especiales](#casos-especiales)
10. [Troubleshooting](#troubleshooting)
---
## Introducción
Analítica Núcleo cuenta con un sistema de temas completamente dinámico que permite personalizar todos los colores de la interfaz en tiempo real. Los cambios se aplican instantáneamente a todos los componentes de la aplicación.
**Características principales:**
- ✅ 8 variables de color personalizables
- ✅ 4 temas predefinidos (Café, Azul, Verde, Carbón)
- ✅ Persistencia en localStorage
- ✅ Vista previa en tiempo real
- ✅ Exportar/importar temas en JSON
- ✅ Integración completa con Nuxt UI
---
## Arquitectura del Sistema
### Flujo de Datos
```
Usuario modifica tema en /settings
useTheme() composable
Actualiza variables CSS (--brand-*)
Variables --ui-color-neutral-* mapeadas automáticamente
Todos los componentes se actualizan instantáneamente
```
### Archivos Clave
| Archivo | Propósito |
|---------|-----------|
| `app/assets/css/main.css` | Definición de variables CSS y clases utilitarias |
| `app/composables/useTheme.ts` | Lógica del sistema de temas |
| `app/pages/settings.vue` | Interfaz de configuración |
---
## Variables CSS Disponibles
### Variables de Tema (`--brand-*`)
Estas son las **ÚNICAS** variables que debes usar en tu código:
| Variable | Uso | Ejemplo de valor |
|----------|-----|------------------|
| `--brand-bg` | Fondo principal de la app | `#14100b` |
| `--brand-surface` | Fondos de cards, modales, elementos elevados | `#1f180f` |
| `--brand-border` | Bordes de todos los elementos | `#3a2a16` |
| `--brand-primary` | Color principal para enlaces, títulos destacados | `#e0c080` |
| `--brand-primary-strong` | Variante más intensa del primario | `#c08040` |
| `--brand-accent` | Highlights, elementos de énfasis | `#ffe0a0` |
| `--brand-text` | Texto principal (alta legibilidad) | `#fef9f0` |
| `--brand-text-muted` | Texto secundario, descripciones | `#d8c7a6` |
### Variables de Nuxt UI (`--ui-color-neutral-*`)
⚠️ **NO uses estas variables directamente**. Están mapeadas automáticamente a `--brand-*` en `main.css`.
**Mapeo actual (NO modificar):**
```css
--ui-color-neutral-50: var(--brand-text); /* Texto más claro */
--ui-color-neutral-100: var(--brand-text-muted); /* Texto secundario */
--ui-color-neutral-200: var(--brand-primary); /* Primario claro */
--ui-color-neutral-300: var(--brand-primary); /* Primario */
--ui-color-neutral-400: var(--brand-primary-strong); /* Primario fuerte */
--ui-color-neutral-500: var(--brand-border); /* Bordes */
--ui-color-neutral-600: var(--brand-border); /* Bordes */
--ui-color-neutral-700: var(--brand-surface); /* Surface */
--ui-color-neutral-800: var(--brand-surface); /* Surface */
--ui-color-neutral-900: var(--brand-bg); /* Fondo más oscuro */
--ui-color-neutral-950: var(--brand-bg); /* Fondo */
```
> **IMPORTANTE:** Nuxt UI usa la escala neutral de forma invertida en dark mode:
> - `neutral-50/100` → Colores claros (texto)
> - `neutral-900/950` → Colores oscuros (fondos)
---
## Reglas de Uso Obligatorias
### ✅ SIEMPRE Hacer
1. **Usar variables CSS en lugar de colores hardcoded:**
```vue
<!-- ✅ CORRECTO -->
<div class="bg-[var(--brand-surface)] text-[var(--brand-text)]">
Contenido
</div>
```
2. **Usar clases utilitarias cuando existan:**
```vue
<!-- ✅ CORRECTO -->
<div class="brand-card">
<h2 class="brand-section-title">Título</h2>
</div>
```
3. **Usar transparencias para hover states:**
```vue
<!-- ✅ CORRECTO -->
<button class="hover:bg-[var(--brand-primary)]/10">
Botón
</button>
```
### ❌ NUNCA Hacer
1. **NO usar colores hardcoded:**
```vue
<!-- ❌ INCORRECTO -->
<div class="bg-[#1f180f] text-[#fef9f0]">
Contenido
</div>
```
2. **NO usar clases gray-scale genéricas:**
```vue
<!-- ❌ INCORRECTO -->
<div class="bg-gray-900 text-gray-400 border-gray-800">
Contenido
</div>
```
3. **NO mezclar variables con hardcoded:**
```vue
<!-- ❌ INCORRECTO -->
<div class="bg-[#1f180f] text-[var(--brand-text)]">
Contenido
</div>
```
---
## Clases Utilitarias
### `.brand-shell`
Contenedor principal con gradiente radial.
```vue
<div class="brand-shell">
<!-- Contenido de la página -->
</div>
```
### `.brand-card`
Tarjetas con estilos consistentes (gradiente, borde, sombra).
```vue
<div class="brand-card">
<h3>Título</h3>
<p>Contenido</p>
</div>
```
### `.brand-divider`
Divisor horizontal decorativo.
```vue
<div class="brand-divider"></div>
```
### `.brand-section-title`
Títulos de sección con color primario.
```vue
<h2 class="brand-section-title">Mi Sección</h2>
```
### `.brand-chip` / `.brand-pill`
Tags o badges pequeños.
```vue
<span class="brand-chip">Estado</span>
<span class="brand-pill">Badge</span>
```
### `.brand-badge`
Badge con fondo primario sólido.
```vue
<span class="brand-badge">3</span>
```
### `.brand-table`
Estilos para tablas.
```vue
<table class="brand-table">
<thead>...</thead>
<tbody>...</tbody>
</table>
```
---
## Composable useTheme()
### Importar
```typescript
const {
theme,
applyTheme,
saveTheme,
resetTheme,
exportTheme,
importTheme
} = useTheme()
```
### API
#### `theme` (Ref<ThemeColors>)
Estado reactivo del tema actual.
```typescript
interface ThemeColors {
bg: string
surface: string
border: string
primary: string
primaryStrong: string
accent: string
text: string
textMuted: string
}
```
#### `applyTheme(newTheme?: ThemeColors)`
Aplica el tema a las variables CSS del DOM.
```typescript
applyTheme() // Aplica theme.value actual
applyTheme(customTheme) // Aplica un tema personalizado
```
#### `saveTheme()`
Guarda el tema actual en localStorage.
```typescript
const success = saveTheme()
if (success) {
console.log('Tema guardado')
}
```
#### `resetTheme()`
Resetea al tema por defecto (Café).
```typescript
resetTheme()
```
#### `exportTheme()`
Exporta el tema actual como JSON string.
```typescript
const jsonTheme = exportTheme()
await navigator.clipboard.writeText(jsonTheme)
```
#### `importTheme(jsonString: string, autoSave: boolean = false)`
Importa un tema desde JSON string.
```typescript
const success = importTheme(jsonString, true) // true = guardar automáticamente
```
---
## Ejemplos de Uso
### Ejemplo 1: Card Básica
```vue
<template>
<UCard
:ui="{
base: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]',
header: { base: 'border-b border-[var(--brand-border)]' }
}"
>
<template #header>
<h3 class="text-[var(--brand-text)]">Mi Card</h3>
</template>
<p class="text-[var(--brand-text-muted)]">
Descripción del contenido
</p>
</UCard>
</template>
```
### Ejemplo 2: Botón con Hover
```vue
<template>
<button
class="px-4 py-2 rounded-lg bg-[var(--brand-surface)] border border-[var(--brand-border)] text-[var(--brand-text)] hover:bg-[var(--brand-primary)]/10 hover:border-[var(--brand-primary)] transition-colors"
>
Mi Botón
</button>
</template>
```
### Ejemplo 3: Input Personalizado
```vue
<template>
<UInput
v-model="value"
placeholder="Ingresa un valor"
:ui="{
base: 'bg-[var(--brand-surface)] border-[var(--brand-border)] text-[var(--brand-text)]',
placeholder: 'placeholder:text-[var(--brand-text-muted)]'
}"
/>
</template>
```
### Ejemplo 4: Link con Hover
```vue
<template>
<NuxtLink
to="/perfil"
class="text-[var(--brand-accent)] hover:text-[var(--brand-primary)] hover:underline transition-colors"
>
Ver perfil →
</NuxtLink>
</template>
```
### Ejemplo 5: Iconos
```vue
<template>
<UIcon
name="i-lucide-star"
class="size-5 text-[var(--brand-primary)]"
/>
<UIcon
name="i-lucide-info"
class="size-4 text-[var(--brand-accent)]"
/>
</template>
```
### Ejemplo 6: Manipular Tema Programáticamente
```vue
<script setup lang="ts">
const { theme, applyTheme, saveTheme } = useTheme()
// Modificar un color
const cambiarColorPrimario = () => {
theme.value.primary = '#60a5fa'
applyTheme()
saveTheme()
}
// Aplicar tema personalizado completo
const aplicarTemaAzul = () => {
theme.value = {
bg: '#0a0e1a',
surface: '#151a28',
border: '#2d3748',
primary: '#60a5fa',
primaryStrong: '#3b82f6',
accent: '#93c5fd',
text: '#f0f4f8',
textMuted: '#cbd5e1'
}
applyTheme()
saveTheme()
}
</script>
<template>
<div>
<button @click="cambiarColorPrimario">Cambiar Primary</button>
<button @click="aplicarTemaAzul">Aplicar Tema Azul</button>
</div>
</template>
```
---
## Integración con Nuxt UI
### Componentes que Respetan el Tema Automáticamente
Los siguientes componentes de Nuxt UI **NO necesitan customización** porque usan `--ui-color-neutral-*` internamente:
- `UButton` (con `color="neutral"`)
- `UBadge` (con `color="neutral"`)
- `UInput` (parcialmente)
- `UTextarea` (parcialmente)
- `USelect` (parcialmente)
- Componentes de navegación (sidebar, navbar)
### Componentes que Necesitan `:ui` Prop
Para estos componentes, debes especificar colores explícitamente:
#### UCard
```vue
<UCard
:ui="{
base: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]',
body: { padding: 'p-6' },
header: { base: 'border-b border-[var(--brand-border)]' }
}"
>
<!-- Contenido -->
</UCard>
```
#### UModal
```vue
<UModal
v-model="isOpen"
:ui="{
background: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]',
header: { base: 'border-b border-[var(--brand-border)]' }
}"
>
<!-- Contenido -->
</UModal>
```
#### UDropdown
```vue
<UDropdown
:items="items"
:ui="{
background: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]',
item: {
base: 'hover:bg-[var(--brand-primary)]/10'
}
}"
>
<!-- Contenido -->
</UDropdown>
```
---
## Casos Especiales
### Colores Semánticos (Success, Error, Warning)
Para estados semánticos, **SÍ puedes usar colores fijos de Tailwind** porque no forman parte del tema personalizable:
```vue
<template>
<!-- ✅ CORRECTO - Estados semánticos -->
<div class="text-green-400">Operación exitosa</div>
<div class="text-red-400">Error al procesar</div>
<div class="text-yellow-400">Advertencia</div>
<div class="text-blue-400">Información</div>
<!-- Pero el fondo y borde deben respetar el tema -->
<div class="bg-[var(--brand-surface)] border-green-600/30 text-green-400">
Éxito con tema
</div>
</template>
```
### Imágenes y Avatares
```vue
<template>
<!-- Avatar con ring temático -->
<UAvatar
src="/avatar.jpg"
:ui="{
wrapper: 'ring-2 ring-[var(--brand-primary)]/40'
}"
/>
<!-- Imagen con borde -->
<img
src="/logo.png"
class="rounded-full border-2 border-[var(--brand-accent)]/40 shadow-lg shadow-[var(--brand-primary-strong)]/25"
/>
</template>
```
### Gradientes
```vue
<template>
<!-- Gradiente usando variables -->
<div
class="bg-gradient-to-br"
:style="{
'--tw-gradient-from': 'var(--brand-primary)',
'--tw-gradient-to': 'var(--brand-accent)'
}"
>
Contenido con gradiente
</div>
</template>
```
---
## Troubleshooting
### Problema 1: Texto Invisible
**Síntoma:** El texto no se ve en algunos componentes.
**Causa:** Estás usando un color de fondo donde debería ir un color de texto.
**Solución:**
```vue
<!-- ❌ INCORRECTO -->
<div class="bg-[var(--brand-text)] text-[var(--brand-bg)]">
<!-- ✅ CORRECTO -->
<div class="bg-[var(--brand-surface)] text-[var(--brand-text)]">
```
### Problema 2: Componentes No Cambian con el Tema
**Síntoma:** Algunos componentes mantienen colores fijos cuando cambias de tema.
**Causa:** Estás usando colores hardcoded o clases gray-scale.
**Solución:** Reemplaza todos los colores fijos con variables `--brand-*`.
### Problema 3: UCard con Fondo Incorrecto
**Síntoma:** UCard tiene un fondo que no corresponde al tema.
**Causa:** Falta especificar la prop `:ui`.
**Solución:**
```vue
<UCard
:ui="{
base: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]'
}"
>
<!-- Contenido -->
</UCard>
```
### Problema 4: Hover No Se Ve
**Síntoma:** Los hover effects no son visibles.
**Causa:** Estás usando colores sólidos en lugar de transparencias.
**Solución:**
```vue
<!-- ❌ INCORRECTO -->
<button class="hover:bg-[var(--brand-primary)]">
<!-- ✅ CORRECTO -->
<button class="hover:bg-[var(--brand-primary)]/10">
```
---
## Checklist Pre-Commit
Antes de hacer commit, verifica:
- [ ] No hay colores hexadecimales hardcoded (`#ffffff`, `#000000`, etc.)
- [ ] No hay clases gray-scale genéricas (`bg-gray-900`, `text-gray-500`, etc.)
- [ ] Todos los fondos usan `--brand-bg` o `--brand-surface`
- [ ] Todos los bordes usan `--brand-border`
- [ ] Todo el texto usa `--brand-text` o `--brand-text-muted`
- [ ] Los elementos interactivos usan `--brand-primary` o `--brand-accent`
- [ ] Los hover states usan transparencias (`/10`, `/20`, etc.)
- [ ] Se usan clases utilitarias cuando sea posible
---
## Resumen de Comandos Rápidos
```vue
<!-- Fondos -->
bg-[var(--brand-bg)] <!-- Fondo principal -->
bg-[var(--brand-surface)] <!-- Cards, modales -->
<!-- Bordes -->
border-[var(--brand-border)]
<!-- Texto -->
text-[var(--brand-text)] <!-- Texto principal -->
text-[var(--brand-text-muted)] <!-- Texto secundario -->
<!-- Colores de marca -->
text-[var(--brand-primary)] <!-- Links, títulos -->
text-[var(--brand-accent)] <!-- Highlights -->
bg-[var(--brand-primary-strong)] <!-- Backgrounds intensos -->
<!-- Hover (siempre con transparencia) -->
hover:bg-[var(--brand-primary)]/10
hover:border-[var(--brand-primary)]
hover:text-[var(--brand-accent)]
```
---
## Notas Finales
- **Nunca modifiques** el mapeo de `--ui-color-neutral-*` en `main.css` sin entender el sistema completamente
- **Siempre usa variables CSS** para mantener la consistencia del tema
- **Prueba todos los temas** después de hacer cambios visuales (Café, Azul, Verde, Carbón)
- **Usa el composable** `useTheme()` para manipulación programática
- **Consulta este documento** ante cualquier duda sobre colores
---
**Mantenido por:** Claude Code para Núcleo Río Frío
**Versión del sistema:** 2.0
**Última revisión:** 2025-10-30