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:
443
_planificacion/01-design-system/08-PATRONES-FORMULARIOS.md
Normal file
443
_planificacion/01-design-system/08-PATRONES-FORMULARIOS.md
Normal file
@@ -0,0 +1,443 @@
|
||||
# 📝 PATRONES DE FORMULARIOS
|
||||
|
||||
## 1. Form Switch (Checkbox Toggle)
|
||||
|
||||
```html
|
||||
<div class="mb-2">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="enabled" checked>
|
||||
<label class="form-check-label small" for="enabled" style="color: #495057;">
|
||||
<i class="bi bi-toggle-on me-1" style="color: #FF8600;"></i>
|
||||
<strong>Activar Top Bar</strong>
|
||||
<span class="text-muted">(Mostrar en el sitio)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Uso:** Activación/desactivación de features
|
||||
|
||||
**CSS necesario (Fix WordPress):**
|
||||
```css
|
||||
/* Eliminar pseudo-elementos de WordPress */
|
||||
body .form-switch .form-check-input[type="checkbox"]::before,
|
||||
body .form-switch .form-check-input[type="checkbox"]::after {
|
||||
content: none !important;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
body .form-switch .form-check-input[type="checkbox"] {
|
||||
background-size: contain !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-position: left center !important;
|
||||
}
|
||||
|
||||
body .form-switch .form-check-input[type="checkbox"]:checked {
|
||||
background-position: right center !important;
|
||||
}
|
||||
|
||||
/* Fix alineación vertical */
|
||||
.form-check.form-switch {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
}
|
||||
|
||||
.form-switch .form-check-input {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.form-switch .form-check-label {
|
||||
line-height: 16px !important;
|
||||
padding-top: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Color Picker
|
||||
|
||||
```html
|
||||
<div class="col-6">
|
||||
<label for="bgColor" class="form-label small mb-1 fw-semibold" style="color: #495057;">
|
||||
<i class="bi bi-paint-bucket me-1" style="color: #FF8600;"></i>
|
||||
Color de Fondo
|
||||
</label>
|
||||
<input type="color" id="bgColor"
|
||||
class="form-control form-control-color w-100"
|
||||
value="#0E2337"
|
||||
title="Seleccionar color de fondo">
|
||||
<small class="text-muted d-block mt-1" id="bgColorValue">#0E2337</small>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Características:**
|
||||
- Grid de 2 columnas (`col-6`)
|
||||
- Display del valor hex debajo
|
||||
- Width 100% (`.w-100`)
|
||||
|
||||
**JavaScript:**
|
||||
```javascript
|
||||
const colorInput = document.getElementById('bgColor');
|
||||
const colorValue = document.getElementById('bgColorValue');
|
||||
|
||||
colorInput.addEventListener('input', function() {
|
||||
colorValue.textContent = this.value.toUpperCase();
|
||||
updatePreview();
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Text Input con Icono
|
||||
|
||||
```html
|
||||
<div class="mb-2">
|
||||
<label for="highlightText" class="form-label small mb-1 fw-semibold" style="color: #495057;">
|
||||
<i class="bi bi-chat-text me-1" style="color: #FF8600;"></i>
|
||||
Texto Destacado
|
||||
<span class="text-danger">*</span> <!-- Si es requerido -->
|
||||
</label>
|
||||
<input type="text" id="highlightText"
|
||||
class="form-control form-control-sm"
|
||||
placeholder="Ej: Nuevo:"
|
||||
value="Nuevo:"
|
||||
maxlength="50">
|
||||
</div>
|
||||
```
|
||||
|
||||
**Uso:** Campos de texto cortos (nombres, títulos, etc.)
|
||||
|
||||
---
|
||||
|
||||
## 4. Textarea con Contador y Progress Bar
|
||||
|
||||
```html
|
||||
<div class="mb-2">
|
||||
<label for="messageText" class="form-label small mb-1 fw-semibold" style="color: #495057;">
|
||||
<i class="bi bi-chat-left-text me-1" style="color: #FF8600;"></i>
|
||||
Mensaje Principal <span class="text-danger">*</span>
|
||||
<span class="float-end text-muted">
|
||||
<span id="messageTextCount" class="fw-bold">0</span>/250
|
||||
</span>
|
||||
</label>
|
||||
<textarea id="messageText"
|
||||
class="form-control form-control-sm"
|
||||
rows="2"
|
||||
maxlength="250"
|
||||
placeholder="Ej: Accede a más de 200,000 APUs actualizados"
|
||||
required></textarea>
|
||||
<div class="progress mt-1" style="height: 3px;">
|
||||
<div id="messageTextProgress"
|
||||
class="progress-bar"
|
||||
role="progressbar"
|
||||
style="width: 0%; background-color: #FF8600;"
|
||||
aria-valuenow="0"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="250"></div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**JavaScript:**
|
||||
```javascript
|
||||
const textarea = document.getElementById('messageText');
|
||||
const counter = document.getElementById('messageTextCount');
|
||||
const progress = document.getElementById('messageTextProgress');
|
||||
|
||||
textarea.addEventListener('input', function() {
|
||||
const length = this.value.length;
|
||||
const maxLength = 250;
|
||||
const percentage = (length / maxLength) * 100;
|
||||
|
||||
counter.textContent = length;
|
||||
progress.style.width = percentage + '%';
|
||||
progress.setAttribute('aria-valuenow', length);
|
||||
|
||||
// Cambiar color según el uso
|
||||
if (percentage > 90) {
|
||||
progress.style.backgroundColor = '#dc3545'; // Rojo
|
||||
} else if (percentage > 75) {
|
||||
progress.style.backgroundColor = '#ffc107'; // Amarillo
|
||||
} else {
|
||||
progress.style.backgroundColor = '#FF8600'; // Orange
|
||||
}
|
||||
|
||||
updatePreview();
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Select Dropdown
|
||||
|
||||
```html
|
||||
<div class="mb-2">
|
||||
<label for="fontSize" class="form-label small mb-1 fw-semibold" style="color: #495057;">
|
||||
<i class="bi bi-fonts me-1" style="color: #FF8600;"></i>
|
||||
Tamaño de Fuente
|
||||
</label>
|
||||
<select id="fontSize" class="form-select form-select-sm">
|
||||
<option value="small">Pequeño (0.875rem)</option>
|
||||
<option value="normal" selected>Normal (1rem)</option>
|
||||
<option value="large">Grande (1.125rem)</option>
|
||||
</select>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Uso:** Opciones predefinidas (tamaños, estilos, etc.)
|
||||
|
||||
---
|
||||
|
||||
## 6. Badges Informativos
|
||||
|
||||
### Badge en Label
|
||||
|
||||
```html
|
||||
<label class="form-label small mb-1 fw-semibold">
|
||||
<i class="bi bi-code me-1" style="color: #FF8600;"></i>
|
||||
Clase del Icono
|
||||
<span class="badge bg-secondary" style="font-size: 0.65rem;">Bootstrap Icons</span>
|
||||
</label>
|
||||
```
|
||||
|
||||
### Badge Standalone
|
||||
|
||||
```html
|
||||
<!-- Opcional -->
|
||||
<span class="badge text-dark" style="background-color: #FFB800; font-size: 0.65rem;">
|
||||
Opcional
|
||||
</span>
|
||||
|
||||
<!-- Info -->
|
||||
<span class="badge bg-secondary" style="font-size: 0.65rem;">
|
||||
Info
|
||||
</span>
|
||||
|
||||
<!-- Requerido -->
|
||||
<span class="badge bg-danger" style="font-size: 0.65rem;">
|
||||
Requerido
|
||||
</span>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Links de Ayuda
|
||||
|
||||
```html
|
||||
<small class="text-muted d-block mt-1">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
Ver: <a href="https://icons.getbootstrap.com/" target="_blank"
|
||||
class="text-decoration-none" style="color: #FF8600;">
|
||||
Bootstrap Icons <i class="bi bi-box-arrow-up-right"></i>
|
||||
</a>
|
||||
</small>
|
||||
```
|
||||
|
||||
**Características:**
|
||||
- Icono de info
|
||||
- Link orange con hover
|
||||
- Icono de "abrir en nueva ventana"
|
||||
- `target="_blank"` para abrir en pestaña nueva
|
||||
|
||||
---
|
||||
|
||||
## 8. Grid de Inputs Compactos
|
||||
|
||||
### 2 Columnas Iguales
|
||||
|
||||
```html
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-6">
|
||||
<label for="bgColor" class="form-label small mb-1 fw-semibold" style="color: #495057;">
|
||||
<i class="bi bi-paint-bucket me-1" style="color: #FF8600;"></i>
|
||||
Color Fondo
|
||||
</label>
|
||||
<input type="color" id="bgColor"
|
||||
class="form-control form-control-color w-100"
|
||||
value="#0E2337">
|
||||
<small class="text-muted d-block mt-1" id="bgColorValue">#0E2337</small>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="textColor" class="form-label small mb-1 fw-semibold" style="color: #495057;">
|
||||
<i class="bi bi-fonts me-1" style="color: #FF8600;"></i>
|
||||
Color Texto
|
||||
</label>
|
||||
<input type="color" id="textColor"
|
||||
class="form-control form-control-color w-100"
|
||||
value="#ffffff">
|
||||
<small class="text-muted d-block mt-1" id="textColorValue">#FFFFFF</small>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 3 Columnas Desiguales
|
||||
|
||||
```html
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-5">
|
||||
<label class="form-label small mb-1 fw-semibold">Campo 1</label>
|
||||
<input type="text" class="form-control form-control-sm">
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<label class="form-label small mb-1 fw-semibold">Campo 2</label>
|
||||
<input type="text" class="form-control form-control-sm">
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<label class="form-label small mb-1 fw-semibold">Icono</label>
|
||||
<input type="text" class="form-control form-control-sm">
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Campo de URL
|
||||
|
||||
```html
|
||||
<div class="mb-2">
|
||||
<label for="linkUrl" class="form-label small mb-1 fw-semibold" style="color: #495057;">
|
||||
<i class="bi bi-link-45deg me-1" style="color: #FF8600;"></i>
|
||||
URL del Enlace
|
||||
</label>
|
||||
<input type="url" id="linkUrl"
|
||||
class="form-control form-control-sm"
|
||||
placeholder="https://ejemplo.com"
|
||||
value="/catalogo">
|
||||
<small class="text-muted d-block mt-1">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
Usa rutas relativas (/) o absolutas (https://)
|
||||
</small>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Campos Relacionados (Link)
|
||||
|
||||
```html
|
||||
<!-- Switch para mostrar/ocultar link -->
|
||||
<div class="mb-2">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="showLink" checked>
|
||||
<label class="form-check-label small" for="showLink" style="color: #495057;">
|
||||
<i class="bi bi-link me-1" style="color: #FF8600;"></i>
|
||||
<strong>Mostrar Enlace</strong>
|
||||
<span class="text-muted">(Call-to-action)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Campos del link (se muestran/ocultan según el switch) -->
|
||||
<div id="linkFields">
|
||||
<!-- Texto del link -->
|
||||
<div class="mb-2">
|
||||
<label for="linkText" class="form-label small mb-1 fw-semibold" style="color: #495057;">
|
||||
<i class="bi bi-chat-text me-1" style="color: #FF8600;"></i>
|
||||
Texto del Enlace
|
||||
</label>
|
||||
<input type="text" id="linkText"
|
||||
class="form-control form-control-sm"
|
||||
placeholder="Ej: Ver Catálogo →"
|
||||
value="Ver Catálogo →"
|
||||
maxlength="50">
|
||||
</div>
|
||||
|
||||
<!-- URL del link -->
|
||||
<div class="mb-2">
|
||||
<label for="linkUrl" class="form-label small mb-1 fw-semibold" style="color: #495057;">
|
||||
<i class="bi bi-link-45deg me-1" style="color: #FF8600;"></i>
|
||||
URL del Enlace
|
||||
</label>
|
||||
<input type="url" id="linkUrl"
|
||||
class="form-control form-control-sm"
|
||||
placeholder="https://ejemplo.com"
|
||||
value="/catalogo">
|
||||
</div>
|
||||
|
||||
<!-- Target del link -->
|
||||
<div class="mb-2">
|
||||
<label for="linkTarget" class="form-label small mb-1 fw-semibold" style="color: #495057;">
|
||||
<i class="bi bi-box-arrow-up-right me-1" style="color: #FF8600;"></i>
|
||||
Abrir En
|
||||
</label>
|
||||
<select id="linkTarget" class="form-select form-select-sm">
|
||||
<option value="_self" selected>Misma ventana (_self)</option>
|
||||
<option value="_blank">Nueva pestaña (_blank)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**JavaScript para mostrar/ocultar:**
|
||||
```javascript
|
||||
const showLink = document.getElementById('showLink');
|
||||
const linkFields = document.getElementById('linkFields');
|
||||
|
||||
showLink.addEventListener('change', function() {
|
||||
linkFields.style.display = this.checked ? 'block' : 'none';
|
||||
updatePreview();
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Validación de Campos
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* Valida los campos del formulario
|
||||
*/
|
||||
function validateForm() {
|
||||
let isValid = true;
|
||||
const errors = [];
|
||||
|
||||
// Validar campo requerido
|
||||
const messageText = document.getElementById('messageText').value.trim();
|
||||
if (!messageText) {
|
||||
errors.push('El mensaje principal es requerido');
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// Validar longitud
|
||||
if (messageText.length > 250) {
|
||||
errors.push('El mensaje no puede exceder 250 caracteres');
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// Validar URL
|
||||
const linkUrl = document.getElementById('linkUrl').value.trim();
|
||||
if (linkUrl && !isValidUrl(linkUrl)) {
|
||||
errors.push('La URL no es válida');
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
alert('⚠️ Errores de validación:\n\n' + errors.join('\n'));
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function isValidUrl(string) {
|
||||
// Permitir rutas relativas
|
||||
if (string.startsWith('/')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Validar URLs absolutas
|
||||
try {
|
||||
new URL(string);
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Volver al Índice
|
||||
|
||||
[← Volver al README](README.md)
|
||||
Reference in New Issue
Block a user