refactor: reorganizar openspec y planificacion con spec recaptcha
- renombrar openspec/ a _openspec/ (carpeta auxiliar) - mover specs de features a changes/ - crear specs base: arquitectura-limpia, estandares-codigo, nomenclatura - migrar _planificacion/ con design-system y roi-theme-template - agregar especificacion recaptcha anti-spam (proposal, tasks, spec) - corregir rutas y referencias en todas las specs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
360
_planificacion/01-design-system/09-VISTA-PREVIA-TIEMPO-REAL.md
Normal file
360
_planificacion/01-design-system/09-VISTA-PREVIA-TIEMPO-REAL.md
Normal file
@@ -0,0 +1,360 @@
|
||||
# 👁️ VISTA PREVIA EN TIEMPO REAL
|
||||
|
||||
## Estructura HTML del Preview
|
||||
|
||||
```html
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm mb-3" style="border-left: 4px solid #FF8600;">
|
||||
<div class="card-body">
|
||||
<h5 class="fw-bold mb-3" style="color: #1e3a5f;">
|
||||
<i class="bi bi-eye me-2" style="color: #FF8600;"></i>
|
||||
Vista Previa en Tiempo Real
|
||||
</h5>
|
||||
|
||||
<!-- IMPORTANTE: Usar las MISMAS clases que el componente real -->
|
||||
<div id="componentPreview" class="[clases-del-componente-real]">
|
||||
<!-- HTML IDÉNTICO al del front-end -->
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mt-3">
|
||||
<small class="text-muted">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
Los cambios se reflejan en tiempo real
|
||||
</small>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button type="button" class="btn btn-outline-secondary active" id="previewDesktop">
|
||||
<i class="bi bi-display"></i> Desktop
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" id="previewMobile">
|
||||
<i class="bi bi-phone"></i> Mobile
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Características clave:**
|
||||
- ✅ Border-left ORANGE (#FF8600) - NO navy
|
||||
- ✅ Clases IDÉNTICAS al componente del front-end
|
||||
- ✅ HTML IDÉNTICO al front-end
|
||||
- ✅ Botones Desktop/Mobile para cambiar el ancho
|
||||
|
||||
---
|
||||
|
||||
## Reglas Críticas para Vista Previa
|
||||
|
||||
### ❌ LO QUE NO DEBES HACER
|
||||
|
||||
#### 1. NO usar inline styles que sobreescriban el CSS real
|
||||
|
||||
```html
|
||||
<!-- ❌ MAL: Inline styles que sobreescriben el CSS real -->
|
||||
<div id="preview" class="component" style="padding: 10px; color: blue;">
|
||||
<!-- Esto NO se verá igual al front-end -->
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 2. NO crear CSS específico para el preview que no existe en el front-end
|
||||
|
||||
```css
|
||||
/* ❌ MAL: CSS específico para el preview que no existe en el front-end */
|
||||
#componentPreview {
|
||||
padding: 20px;
|
||||
font-size: 16px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. NO modificar la estructura HTML del componente
|
||||
|
||||
```html
|
||||
<!-- ❌ MAL: HTML diferente al front-end -->
|
||||
<div id="preview" class="my-custom-wrapper">
|
||||
<div class="component">
|
||||
<!-- Estructura diferente -->
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ✅ LO QUE DEBES HACER
|
||||
|
||||
#### 1. Usar EXACTAMENTE las mismas clases que el front-end
|
||||
|
||||
```html
|
||||
<!-- ✅ BIEN: Usar EXACTAMENTE las mismas clases que el front-end -->
|
||||
<div id="topBarPreview" class="top-notification-bar">
|
||||
<div class="container">
|
||||
<div class="notification-content">
|
||||
<!-- Estructura IDÉNTICA al front-end -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 2. Cargar el CSS del front-end en el admin
|
||||
|
||||
```html
|
||||
<!-- ✅ BIEN: Cargar el CSS real del front-end -->
|
||||
<link rel="stylesheet" href="../../Css/style.css">
|
||||
```
|
||||
|
||||
#### 3. Solo aplicar estilos si es ABSOLUTAMENTE necesario con !important
|
||||
|
||||
```css
|
||||
/* ✅ BIEN: Solo si el CSS del front-end no se aplica correctamente */
|
||||
#componentPreview.top-notification-bar {
|
||||
/* Solo agregar si es necesario para el contexto del admin */
|
||||
border: 1px solid #e9ecef; /* Border para debugging visual */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ejemplo Completo: Top Bar Preview
|
||||
|
||||
### HTML del Front-end (Original)
|
||||
|
||||
```html
|
||||
<div class="top-notification-bar">
|
||||
<div class="container">
|
||||
<div class="notification-content">
|
||||
<i class="bi bi-megaphone-fill notification-icon"></i>
|
||||
<span class="notification-text">
|
||||
<strong class="notification-highlight">Nuevo:</strong>
|
||||
Accede a más de 200,000 APUs actualizados.
|
||||
</span>
|
||||
<a href="/catalogo" class="notification-link">
|
||||
Ver Catálogo →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### HTML del Preview (Admin) ✅ CORRECTO
|
||||
|
||||
```html
|
||||
<!-- ✅ IDÉNTICO al front-end -->
|
||||
<div id="topBarPreview" class="top-notification-bar">
|
||||
<div class="container">
|
||||
<div class="notification-content">
|
||||
<i class="bi bi-megaphone-fill notification-icon" id="previewIcon"></i>
|
||||
<span class="notification-text">
|
||||
<strong class="notification-highlight" id="previewHighlight">Nuevo:</strong>
|
||||
<span id="previewMessage">Accede a más de 200,000 APUs actualizados.</span>
|
||||
</span>
|
||||
<a href="/catalogo" class="notification-link" id="previewLink">
|
||||
Ver Catálogo →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Diferencias permitidas:**
|
||||
- ✅ IDs agregados para manipulación con JavaScript (`id="previewIcon"`, `id="previewMessage"`, etc.)
|
||||
- ✅ Clases CSS IDÉNTICAS al front-end
|
||||
- ✅ Estructura HTML IDÉNTICA
|
||||
|
||||
---
|
||||
|
||||
## CSS para Vista Previa
|
||||
|
||||
### Principio: NO sobreescribir estilos del front-end
|
||||
|
||||
```css
|
||||
/* REGLA DE ORO: NO sobreescribir estilos del front-end */
|
||||
/* Solo agregar si es absolutamente necesario */
|
||||
|
||||
/* ✅ Permitido: Border para distinguir visualmente el preview en el admin */
|
||||
#topBarPreview {
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
/* ❌ NO permitido: Sobreescribir propiedades del componente */
|
||||
#topBarPreview {
|
||||
padding: 20px !important; /* ❌ Esto hará que no se vea igual */
|
||||
font-size: 18px !important; /* ❌ Esto hará que no se vea igual */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## JavaScript para updatePreview()
|
||||
|
||||
### Patrón Básico
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* Actualiza la vista previa en tiempo real
|
||||
*/
|
||||
function updatePreview() {
|
||||
const preview = document.getElementById('topBarPreview');
|
||||
if (!preview) return;
|
||||
|
||||
// REGLA: Solo modificar propiedades que el usuario puede cambiar
|
||||
// NO modificar padding, margins, o estructura del HTML
|
||||
|
||||
// 1. Actualizar colores
|
||||
const bgColor = document.getElementById('bgColor').value;
|
||||
const textColor = document.getElementById('textColor').value;
|
||||
preview.style.backgroundColor = bgColor;
|
||||
preview.style.color = textColor;
|
||||
|
||||
// 2. Actualizar texto
|
||||
const highlightText = document.getElementById('highlightText').value;
|
||||
const messageText = document.getElementById('messageText').value;
|
||||
document.getElementById('previewHighlight').textContent = highlightText;
|
||||
document.getElementById('previewMessage').textContent = messageText;
|
||||
|
||||
// 3. Actualizar link
|
||||
const showLink = document.getElementById('showLink').checked;
|
||||
const linkElement = document.getElementById('previewLink');
|
||||
linkElement.style.display = showLink ? 'inline-block' : 'none';
|
||||
|
||||
if (showLink) {
|
||||
const linkText = document.getElementById('linkText').value;
|
||||
const linkUrl = document.getElementById('linkUrl').value;
|
||||
const linkTarget = document.getElementById('linkTarget').value;
|
||||
linkElement.textContent = linkText;
|
||||
linkElement.href = linkUrl;
|
||||
linkElement.target = linkTarget;
|
||||
}
|
||||
|
||||
// 4. Mostrar/ocultar icono
|
||||
const showIcon = document.getElementById('showIcon').checked;
|
||||
const iconElement = document.getElementById('previewIcon');
|
||||
iconElement.style.display = showIcon ? 'inline-block' : 'none';
|
||||
|
||||
// 5. Cambiar clase del icono
|
||||
const iconClass = document.getElementById('iconClass').value;
|
||||
iconElement.className = iconClass + ' notification-icon';
|
||||
}
|
||||
```
|
||||
|
||||
### Conectar updatePreview() a Todos los Campos
|
||||
|
||||
```javascript
|
||||
function initializeEventListeners() {
|
||||
// Lista de campos que deben actualizar el preview
|
||||
const fields = [
|
||||
'bgColor',
|
||||
'textColor',
|
||||
'highlightColor',
|
||||
'highlightText',
|
||||
'messageText',
|
||||
'showLink',
|
||||
'linkText',
|
||||
'linkUrl',
|
||||
'linkTarget',
|
||||
'showIcon',
|
||||
'iconClass',
|
||||
'fontSize'
|
||||
];
|
||||
|
||||
// Conectar event listeners
|
||||
fields.forEach(fieldId => {
|
||||
const element = document.getElementById(fieldId);
|
||||
if (element) {
|
||||
if (element.type === 'checkbox') {
|
||||
element.addEventListener('change', updatePreview);
|
||||
} else {
|
||||
element.addEventListener('input', updatePreview);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Botones Desktop/Mobile
|
||||
|
||||
### HTML
|
||||
|
||||
```html
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button type="button" class="btn btn-outline-secondary active" id="previewDesktop">
|
||||
<i class="bi bi-display"></i> Desktop
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" id="previewMobile">
|
||||
<i class="bi bi-phone"></i> Mobile
|
||||
</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
### JavaScript
|
||||
|
||||
```javascript
|
||||
const btnDesktop = document.getElementById('previewDesktop');
|
||||
const btnMobile = document.getElementById('previewMobile');
|
||||
const preview = document.getElementById('topBarPreview');
|
||||
|
||||
btnDesktop.addEventListener('click', function() {
|
||||
// Activar botón
|
||||
this.classList.add('active');
|
||||
btnMobile.classList.remove('active');
|
||||
|
||||
// Cambiar ancho del preview
|
||||
preview.style.maxWidth = '100%';
|
||||
preview.style.margin = '0';
|
||||
});
|
||||
|
||||
btnMobile.addEventListener('click', function() {
|
||||
// Activar botón
|
||||
this.classList.add('active');
|
||||
btnDesktop.classList.remove('active');
|
||||
|
||||
// Cambiar ancho del preview (simular mobile)
|
||||
preview.style.maxWidth = '375px';
|
||||
preview.style.margin = '0 auto';
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checklist de Vista Previa
|
||||
|
||||
Antes de considerar completa la vista previa, verificar:
|
||||
|
||||
- [ ] HTML del preview es IDÉNTICO al front-end
|
||||
- [ ] Se usan las MISMAS clases CSS que el componente real
|
||||
- [ ] Se carga el archivo CSS del front-end (`../../Css/style.css`)
|
||||
- [ ] NO hay inline styles que sobreescriban propiedades del componente
|
||||
- [ ] La función `updatePreview()` está conectada a todos los campos
|
||||
- [ ] Los botones Desktop/Mobile funcionan correctamente
|
||||
- [ ] El preview se ve IDÉNTICO al componente en el sitio real
|
||||
|
||||
---
|
||||
|
||||
## Debugging de Vista Previa
|
||||
|
||||
### Problema: El preview no se ve igual al front-end
|
||||
|
||||
**Solución:**
|
||||
|
||||
1. Abrir DevTools (F12)
|
||||
2. Inspeccionar el elemento del preview
|
||||
3. Verificar que se cargan los estilos correctos:
|
||||
|
||||
```
|
||||
Computed Styles →
|
||||
padding: 0.5rem 0 (debe venir de style.css)
|
||||
background-color: rgb(14, 35, 55) (debe venir del inline style del preview)
|
||||
```
|
||||
|
||||
4. Si hay estilos incorrectos:
|
||||
- Verificar que `style.css` esté cargado
|
||||
- Verificar que las clases CSS sean idénticas
|
||||
- Verificar que no haya inline styles conflictivos
|
||||
|
||||
---
|
||||
|
||||
## Volver al Índice
|
||||
|
||||
[← Volver al README](README.md)
|
||||
Reference in New Issue
Block a user