Feat: Extender sistema de temas con colores de café y estados
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 49s

Cambios:
- Agregar documentación completa del sistema de temas en /settings
- Extender ThemeColors con 7 nuevas variables:
  * coffeeUva, coffeeOreado, coffeeMojado, coffeeVerde
  * statusPendiente, statusPagado, statusAnulado
- Actualizar useTheme.ts para aplicar nuevas variables CSS
- Actualizar main.css con definiciones de nuevas variables
- Actualizar temas predefinidos (azul, verde, carbón)
- Mantener colores de café y estados consistentes en todos los temas

Las nuevas variables permiten personalizar:
- Colores de identificación de tipos de café en gráficas
- Colores de estados de pago en tablas y badges
This commit is contained in:
2025-10-30 17:31:50 -06:00
parent b9c780d667
commit cac84adc7d
3 changed files with 294 additions and 5 deletions

View File

@@ -18,6 +18,7 @@
}
:root {
/* Colores base del tema */
--brand-bg: #14100b;
--brand-surface: #1f180f;
--brand-border: #3a2a16;
@@ -27,6 +28,17 @@
--brand-text: #fef9f0;
--brand-text-muted: #d8c7a6;
/* Colores para tipos de café */
--coffee-uva: #a855f7; /* Purple - Café Uva */
--coffee-oreado: #f97316; /* Orange - Café Oreado */
--coffee-mojado: #06b6d4; /* Cyan - Café Mojado */
--coffee-verde: #22c55e; /* Green - Café Verde */
/* Colores para estados */
--status-pendiente: #f59e0b; /* Amber - Pendiente de pago */
--status-pagado: #10b981; /* Emerald - Pagado */
--status-anulado: #6b7280; /* Gray - Anulado */
/* Mapear variables UI neutral a nuestras variables dinámicas --brand-*
Esto permite que los componentes de Nuxt UI respondan a cambios de tema
IMPORTANTE: Nuxt UI usa neutral-50 para fondos oscuros y neutral-950 para texto claro en dark mode */

View File

@@ -19,6 +19,7 @@
*/
export interface ThemeColors {
// Colores base
bg: string
surface: string
border: string
@@ -27,12 +28,24 @@ export interface ThemeColors {
accent: string
text: string
textMuted: string
// Colores para tipos de café
coffeeUva: string // Purple - Café Uva
coffeeOreado: string // Orange - Café Oreado
coffeeMojado: string // Cyan - Café Mojado
coffeeVerde: string // Green - Café Verde
// Colores para estados
statusPendiente: string // Amarillo/naranja - Pendiente de pago
statusPagado: string // Verde - Pagado
statusAnulado: string // Rojo/gris - Anulado
}
/**
* Tema por defecto - Café
*/
export const defaultTheme: ThemeColors = {
// Colores base
bg: '#14100b',
surface: '#1f180f',
border: '#3a2a16',
@@ -40,7 +53,18 @@ export const defaultTheme: ThemeColors = {
primaryStrong: '#c08040',
accent: '#ffe0a0',
text: '#fef9f0',
textMuted: '#d8c7a6'
textMuted: '#d8c7a6',
// Colores para tipos de café
coffeeUva: '#a855f7', // Purple
coffeeOreado: '#f97316', // Orange
coffeeMojado: '#06b6d4', // Cyan
coffeeVerde: '#22c55e', // Green
// Colores para estados
statusPendiente: '#f59e0b', // Amber
statusPagado: '#10b981', // Emerald
statusAnulado: '#6b7280' // Gray
}
/**
@@ -64,6 +88,7 @@ export const useTheme = () => {
const colors = themeColors || theme.value
const root = document.documentElement
// Colores base
root.style.setProperty('--brand-bg', colors.bg)
root.style.setProperty('--brand-surface', colors.surface)
root.style.setProperty('--brand-border', colors.border)
@@ -72,6 +97,17 @@ export const useTheme = () => {
root.style.setProperty('--brand-accent', colors.accent)
root.style.setProperty('--brand-text', colors.text)
root.style.setProperty('--brand-text-muted', colors.textMuted)
// Colores para tipos de café
root.style.setProperty('--coffee-uva', colors.coffeeUva)
root.style.setProperty('--coffee-oreado', colors.coffeeOreado)
root.style.setProperty('--coffee-mojado', colors.coffeeMojado)
root.style.setProperty('--coffee-verde', colors.coffeeVerde)
// Colores para estados
root.style.setProperty('--status-pendiente', colors.statusPendiente)
root.style.setProperty('--status-pagado', colors.statusPagado)
root.style.setProperty('--status-anulado', colors.statusAnulado)
}
}
@@ -167,7 +203,9 @@ export const useTheme = () => {
// Validar que tenga todas las propiedades requeridas
const requiredKeys: (keyof ThemeColors)[] = [
'bg', 'surface', 'border', 'primary',
'primaryStrong', 'accent', 'text', 'textMuted'
'primaryStrong', 'accent', 'text', 'textMuted',
'coffeeUva', 'coffeeOreado', 'coffeeMojado', 'coffeeVerde',
'statusPendiente', 'statusPagado', 'statusAnulado'
]
for (const key of requiredKeys) {

View File

@@ -29,7 +29,16 @@ const presetThemes: Record<string, ThemeColors> = {
primaryStrong: '#3b82f6',
accent: '#93c5fd',
text: '#f0f4f8',
textMuted: '#cbd5e1'
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'
},
verde: {
bg: '#0f1a14',
@@ -39,7 +48,16 @@ const presetThemes: Record<string, ThemeColors> = {
primaryStrong: '#4ade80',
accent: '#bbf7d0',
text: '#f0fdf4',
textMuted: '#d1fae5'
textMuted: '#d1fae5',
// Colores de café (mantener consistentes)
coffeeUva: '#a855f7',
coffeeOreado: '#f97316',
coffeeMojado: '#06b6d4',
coffeeVerde: '#22c55e',
// Colores de estados (mantener consistentes)
statusPendiente: '#f59e0b',
statusPagado: '#10b981',
statusAnulado: '#6b7280'
},
carbon: {
bg: '#0f0f0f',
@@ -49,7 +67,16 @@ const presetThemes: Record<string, ThemeColors> = {
primaryStrong: '#737373',
accent: '#d4d4d4',
text: '#fafafa',
textMuted: '#d4d4d4'
textMuted: '#d4d4d4',
// Colores de café (mantener consistentes)
coffeeUva: '#a855f7',
coffeeOreado: '#f97316',
coffeeMojado: '#06b6d4',
coffeeVerde: '#22c55e',
// Colores de estados (mantener consistentes)
statusPendiente: '#f59e0b',
statusPagado: '#10b981',
statusAnulado: '#6b7280'
}
}
@@ -507,6 +534,218 @@ watch(() => theme.value, (newTheme) => {
</div>
</UCard>
<!-- Documentación del Sistema de Temas -->
<UCard
:ui="{
base: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]',
body: { base: '', padding: 'px-4 py-5 sm:p-6' },
header: { base: 'border-b border-[var(--brand-border)]', padding: 'px-4 py-5 sm:px-6' }
}"
>
<template #header>
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-lg bg-[var(--brand-accent)]/20 flex items-center justify-center">
<UIcon name="i-lucide-book-open" class="size-5 text-[var(--brand-accent)]" />
</div>
<div>
<h3 class="font-semibold text-[var(--brand-text)]">
Cómo funciona el Sistema de Temas
</h3>
<p class="text-xs text-[var(--brand-text-muted)]">
Guía completa de personalización
</p>
</div>
</div>
</template>
<div class="space-y-6">
<!-- Introducción -->
<div>
<h4 class="text-sm font-semibold text-[var(--brand-primary)] mb-2">
¿Qué es el Sistema de Temas?
</h4>
<p class="text-sm text-[var(--brand-text-muted)] leading-relaxed">
El sistema de temas te permite personalizar completamente la apariencia de Analítica Núcleo.
Cada color que cambies se aplicará <strong class="text-[var(--brand-text)]">instantáneamente</strong> en
toda la aplicación: menús, tablas, gráficas, botones y más.
</p>
</div>
<div class="brand-divider"></div>
<!-- Variables de Color -->
<div>
<h4 class="text-sm font-semibold text-[var(--brand-primary)] mb-3">
Variables de Color
</h4>
<div class="space-y-3">
<!-- Fondo Principal -->
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded border-2 border-[var(--brand-border)] mt-0.5" :style="{ backgroundColor: theme.bg }"></div>
<div class="flex-1">
<p class="text-sm font-medium text-[var(--brand-text)]">Fondo Principal</p>
<p class="text-xs text-[var(--brand-text-muted)]">Color de fondo base de toda la aplicación</p>
</div>
</div>
<!-- Surface -->
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded border-2 border-[var(--brand-border)] mt-0.5" :style="{ backgroundColor: theme.surface }"></div>
<div class="flex-1">
<p class="text-sm font-medium text-[var(--brand-text)]">Fondo Secundario (Surface)</p>
<p class="text-xs text-[var(--brand-text-muted)]">Usado en cards, modales y elementos elevados</p>
</div>
</div>
<!-- Border -->
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded border-2 border-[var(--brand-border)] mt-0.5" :style="{ backgroundColor: theme.border }"></div>
<div class="flex-1">
<p class="text-sm font-medium text-[var(--brand-text)]">Color de Bordes</p>
<p class="text-xs text-[var(--brand-text-muted)]">Bordes de todos los elementos y separadores</p>
</div>
</div>
<!-- Primary -->
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded border-2 border-[var(--brand-border)] mt-0.5" :style="{ backgroundColor: theme.primary }"></div>
<div class="flex-1">
<p class="text-sm font-medium text-[var(--brand-text)]">Color Primario</p>
<p class="text-xs text-[var(--brand-text-muted)]">Enlaces, títulos destacados y elementos interactivos</p>
</div>
</div>
<!-- Primary Strong -->
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded border-2 border-[var(--brand-border)] mt-0.5" :style="{ backgroundColor: theme.primaryStrong }"></div>
<div class="flex-1">
<p class="text-sm font-medium text-[var(--brand-text)]">Color Primario Fuerte</p>
<p class="text-xs text-[var(--brand-text-muted)]">Variante más intensa para hover y énfasis</p>
</div>
</div>
<!-- Accent -->
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded border-2 border-[var(--brand-border)] mt-0.5" :style="{ backgroundColor: theme.accent }"></div>
<div class="flex-1">
<p class="text-sm font-medium text-[var(--brand-text)]">Color de Acento</p>
<p class="text-xs text-[var(--brand-text-muted)]">Highlights, badges y elementos de énfasis</p>
</div>
</div>
<!-- Text -->
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded border-2 border-[var(--brand-border)] mt-0.5" :style="{ backgroundColor: theme.text }"></div>
<div class="flex-1">
<p class="text-sm font-medium text-[var(--brand-text)]">Color de Texto</p>
<p class="text-xs text-[var(--brand-text-muted)]">Texto principal con alta legibilidad</p>
</div>
</div>
<!-- Text Muted -->
<div class="flex items-start gap-3">
<div class="w-6 h-6 rounded border-2 border-[var(--brand-border)] mt-0.5" :style="{ backgroundColor: theme.textMuted }"></div>
<div class="flex-1">
<p class="text-sm font-medium text-[var(--brand-text)]">Color de Texto Secundario</p>
<p class="text-xs text-[var(--brand-text-muted)]">Descripciones, subtítulos y texto menos prominente</p>
</div>
</div>
</div>
</div>
<div class="brand-divider"></div>
<!-- Cómo usar -->
<div>
<h4 class="text-sm font-semibold text-[var(--brand-primary)] mb-3">
Cómo Personalizar
</h4>
<div class="space-y-2">
<div class="flex items-start gap-2">
<UIcon name="i-lucide-check" class="size-4 text-[var(--brand-accent)] mt-0.5" />
<p class="text-sm text-[var(--brand-text-muted)]">
<strong class="text-[var(--brand-text)]">Temas Predefinidos:</strong> Haz clic en uno de los botones (Café, Azul, Verde, Carbón) para aplicar un tema completo
</p>
</div>
<div class="flex items-start gap-2">
<UIcon name="i-lucide-check" class="size-4 text-[var(--brand-accent)] mt-0.5" />
<p class="text-sm text-[var(--brand-text-muted)]">
<strong class="text-[var(--brand-text)]">Personalización Individual:</strong> Usa los selectores de color para ajustar cada variable a tu gusto
</p>
</div>
<div class="flex items-start gap-2">
<UIcon name="i-lucide-check" class="size-4 text-[var(--brand-accent)] mt-0.5" />
<p class="text-sm text-[var(--brand-text-muted)]">
<strong class="text-[var(--brand-text)]">Vista Previa en Vivo:</strong> Los cambios se aplican instantáneamente para que veas el resultado
</p>
</div>
<div class="flex items-start gap-2">
<UIcon name="i-lucide-check" class="size-4 text-[var(--brand-accent)] mt-0.5" />
<p class="text-sm text-[var(--brand-text-muted)]">
<strong class="text-[var(--brand-text)]">Guardar Cambios:</strong> No olvides hacer clic en "Guardar cambios" para que tu tema persista
</p>
</div>
</div>
</div>
<div class="brand-divider"></div>
<!-- Tips -->
<div>
<h4 class="text-sm font-semibold text-[var(--brand-primary)] mb-3">
Consejos y Mejores Prácticas
</h4>
<div class="space-y-2">
<div class="flex items-start gap-2">
<UIcon name="i-lucide-lightbulb" class="size-4 text-[var(--brand-accent)] mt-0.5" />
<p class="text-sm text-[var(--brand-text-muted)]">
<strong class="text-[var(--brand-text)]">Contraste:</strong> Asegúrate de que el texto tenga buen contraste con el fondo para facilitar la lectura
</p>
</div>
<div class="flex items-start gap-2">
<UIcon name="i-lucide-lightbulb" class="size-4 text-[var(--brand-accent)] mt-0.5" />
<p class="text-sm text-[var(--brand-text-muted)]">
<strong class="text-[var(--brand-text)]">Armonía:</strong> El "Color Primario Fuerte" debería ser una versión más intensa del "Color Primario"
</p>
</div>
<div class="flex items-start gap-2">
<UIcon name="i-lucide-lightbulb" class="size-4 text-[var(--brand-accent)] mt-0.5" />
<p class="text-sm text-[var(--brand-text-muted)]">
<strong class="text-[var(--brand-text)]">Exportar:</strong> Usa "Exportar tema" para hacer backup de tu configuración o compartirla
</p>
</div>
<div class="flex items-start gap-2">
<UIcon name="i-lucide-lightbulb" class="size-4 text-[var(--brand-accent)] mt-0.5" />
<p class="text-sm text-[var(--brand-text-muted)]">
<strong class="text-[var(--brand-text)]">Resetear:</strong> Si no te gusta el resultado, usa "Restaurar por defecto" para volver al tema Café original
</p>
</div>
</div>
</div>
<div class="brand-divider"></div>
<!-- Alcance -->
<div class="bg-[var(--brand-primary)]/5 border border-[var(--brand-primary)]/20 rounded-lg p-4">
<div class="flex items-start gap-3">
<UIcon name="i-lucide-info" class="size-5 text-[var(--brand-primary)] mt-0.5" />
<div>
<p class="text-sm font-medium text-[var(--brand-text)] mb-1">
Alcance del Sistema de Temas
</p>
<p class="text-xs text-[var(--brand-text-muted)] leading-relaxed">
El tema se aplica a <strong class="text-[var(--brand-text)]">toda la aplicación</strong>: sidebar,
menús, tablas, cards, gráficas, botones, inputs y más. Los únicos colores que NO cambian son
los semánticos (estados de éxito/error/advertencia) y los identificadores de tipos de café
(Uva/Oreado/Mojado/Verde) que mantienen sus colores específicos para mejor identificación.
</p>
</div>
</div>
</div>
</div>
</UCard>
<!-- Otras configuraciones (placeholder) -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<UCard