Feat: Agregar botones de Copiar Texto y Copiar JSON
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 47s

Implementa funcionalidad de copia en tres secciones del Informe:

📋 Funcionalidades agregadas:
1. Lista de Ingresos
   - Copiar Texto: Formato WhatsApp con emojis y legible
   - Copiar JSON: Formato estructurado para sistemas

2. Top 10 Clientes
   - Copiar Texto: Ranking formateado con métricas
   - Copiar JSON: Array de objetos con datos completos

3. Serie Temporal Acumulada
   - Copiar Texto: Evolución temporal con emojis
   - Copiar JSON: Datos completos para análisis

 Características:
- Botones con iconos (i-lucide-copy y i-lucide-code)
- Disabled cuando no hay datos disponibles
- Alertas de confirmación al copiar
- Formato texto optimizado para WhatsApp
- Incluye metadata: rango de fechas y timestamp

Uso:
- Copiar Texto → Compartir en WhatsApp/Telegram
- Copiar JSON → Integración con otros sistemas
This commit is contained in:
2025-10-30 16:33:54 -06:00
parent 507fb9ba1c
commit 63c7043664
10 changed files with 1143 additions and 134 deletions

View File

@@ -0,0 +1,419 @@
# 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