All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 49s
Cambios realizados: - Agregada variable success (#00dc82 Nuxt green) para botones de confirmación y elementos de éxito - Agregados inputs de color para todas las variables de café (Uva, Oreado, Mojado, Verde) - Agregados inputs de color para todas las variables de estados (Pendiente, Pagado, Anulado) - Actualizada interfaz ThemeColors con nueva propiedad success - Actualizados todos los temas preestablecidos (café, azul, verde, carbón) con variable success - Actualizada validación de importación de temas con nueva propiedad - Agregado CSS --brand-success en main.css Los usuarios ahora pueden personalizar completamente todos los colores del sistema: - 9 colores base (incluye success) - 4 colores de tipos de café - 3 colores de estados de pago Total: 16 variables personalizables La variable success se aplica a: - Botones de confirmación - Página seleccionada en sidebar - Indicadores de éxito
981 lines
39 KiB
Vue
981 lines
39 KiB
Vue
<script setup lang="ts">
|
|
import { ref, watch } from 'vue'
|
|
import type { ThemeColors } from '~/composables/useTheme'
|
|
|
|
definePageMeta({
|
|
layout: 'dashboard',
|
|
title: 'Configuración'
|
|
})
|
|
|
|
// Usar el composable de temas
|
|
const {
|
|
theme,
|
|
defaultTheme,
|
|
applyTheme,
|
|
saveTheme: saveThemeComposable,
|
|
resetTheme: resetThemeComposable,
|
|
exportTheme,
|
|
importTheme
|
|
} = useTheme()
|
|
|
|
// Temas predefinidos
|
|
const presetThemes: Record<string, ThemeColors> = {
|
|
cafe: { ...defaultTheme },
|
|
azul: {
|
|
bg: '#0a0e1a',
|
|
surface: '#151a28',
|
|
border: '#2d3748',
|
|
primary: '#60a5fa',
|
|
primaryStrong: '#3b82f6',
|
|
accent: '#93c5fd',
|
|
success: '#00dc82',
|
|
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'
|
|
},
|
|
verde: {
|
|
bg: '#0f1a14',
|
|
surface: '#1a2820',
|
|
border: '#2d4033',
|
|
primary: '#86efac',
|
|
primaryStrong: '#4ade80',
|
|
accent: '#bbf7d0',
|
|
success: '#00dc82',
|
|
text: '#f0fdf4',
|
|
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',
|
|
surface: '#1a1a1a',
|
|
border: '#333333',
|
|
primary: '#a3a3a3',
|
|
primaryStrong: '#737373',
|
|
accent: '#d4d4d4',
|
|
success: '#00dc82',
|
|
text: '#fafafa',
|
|
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'
|
|
}
|
|
}
|
|
|
|
// Aplicar preset de tema
|
|
const applyPreset = (presetName: keyof typeof presetThemes) => {
|
|
const preset = presetThemes[presetName]
|
|
theme.value = { ...preset }
|
|
applyTheme(theme.value)
|
|
useToast().add({
|
|
title: 'Tema aplicado',
|
|
description: `Se aplicó el tema ${presetName}`,
|
|
color: 'blue'
|
|
})
|
|
}
|
|
|
|
// Guardar tema con feedback
|
|
const handleSaveTheme = () => {
|
|
const success = saveThemeComposable()
|
|
if (success) {
|
|
useToast().add({
|
|
title: 'Tema guardado',
|
|
description: 'Los cambios se aplicaron correctamente',
|
|
color: 'green'
|
|
})
|
|
} else {
|
|
useToast().add({
|
|
title: 'Error al guardar',
|
|
description: 'No se pudo guardar el tema',
|
|
color: 'red'
|
|
})
|
|
}
|
|
}
|
|
|
|
// Resetear al tema por defecto
|
|
const handleResetTheme = () => {
|
|
resetThemeComposable()
|
|
useToast().add({
|
|
title: 'Tema reseteado',
|
|
description: 'Se restauraron los colores por defecto',
|
|
color: 'blue'
|
|
})
|
|
}
|
|
|
|
// Exportar tema al portapapeles
|
|
const handleExportTheme = async () => {
|
|
try {
|
|
const themeJson = exportTheme()
|
|
await navigator.clipboard.writeText(themeJson)
|
|
useToast().add({
|
|
title: 'Tema exportado',
|
|
description: 'El JSON del tema se copió al portapapeles',
|
|
color: 'green'
|
|
})
|
|
} catch (error) {
|
|
useToast().add({
|
|
title: 'Error al exportar',
|
|
description: 'No se pudo copiar al portapapeles',
|
|
color: 'red'
|
|
})
|
|
}
|
|
}
|
|
|
|
// Importar tema desde JSON
|
|
const importJsonInput = ref('')
|
|
const showImportModal = ref(false)
|
|
|
|
const handleImportTheme = () => {
|
|
const success = importTheme(importJsonInput.value, false)
|
|
if (success) {
|
|
useToast().add({
|
|
title: 'Tema importado',
|
|
description: 'El tema se aplicó correctamente',
|
|
color: 'green'
|
|
})
|
|
showImportModal.value = false
|
|
importJsonInput.value = ''
|
|
} else {
|
|
useToast().add({
|
|
title: 'Error al importar',
|
|
description: 'El JSON proporcionado no es válido',
|
|
color: 'red'
|
|
})
|
|
}
|
|
}
|
|
|
|
// Vista previa en tiempo real (activada por defecto)
|
|
const livePreview = ref(true)
|
|
watch(() => theme.value, (newTheme) => {
|
|
if (livePreview.value) {
|
|
applyTheme(newTheme)
|
|
}
|
|
}, { deep: true })
|
|
</script>
|
|
|
|
<template>
|
|
<UDashboardLayout>
|
|
<UDashboardPanel grow>
|
|
<UDashboardNavbar
|
|
title="Configuración"
|
|
description="Personaliza tu experiencia y preferencias del sistema"
|
|
/>
|
|
|
|
<UDashboardPanelContent>
|
|
<div class="max-w-4xl mx-auto space-y-8">
|
|
<!-- Configuración de Tema -->
|
|
<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 justify-between">
|
|
<div class="flex items-center gap-3">
|
|
<div class="w-10 h-10 rounded-lg bg-[var(--brand-primary)]/20 flex items-center justify-center">
|
|
<UIcon name="i-lucide-palette" class="size-5 text-[var(--brand-primary)]" />
|
|
</div>
|
|
<div>
|
|
<h3 class="font-semibold text-[var(--brand-text)]">
|
|
Tema y Apariencia
|
|
</h3>
|
|
<p class="text-sm text-[var(--brand-text-muted)]">
|
|
Personaliza los colores de la interfaz
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<UToggle v-model="livePreview" label="Vista previa en vivo" />
|
|
</div>
|
|
</template>
|
|
|
|
<!-- Temas Predefinidos -->
|
|
<div class="mb-6 pb-6 border-b border-[var(--brand-border)]">
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-3">
|
|
Temas Predefinidos
|
|
</label>
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-3">
|
|
<button
|
|
@click="applyPreset('cafe')"
|
|
class="p-4 rounded-lg border-2 border-[var(--brand-border)] hover:border-[var(--brand-primary)] transition-colors group"
|
|
>
|
|
<div class="flex gap-2 mb-2">
|
|
<div class="w-6 h-6 rounded" style="background: #e0c080" />
|
|
<div class="w-6 h-6 rounded" style="background: #1f180f" />
|
|
</div>
|
|
<p class="text-xs text-[var(--brand-text)] font-medium group-hover:text-[var(--brand-primary)]">Café</p>
|
|
</button>
|
|
|
|
<button
|
|
@click="applyPreset('azul')"
|
|
class="p-4 rounded-lg border-2 border-[var(--brand-border)] hover:border-[var(--brand-primary)] transition-colors group"
|
|
>
|
|
<div class="flex gap-2 mb-2">
|
|
<div class="w-6 h-6 rounded" style="background: #60a5fa" />
|
|
<div class="w-6 h-6 rounded" style="background: #151a28" />
|
|
</div>
|
|
<p class="text-xs text-[var(--brand-text)] font-medium group-hover:text-[var(--brand-primary)]">Azul</p>
|
|
</button>
|
|
|
|
<button
|
|
@click="applyPreset('verde')"
|
|
class="p-4 rounded-lg border-2 border-[var(--brand-border)] hover:border-[var(--brand-primary)] transition-colors group"
|
|
>
|
|
<div class="flex gap-2 mb-2">
|
|
<div class="w-6 h-6 rounded" style="background: #86efac" />
|
|
<div class="w-6 h-6 rounded" style="background: #1a2820" />
|
|
</div>
|
|
<p class="text-xs text-[var(--brand-text)] font-medium group-hover:text-[var(--brand-primary)]">Verde</p>
|
|
</button>
|
|
|
|
<button
|
|
@click="applyPreset('carbon')"
|
|
class="p-4 rounded-lg border-2 border-[var(--brand-border)] hover:border-[var(--brand-primary)] transition-colors group"
|
|
>
|
|
<div class="flex gap-2 mb-2">
|
|
<div class="w-6 h-6 rounded" style="background: #a3a3a3" />
|
|
<div class="w-6 h-6 rounded" style="background: #1a1a1a" />
|
|
</div>
|
|
<p class="text-xs text-[var(--brand-text)] font-medium group-hover:text-[var(--brand-primary)]">Carbón</p>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-6">
|
|
<!-- Fondo Principal -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Fondo Principal
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.bg"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.bg"
|
|
placeholder="var(--brand-bg)"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Fondo Secundario (Surface)
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.surface"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.surface"
|
|
placeholder="#1f180f"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bordes y Primario -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Color de Bordes
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.border"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.border"
|
|
placeholder="#3a2a16"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Color Primario
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.primary"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.primary"
|
|
placeholder="#e0c080"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Primario Fuerte y Acento -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Color Primario Fuerte
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.primaryStrong"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.primaryStrong"
|
|
placeholder="var(--brand-primary-strong)"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Color de Acento
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.accent"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.accent"
|
|
placeholder="#ffe0a0"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Éxito/Confirmación -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Color de Éxito/Confirmación
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.success"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.success"
|
|
placeholder="#00dc82"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
<p class="text-xs text-[var(--brand-text-muted)] mt-1">
|
|
Se usa en botones de confirmar, página seleccionada en sidebar, etc.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Texto y Texto Muted -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Color de Texto
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.text"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.text"
|
|
placeholder="#fef9f0"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Color de Texto Secundario
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.textMuted"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.textMuted"
|
|
placeholder="#d8c7a6"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Separador -->
|
|
<div class="pt-6 border-t border-[var(--brand-border)]">
|
|
<h4 class="text-sm font-semibold text-[var(--brand-text)] mb-4">
|
|
Colores de Tipos de Café
|
|
</h4>
|
|
</div>
|
|
|
|
<!-- Café Uva y Oreado -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Café Uva
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.coffeeUva"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.coffeeUva"
|
|
placeholder="#a855f7"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Café Oreado
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.coffeeOreado"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.coffeeOreado"
|
|
placeholder="#f97316"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Café Mojado y Verde -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Café Mojado
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.coffeeMojado"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.coffeeMojado"
|
|
placeholder="#06b6d4"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Café Verde
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.coffeeVerde"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.coffeeVerde"
|
|
placeholder="#22c55e"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Separador -->
|
|
<div class="pt-6 border-t border-[var(--brand-border)]">
|
|
<h4 class="text-sm font-semibold text-[var(--brand-text)] mb-4">
|
|
Colores de Estados
|
|
</h4>
|
|
</div>
|
|
|
|
<!-- Estado Pendiente y Pagado -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Estado Pendiente
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.statusPendiente"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.statusPendiente"
|
|
placeholder="#f59e0b"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Estado Pagado
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.statusPagado"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.statusPagado"
|
|
placeholder="#10b981"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Estado Anulado -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Estado Anulado
|
|
</label>
|
|
<div class="flex gap-2">
|
|
<input
|
|
v-model="theme.statusAnulado"
|
|
type="color"
|
|
class="h-10 w-20 rounded-lg border border-[var(--brand-border)] cursor-pointer"
|
|
/>
|
|
<UInput
|
|
v-model="theme.statusAnulado"
|
|
placeholder="#6b7280"
|
|
class="flex-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Acciones -->
|
|
<div class="space-y-3 pt-4 border-t border-[var(--brand-border)]">
|
|
<!-- Botones principales -->
|
|
<div class="flex justify-between items-center">
|
|
<UButton
|
|
color="neutral"
|
|
variant="ghost"
|
|
icon="i-lucide-rotate-ccw"
|
|
@click="handleResetTheme"
|
|
>
|
|
Restaurar por defecto
|
|
</UButton>
|
|
<UButton
|
|
color="primary"
|
|
icon="i-lucide-save"
|
|
@click="handleSaveTheme"
|
|
>
|
|
Guardar cambios
|
|
</UButton>
|
|
</div>
|
|
|
|
<!-- Botones de import/export -->
|
|
<div class="flex gap-2">
|
|
<UButton
|
|
color="neutral"
|
|
variant="outline"
|
|
icon="i-lucide-download"
|
|
@click="handleExportTheme"
|
|
class="flex-1"
|
|
>
|
|
Exportar tema
|
|
</UButton>
|
|
<UButton
|
|
color="neutral"
|
|
variant="outline"
|
|
icon="i-lucide-upload"
|
|
@click="showImportModal = true"
|
|
class="flex-1"
|
|
>
|
|
Importar tema
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
|
|
<!-- Modal de Importar Tema -->
|
|
<UModal v-model="showImportModal" title="Importar Tema">
|
|
<div class="p-4 space-y-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-[var(--brand-text)] mb-2">
|
|
Pega el JSON del tema
|
|
</label>
|
|
<UTextarea
|
|
v-model="importJsonInput"
|
|
:rows="10"
|
|
placeholder='{\n "bg": "var(--brand-bg)",\n "surface": "#1f180f",\n ...\n}'
|
|
class="font-mono text-xs"
|
|
/>
|
|
</div>
|
|
<div class="flex justify-end gap-2">
|
|
<UButton
|
|
color="neutral"
|
|
variant="ghost"
|
|
@click="showImportModal = false"
|
|
>
|
|
Cancelar
|
|
</UButton>
|
|
<UButton
|
|
color="primary"
|
|
@click="handleImportTheme"
|
|
>
|
|
Importar
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
</UModal>
|
|
|
|
<!-- Vista previa de colores -->
|
|
<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">
|
|
<UIcon name="i-lucide-eye" class="size-5 text-[var(--brand-primary)]" />
|
|
<h3 class="font-semibold text-[var(--brand-text)]">
|
|
Vista Previa
|
|
</h3>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div class="space-y-2">
|
|
<div class="h-20 rounded-lg border-2 border-[var(--brand-border)]" :style="{ backgroundColor: theme.bg }" />
|
|
<p class="text-xs text-center text-[var(--brand-text-muted)]">Fondo Principal</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<div class="h-20 rounded-lg border-2 border-[var(--brand-border)]" :style="{ backgroundColor: theme.surface }" />
|
|
<p class="text-xs text-center text-[var(--brand-text-muted)]">Surface</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<div class="h-20 rounded-lg border-2 border-[var(--brand-border)]" :style="{ backgroundColor: theme.primary }" />
|
|
<p class="text-xs text-center text-[var(--brand-text-muted)]">Primario</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<div class="h-20 rounded-lg border-2 border-[var(--brand-border)]" :style="{ backgroundColor: theme.accent }" />
|
|
<p class="text-xs text-center text-[var(--brand-text-muted)]">Acento</p>
|
|
</div>
|
|
</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
|
|
: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-primary)]/20 flex items-center justify-center">
|
|
<UIcon name="i-lucide-bell" class="size-5 text-[var(--brand-accent)]" />
|
|
</div>
|
|
<h3 class="font-semibold text-[var(--brand-text)]">
|
|
Notificaciones
|
|
</h3>
|
|
</div>
|
|
</template>
|
|
<p class="text-sm text-[var(--brand-text-muted)]">
|
|
Gestión de alertas y comunicaciones (Próximamente)
|
|
</p>
|
|
</UCard>
|
|
|
|
<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-primary)]/20 flex items-center justify-center">
|
|
<UIcon name="i-lucide-shield" class="size-5 text-[var(--brand-accent)]" />
|
|
</div>
|
|
<h3 class="font-semibold text-[var(--brand-text)]">
|
|
Privacidad
|
|
</h3>
|
|
</div>
|
|
</template>
|
|
<p class="text-sm text-[var(--brand-text-muted)]">
|
|
Control de datos y seguridad (Próximamente)
|
|
</p>
|
|
</UCard>
|
|
</div>
|
|
</div>
|
|
</UDashboardPanelContent>
|
|
</UDashboardPanel>
|
|
</UDashboardLayout>
|
|
</template>
|