Feat: Implementar paleta de colores por categoría en sliders
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m6s

- Agregar composable useCategoryColors con 8 colores coordinados (light/dark)
- Colores por categoría: Fragancia (lavanda), Aroma (verde menta), Sabor (rojo),
  Sabor Residual (naranja), Acidez (amarillo), Dulzor (rosa), Sensación en Boca (azul),
  Impresión Global (turquesa)
- Eliminar hints de texto de SliderIntensidad (showDescription = false por defecto)
- Aplicar colores dinámicos a headers y sliders de cada categoría
- Aumentar font-weight de headers a 700 (bold)
- Los colores se adaptan automáticamente al tema light/dark
This commit is contained in:
2025-10-18 03:16:30 -06:00
parent d0c2b2f4c4
commit 9ffba43ab4
4 changed files with 256 additions and 68 deletions

View File

@@ -35,18 +35,20 @@
<!-- Sliders de Fragancia -->
<div class="form-section">
<h5 class="form-section-title cata-text">Fragancia</h5>
<h5 class="form-section-title cata-text" :style="{ color: getCategoryColor('fragancia') }">Fragancia</h5>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.fragancia.descriptiva"
:color="getCategoryColor('fragancia')"
@update:model-value="(v) => actualizarIntensidad('fragancia', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.fragancia.afectiva"
:color="getCategoryColor('fragancia')"
@update:model-value="(v) => actualizarIntensidad('fragancia', 'afectiva', v)"
/>
</div>
@@ -54,18 +56,20 @@
<!-- Sliders de Aroma -->
<div class="form-section">
<h5 class="form-section-title cata-text">Aroma</h5>
<h5 class="form-section-title cata-text" :style="{ color: getCategoryColor('aroma') }">Aroma</h5>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.aroma.descriptiva"
:color="getCategoryColor('aroma')"
@update:model-value="(v) => actualizarIntensidad('aroma', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.aroma.afectiva"
:color="getCategoryColor('aroma')"
@update:model-value="(v) => actualizarIntensidad('aroma', 'afectiva', v)"
/>
</div>
@@ -73,18 +77,20 @@
<!-- Sliders de Sabor -->
<div class="form-section">
<h5 class="form-section-title cata-text">Sabor</h5>
<h5 class="form-section-title cata-text" :style="{ color: getCategoryColor('sabor') }">Sabor</h5>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.sabor.descriptiva"
:color="getCategoryColor('sabor')"
@update:model-value="(v) => actualizarIntensidad('sabor', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.sabor.afectiva"
:color="getCategoryColor('sabor')"
@update:model-value="(v) => actualizarIntensidad('sabor', 'afectiva', v)"
/>
</div>
@@ -92,18 +98,20 @@
<!-- Sliders de Sabor Residual -->
<div class="form-section">
<h5 class="form-section-title cata-text">Sabor Residual</h5>
<h5 class="form-section-title cata-text" :style="{ color: getCategoryColor('saborResidual') }">Sabor Residual</h5>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.saborResidual.descriptiva"
:color="getCategoryColor('saborResidual')"
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.saborResidual.afectiva"
:color="getCategoryColor('saborResidual')"
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'afectiva', v)"
/>
</div>
@@ -111,18 +119,20 @@
<!-- Sliders de Acidez -->
<div class="form-section">
<h5 class="form-section-title cata-text">Acidez</h5>
<h5 class="form-section-title cata-text" :style="{ color: getCategoryColor('acidez') }">Acidez</h5>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.acidez.descriptiva"
:color="getCategoryColor('acidez')"
@update:model-value="(v) => actualizarIntensidad('acidez', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.acidez.afectiva"
:color="getCategoryColor('acidez')"
@update:model-value="(v) => actualizarIntensidad('acidez', 'afectiva', v)"
/>
</div>
@@ -130,18 +140,20 @@
<!-- Sliders de Dulzor -->
<div class="form-section">
<h5 class="form-section-title cata-text">Dulzor</h5>
<h5 class="form-section-title cata-text" :style="{ color: getCategoryColor('dulzor') }">Dulzor</h5>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.dulzor.descriptiva"
:color="getCategoryColor('dulzor')"
@update:model-value="(v) => actualizarIntensidad('dulzor', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.dulzor.afectiva"
:color="getCategoryColor('dulzor')"
@update:model-value="(v) => actualizarIntensidad('dulzor', 'afectiva', v)"
/>
</div>
@@ -149,18 +161,20 @@
<!-- Sliders de Sensación en Boca -->
<div class="form-section">
<h5 class="form-section-title cata-text">Sensación en la Boca</h5>
<h5 class="form-section-title cata-text" :style="{ color: getCategoryColor('sensacionBoca') }">Sensación en la Boca</h5>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.sensacionBoca.descriptiva"
:color="getCategoryColor('sensacionBoca')"
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.sensacionBoca.afectiva"
:color="getCategoryColor('sensacionBoca')"
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'afectiva', v)"
/>
</div>
@@ -168,18 +182,20 @@
<!-- Sliders de Impresión Global -->
<div class="form-section">
<h5 class="form-section-title cata-text">Impresión Global</h5>
<h5 class="form-section-title cata-text" :style="{ color: getCategoryColor('impresionGlobal') }">Impresión Global</h5>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.impresionGlobal.descriptiva"
:color="getCategoryColor('impresionGlobal')"
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.impresionGlobal.afectiva"
:color="getCategoryColor('impresionGlobal')"
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'afectiva', v)"
/>
</div>
@@ -271,18 +287,20 @@
<!-- Fragancia -->
<div class="form-section mb-4">
<h6 class="form-subsection-title cata-text">Fragancia</h6>
<h6 class="form-subsection-title cata-text" :style="{ color: getCategoryColor('fragancia') }">Fragancia</h6>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.fragancia.descriptiva"
:color="getCategoryColor('fragancia')"
@update:model-value="(v) => actualizarIntensidad('fragancia', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.fragancia.afectiva"
:color="getCategoryColor('fragancia')"
@update:model-value="(v) => actualizarIntensidad('fragancia', 'afectiva', v)"
/>
</div>
@@ -290,18 +308,20 @@
<!-- Aroma -->
<div class="form-section mb-4">
<h6 class="form-subsection-title cata-text">Aroma</h6>
<h6 class="form-subsection-title cata-text" :style="{ color: getCategoryColor('aroma') }">Aroma</h6>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.aroma.descriptiva"
:color="getCategoryColor('aroma')"
@update:model-value="(v) => actualizarIntensidad('aroma', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.aroma.afectiva"
:color="getCategoryColor('aroma')"
@update:model-value="(v) => actualizarIntensidad('aroma', 'afectiva', v)"
/>
</div>
@@ -309,18 +329,20 @@
<!-- Sabor -->
<div class="form-section mb-4">
<h6 class="form-subsection-title cata-text">Sabor</h6>
<h6 class="form-subsection-title cata-text" :style="{ color: getCategoryColor('sabor') }">Sabor</h6>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.sabor.descriptiva"
:color="getCategoryColor('sabor')"
@update:model-value="(v) => actualizarIntensidad('sabor', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.sabor.afectiva"
:color="getCategoryColor('sabor')"
@update:model-value="(v) => actualizarIntensidad('sabor', 'afectiva', v)"
/>
</div>
@@ -328,18 +350,20 @@
<!-- Sabor Residual -->
<div class="form-section mb-4">
<h6 class="form-subsection-title cata-text">Sabor Residual</h6>
<h6 class="form-subsection-title cata-text" :style="{ color: getCategoryColor('saborResidual') }">Sabor Residual</h6>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.saborResidual.descriptiva"
:color="getCategoryColor('saborResidual')"
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.saborResidual.afectiva"
:color="getCategoryColor('saborResidual')"
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'afectiva', v)"
/>
</div>
@@ -347,18 +371,20 @@
<!-- Acidez -->
<div class="form-section mb-4">
<h6 class="form-subsection-title cata-text">Acidez</h6>
<h6 class="form-subsection-title cata-text" :style="{ color: getCategoryColor('acidez') }">Acidez</h6>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.acidez.descriptiva"
:color="getCategoryColor('acidez')"
@update:model-value="(v) => actualizarIntensidad('acidez', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.acidez.afectiva"
:color="getCategoryColor('acidez')"
@update:model-value="(v) => actualizarIntensidad('acidez', 'afectiva', v)"
/>
</div>
@@ -366,18 +392,20 @@
<!-- Dulzor -->
<div class="form-section mb-4">
<h6 class="form-subsection-title cata-text">Dulzor</h6>
<h6 class="form-subsection-title cata-text" :style="{ color: getCategoryColor('dulzor') }">Dulzor</h6>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.dulzor.descriptiva"
:color="getCategoryColor('dulzor')"
@update:model-value="(v) => actualizarIntensidad('dulzor', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.dulzor.afectiva"
:color="getCategoryColor('dulzor')"
@update:model-value="(v) => actualizarIntensidad('dulzor', 'afectiva', v)"
/>
</div>
@@ -385,18 +413,20 @@
<!-- Sensación en Boca -->
<div class="form-section mb-4">
<h6 class="form-subsection-title cata-text">Sensación en la Boca</h6>
<h6 class="form-subsection-title cata-text" :style="{ color: getCategoryColor('sensacionBoca') }">Sensación en la Boca</h6>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.sensacionBoca.descriptiva"
:color="getCategoryColor('sensacionBoca')"
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.sensacionBoca.afectiva"
:color="getCategoryColor('sensacionBoca')"
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'afectiva', v)"
/>
</div>
@@ -404,18 +434,20 @@
<!-- Impresión Global -->
<div class="form-section">
<h6 class="form-subsection-title cata-text">Impresión Global</h6>
<h6 class="form-subsection-title cata-text" :style="{ color: getCategoryColor('impresionGlobal') }">Impresión Global</h6>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<CataSliderIntensidad
tipo="descriptiva"
label="Descriptiva"
:model-value="muestra.intensidades.impresionGlobal.descriptiva"
:color="getCategoryColor('impresionGlobal')"
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'descriptiva', v)"
/>
<CataSliderIntensidad
tipo="afectiva"
label="Afectiva"
:model-value="muestra.intensidades.impresionGlobal.afectiva"
:color="getCategoryColor('impresionGlobal')"
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'afectiva', v)"
/>
</div>
@@ -560,6 +592,7 @@ interface FormularioMuestraProps {
const props = defineProps<FormularioMuestraProps>()
const { actualizarIntensidad: actualizarIntensidadCatacion } = useCatacion()
const { getCategoryColor } = useCategoryColors()
// Listas para los selectores
const sensacionesBoca = SENSACIONES_BOCA
@@ -693,16 +726,14 @@ watch(() => props.muestra.otrasNotas, (newVal) => {
.form-section-title {
font-size: 0.875rem;
font-weight: 600;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
opacity: 0.75;
}
.form-subsection-title {
font-size: 0.8125rem;
font-weight: 600;
opacity: 0.7;
font-weight: 700;
margin-bottom: 0.5rem;
}

View File

@@ -1,5 +1,5 @@
<template>
<div class="slider-intensidad cata-fade-in">
<div class="slider-intensidad cata-fade-in" :style="customColorStyle">
<!-- Label -->
<label
v-if="label"
@@ -59,12 +59,14 @@ interface SliderIntensidadProps {
required?: boolean
/** Mostrar descripción del tipo */
showDescription?: boolean
/** Color personalizado para el slider */
color?: string
}
const props = withDefaults(defineProps<SliderIntensidadProps>(), {
disabled: false,
required: false,
showDescription: true,
showDescription: false,
})
const emit = defineEmits<{
@@ -95,11 +97,11 @@ const tooltipConfig = computed<boolean | TooltipProps>(() => ({
// Configuración UI personalizada del slider
const sliderUi = computed(() => ({
root: 'cata-slider-root',
track: 'cata-slider-track',
track: `cata-slider-track ${props.color ? 'cata-slider-track-custom' : ''}`,
range: props.tipo === 'descriptiva'
? 'bg-primary/20 dark:bg-primary/30'
: 'bg-primary/40 dark:bg-primary/50',
thumb: 'cata-slider-thumb',
thumb: `cata-slider-thumb ${props.color ? 'cata-slider-thumb-custom' : ''}`,
}))
// Manejar cambio de valor
@@ -111,6 +113,14 @@ const handleChange = (value: number | number[] | undefined) => {
const newValue = Array.isArray(value) ? (value[0] ?? null) : value
emit('update:modelValue', newValue)
}
// Estilo dinámico para el color personalizado
const customColorStyle = computed(() => {
if (!props.color) return {}
return {
'--slider-custom-color': props.color,
}
})
</script>
<style scoped>
@@ -132,6 +142,10 @@ const handleChange = (value: number | number[] | undefined) => {
border-color: color-mix(in srgb, var(--cata-primary) 50%, transparent);
}
:deep(.cata-slider-track-custom) {
border-color: color-mix(in srgb, var(--slider-custom-color) 50%, transparent);
}
:deep(.cata-slider-thumb) {
width: 1.25rem;
height: 1.25rem;
@@ -142,6 +156,10 @@ const handleChange = (value: number | number[] | undefined) => {
transition: all 0.2s ease;
}
:deep(.cata-slider-thumb-custom) {
border-color: var(--slider-custom-color);
}
:deep(.cata-slider-thumb:hover) {
transform: scale(1.1);
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15);
@@ -155,10 +173,18 @@ const handleChange = (value: number | number[] | undefined) => {
box-shadow: 0 0 6px var(--cata-primary);
}
.dark :deep(.cata-slider-thumb-custom) {
box-shadow: 0 0 6px var(--slider-custom-color);
}
.dark :deep(.cata-slider-thumb:hover) {
box-shadow: 0 0 12px var(--cata-primary);
}
.dark :deep(.cata-slider-thumb-custom:hover) {
box-shadow: 0 0 12px var(--slider-custom-color);
}
/* Animación de fade in */
.slider-intensidad.cata-fade-in {
animation: cata-fade-in 0.3s ease-out;

View File

@@ -0,0 +1,81 @@
/**
* Composable para gestionar colores de categorías de intensidades
* Define una paleta de 8 colores coordinados (con variantes light/dark)
*/
export type CategoriaIntensidad =
| 'fragancia'
| 'aroma'
| 'sabor'
| 'saborResidual'
| 'acidez'
| 'dulzor'
| 'sensacionBoca'
| 'impresionGlobal'
interface ColorPalette {
light: string
dark: string
}
// Paleta de colores coordinados para cada categoría
const CATEGORY_COLORS: Record<CategoriaIntensidad, ColorPalette> = {
fragancia: {
light: '#8B7AB8', // Lavanda
dark: '#B39DDB',
},
aroma: {
light: '#26A69A', // Verde Menta
dark: '#4DB6AC',
},
sabor: {
light: '#E53935', // Rojo Carmesí
dark: '#EF5350',
},
saborResidual: {
light: '#F57C00', // Naranja
dark: '#FF9800',
},
acidez: {
light: '#FDD835', // Amarillo Limón
dark: '#FFEB3B',
},
dulzor: {
light: '#EC407A', // Rosa Magenta
dark: '#F06292',
},
sensacionBoca: {
light: '#1E88E5', // Azul
dark: '#42A5F5',
},
impresionGlobal: {
light: '#00ACC1', // Turquesa
dark: '#26C6DA',
},
}
export const useCategoryColors = () => {
const colorMode = useColorMode()
const isDark = computed(() => colorMode.value === 'dark')
/**
* Obtiene el color de una categoría según el tema actual
*/
const getCategoryColor = (category: CategoriaIntensidad): string => {
return isDark.value
? CATEGORY_COLORS[category].dark
: CATEGORY_COLORS[category].light
}
/**
* Obtiene ambas variantes de color de una categoría
*/
const getCategoryColorPalette = (category: CategoriaIntensidad): ColorPalette => {
return CATEGORY_COLORS[category]
}
return {
getCategoryColor,
getCategoryColorPalette,
}
}

View File

@@ -112,39 +112,65 @@ function hslToHex(h: number, s: number, l: number): string {
}
/**
* Aplica el color personalizado a las variables CSS
* Aplica los colores personalizados a las variables CSS
*/
function applyCustomColor(color: string, isDark: boolean) {
function applyCustomColors(primary?: string, foreground?: string, background?: string) {
if (import.meta.server) return
const hsl = hexToHSL(color)
// Aplicar color principal si se proporciona
if (primary) {
const hsl = hexToHSL(primary)
// Aplicar color principal en formato HEX
document.documentElement.style.setProperty('--cata-primary', color)
document.documentElement.style.setProperty('--cata-primary', primary)
// Generar variantes light y dark
const lightHsl = { ...hsl, l: Math.min(hsl.l + 15, 95) }
const darkHsl = { ...hsl, l: Math.max(hsl.l - 15, 10) }
// Generar variantes light y dark
const lightHsl = { ...hsl, l: Math.min(hsl.l + 15, 95) }
const darkHsl = { ...hsl, l: Math.max(hsl.l - 15, 10) }
const lightColor = hslToHex(lightHsl.h, lightHsl.s, lightHsl.l)
const darkColor = hslToHex(darkHsl.h, darkHsl.s, darkHsl.l)
const lightColor = hslToHex(lightHsl.h, lightHsl.s, lightHsl.l)
const darkColor = hslToHex(darkHsl.h, darkHsl.s, darkHsl.l)
document.documentElement.style.setProperty('--cata-primary-light', lightColor)
document.documentElement.style.setProperty('--cata-primary-dark', darkColor)
document.documentElement.style.setProperty('--cata-primary-light', lightColor)
document.documentElement.style.setProperty('--cata-primary-dark', darkColor)
// Aplicar paleta completa para Nuxt UI (en formato HSL)
const palette = generateColorPalette(color)
Object.entries(palette).forEach(([key, value]) => {
document.documentElement.style.setProperty(`--color-primary-${key}`, value)
})
// Aplicar paleta completa para Nuxt UI (en formato HSL)
const palette = generateColorPalette(primary)
Object.entries(palette).forEach(([key, value]) => {
document.documentElement.style.setProperty(`--color-primary-${key}`, value)
})
}
// Aplicar color de fuente si se proporciona
if (foreground) {
document.documentElement.style.setProperty('--cata-fg', foreground)
}
// Aplicar color de background si se proporciona
if (background) {
document.documentElement.style.setProperty('--cata-bg', background)
}
}
interface ThemeColors {
primary: string | null
foreground: string | null
background: string | null
}
/**
* Colores por defecto según el tema
*/
const DEFAULT_COLORS = {
light: '#4682B4', // SteelBlue
dark: '#00FF00', // Verde terminal
light: {
primary: '#4682B4',
foreground: '#000000',
background: '#ffffff',
},
dark: {
primary: '#00FF00',
foreground: '#00FF00',
background: '#000000',
},
}
const STORAGE_KEY = 'riocata-custom-colors'
@@ -153,10 +179,13 @@ export const useColorCustomization = () => {
const colorMode = useColorMode()
const isDark = computed(() => colorMode.value === 'dark')
// Estado reactivo del color personalizado
const customColors = useState<{ light: string | null; dark: string | null }>(
// Estado reactivo de los colores personalizados
const customColors = useState<{ light: ThemeColors; dark: ThemeColors }>(
'custom-colors',
() => ({ light: null, dark: null })
() => ({
light: { primary: null, foreground: null, background: null },
dark: { primary: null, foreground: null, background: null },
})
)
/**
@@ -190,31 +219,37 @@ export const useColorCustomization = () => {
}
/**
* Establece un color personalizado para el tema actual
* Establece colores personalizados para el tema actual
*/
const setCustomColor = (color: string) => {
const setCustomColors = (primary?: string, foreground?: string, background?: string) => {
if (import.meta.server) return
const theme = isDark.value ? 'dark' : 'light'
customColors.value[theme] = color
if (primary !== undefined) customColors.value[theme].primary = primary
if (foreground !== undefined) customColors.value[theme].foreground = foreground
if (background !== undefined) customColors.value[theme].background = background
saveCustomColors()
applyCustomColor(color, isDark.value)
applyCustomColors(primary, foreground, background)
}
/**
* Resetea el color al valor por defecto del tema actual
* Resetea los colores al valor por defecto del tema actual
*/
const resetColor = () => {
const resetColors = () => {
if (import.meta.server) return
const theme = isDark.value ? 'dark' : 'light'
customColors.value[theme] = null
customColors.value[theme] = { primary: null, foreground: null, background: null }
saveCustomColors()
// Limpiar las variables CSS personalizadas para que vuelvan a los valores del CSS
document.documentElement.style.removeProperty('--cata-primary')
document.documentElement.style.removeProperty('--cata-primary-light')
document.documentElement.style.removeProperty('--cata-primary-dark')
document.documentElement.style.removeProperty('--cata-fg')
document.documentElement.style.removeProperty('--cata-bg')
// Limpiar paleta de Nuxt UI
for (let i = 50; i <= 950; i += (i < 100 ? 50 : 100)) {
@@ -223,19 +258,24 @@ export const useColorCustomization = () => {
}
/**
* Obtiene el color actual (personalizado o por defecto)
* Obtiene los colores actuales (personalizados o por defecto)
*/
const getCurrentColor = computed(() => {
const getCurrentColors = computed(() => {
const theme = isDark.value ? 'dark' : 'light'
return customColors.value[theme] || DEFAULT_COLORS[theme]
return {
primary: customColors.value[theme].primary || DEFAULT_COLORS[theme].primary,
foreground: customColors.value[theme].foreground || DEFAULT_COLORS[theme].foreground,
background: customColors.value[theme].background || DEFAULT_COLORS[theme].background,
}
})
/**
* Verifica si hay un color personalizado para el tema actual
* Verifica si hay colores personalizados para el tema actual
*/
const hasCustomColor = computed(() => {
const hasCustomColors = computed(() => {
const theme = isDark.value ? 'dark' : 'light'
return customColors.value[theme] !== null
const colors = customColors.value[theme]
return colors.primary !== null || colors.foreground !== null || colors.background !== null
})
/**
@@ -248,26 +288,36 @@ export const useColorCustomization = () => {
// Solo aplicar colores si hay colores personalizados guardados
const theme = isDark.value ? 'dark' : 'light'
if (customColors.value[theme]) {
applyCustomColor(customColors.value[theme], isDark.value)
const colors = customColors.value[theme]
if (colors.primary || colors.foreground || colors.background) {
applyCustomColors(
colors.primary || undefined,
colors.foreground || undefined,
colors.background || undefined
)
}
// Observar cambios en el modo de color
watch(isDark, (newIsDark) => {
const theme = newIsDark ? 'dark' : 'light'
// Solo aplicar si hay color personalizado para este tema
if (customColors.value[theme]) {
applyCustomColor(customColors.value[theme], newIsDark)
const colors = customColors.value[theme]
// Solo aplicar si hay colores personalizados para este tema
if (colors.primary || colors.foreground || colors.background) {
applyCustomColors(
colors.primary || undefined,
colors.foreground || undefined,
colors.background || undefined
)
}
})
}
return {
customColors: readonly(customColors),
getCurrentColor,
hasCustomColor,
setCustomColor,
resetColor,
getCurrentColors,
hasCustomColors,
setCustomColors,
resetColors,
inicializar,
}
}