# 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 Base (`--brand-*`)

Estas variables controlan la apariencia general de la aplicación:

| 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 Tipos de Café (`--coffee-*`)

Estas variables se usan para identificar visualmente los tipos de café en gráficas y tablas:

| Variable | Uso | Ejemplo de valor |
|----------|-----|------------------|
| `--coffee-uva` | Color de identificación para Café Uva | `#a855f7` (Purple) |
| `--coffee-oreado` | Color de identificación para Café Oreado | `#f97316` (Orange) |
| `--coffee-mojado` | Color de identificación para Café Mojado | `#06b6d4` (Cyan) |
| `--coffee-verde` | Color de identificación para Café Verde | `#22c55e` (Green) |

### Variables de Estados (`--status-*`)

Estas variables se usan para indicar estados de pago en tablas y badges:

| Variable | Uso | Ejemplo de valor |
|----------|-----|------------------|
| `--status-pendiente` | Estado de pago pendiente | `#f59e0b` (Amber) |
| `--status-pagado` | Estado pagado completamente | `#10b981` (Emerald) |
| `--status-anulado` | Estado anulado o cancelado | `#6b7280` (Gray) |

### 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',
    // Colores de café (mantener consistentes)
    coffeeUva: '#a855f7',
    coffeeOreado: '#f97316',
    coffeeMojado: '#06b6d4',
    coffeeVerde: '#22c55e',
    // Colores de estados (mantener consistentes)
    statusPendiente: '#f59e0b',
    statusPagado: '#10b981',
    statusAnulado: '#6b7280'
  }
  applyTheme()
  saveTheme()
}
</script>

<template>
  <div>
    <button @click="cambiarColorPrimario">Cambiar Primary</button>
    <button @click="aplicarTemaAzul">Aplicar Tema Azul</button>
  </div>
</template>
```

### Ejemplo 7: Usar Colores de Tipos de Café

```vue
<template>
  <!-- Badge para tipo de café -->
  <UBadge
    :style="{ backgroundColor: 'var(--coffee-uva)', color: 'white' }"
    size="sm"
  >
    Café Uva
  </UBadge>

  <!-- Indicador visual de tipo -->
  <div class="flex items-center gap-2">
    <div class="w-3 h-3 rounded-full" style="background: var(--coffee-oreado)"></div>
    <span>Café Oreado</span>
  </div>

  <!-- En gráficas (ejemplo con Chart.js) -->
  <script setup>
  const chartData = {
    datasets: [{
      label: 'Uva',
      backgroundColor: 'var(--coffee-uva)',
      data: [10, 20, 30]
    }, {
      label: 'Oreado',
      backgroundColor: 'var(--coffee-oreado)',
      data: [15, 25, 35]
    }]
  }
  </script>
</template>
```

### Ejemplo 8: Usar Colores de Estados

```vue
<template>
  <!-- Badge de estado pendiente -->
  <UBadge
    class="text-[var(--status-pendiente)] bg-[var(--status-pendiente)]/10 border border-[var(--status-pendiente)]/30"
    size="sm"
  >
    Pendiente
  </UBadge>

  <!-- Badge de estado pagado -->
  <UBadge
    class="text-[var(--status-pagado)] bg-[var(--status-pagado)]/10 border border-[var(--status-pagado)]/30"
    size="sm"
  >
    Pagado
  </UBadge>

  <!-- Badge de estado anulado -->
  <UBadge
    class="text-[var(--status-anulado)] bg-[var(--status-anulado)]/10 border border-[var(--status-anulado)]/30"
    size="sm"
  >
    Anulado
  </UBadge>

  <!-- Indicador en tabla -->
  <td>
    <div class="flex items-center gap-2">
      <div class="w-2 h-2 rounded-full" :style="{ backgroundColor: 'var(--status-pagado)' }"></div>
      <span>Pagado</span>
    </div>
  </td>
</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
<!-- VARIABLES BASE -->

<!-- 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)]

<!-- VARIABLES DE TIPOS DE CAFÉ -->

<!-- Colores de café -->
bg-[var(--coffee-uva)]      <!-- Purple - Café Uva -->
bg-[var(--coffee-oreado)]   <!-- Orange - Café Oreado -->
bg-[var(--coffee-mojado)]   <!-- Cyan - Café Mojado -->
bg-[var(--coffee-verde)]    <!-- Green - Café Verde -->

<!-- Ejemplo en badges -->
<UBadge :style="{ backgroundColor: 'var(--coffee-uva)', color: 'white' }">
  Café Uva
</UBadge>

<!-- VARIABLES DE ESTADOS -->

<!-- Colores de estados -->
text-[var(--status-pendiente)]  <!-- Amber - Pendiente -->
text-[var(--status-pagado)]     <!-- Green - Pagado -->
text-[var(--status-anulado)]    <!-- Gray - Anulado -->

<!-- Ejemplo en badges con fondo suave -->
<UBadge class="text-[var(--status-pagado)] bg-[var(--status-pagado)]/10">
  Pagado
</UBadge>
```

---

## 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
