Todos los componentes del NIVEL 2 ya están implementados correctamente: - ✅ Notification Bar (#49) - ✅ Navbar (#50) - ✅ Hero Section (#51) - ✅ Sidebar (#52) - ✅ Footer (#53) Solo se actualizó notification-bar.css para usar variables CSS. Próximo paso: NIVEL 3 (Refinamientos visuales) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
997 lines
23 KiB
Markdown
997 lines
23 KiB
Markdown
# GAP Implementation - Code Snippets Ready to Use
|
|
|
|
**Quick Copy-Paste Reference**
|
|
**Fecha:** 2025-11-04
|
|
|
|
---
|
|
|
|
## Issue #41: TOC Sticky con ScrollSpy
|
|
|
|
### Archivo: `assets/css/toc.css`
|
|
|
|
**Agregar al final del archivo:**
|
|
|
|
```css
|
|
/* ==========================================================================
|
|
TOC STICKY + SCROLLSPY (Issue #41)
|
|
========================================================================== */
|
|
|
|
/* Contenedor Sticky */
|
|
.apus-toc {
|
|
position: sticky;
|
|
top: 5.5rem; /* Offset debajo del navbar */
|
|
max-height: calc(100vh - 6rem);
|
|
overflow-y: auto;
|
|
z-index: 100;
|
|
}
|
|
|
|
/* Scrollbar Personalizado - Chrome/Safari/Edge */
|
|
.apus-toc::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
.apus-toc::-webkit-scrollbar-track {
|
|
background: #f1f3f4;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.apus-toc::-webkit-scrollbar-thumb {
|
|
background: #cbd5e0;
|
|
border-radius: 3px;
|
|
transition: background 0.3s ease;
|
|
}
|
|
|
|
.apus-toc::-webkit-scrollbar-thumb:hover {
|
|
background: #a0aec0;
|
|
}
|
|
|
|
/* Scrollbar Personalizado - Firefox */
|
|
.apus-toc {
|
|
scrollbar-width: thin;
|
|
scrollbar-color: #cbd5e0 #f1f3f4;
|
|
}
|
|
|
|
/* Active Link Highlighting */
|
|
.apus-toc-link.active {
|
|
color: #1a73e8;
|
|
font-weight: 700;
|
|
background: rgba(26, 115, 232, 0.1);
|
|
border-left: 3px solid #1a73e8;
|
|
padding-left: calc(0.5rem - 3px); /* Compensar border */
|
|
}
|
|
|
|
/* Smooth Transition para Active State */
|
|
.apus-toc-link {
|
|
transition: all 0.3s ease;
|
|
padding-left: 0.5rem;
|
|
}
|
|
|
|
/* Mobile: Reducir max-height */
|
|
@media (max-width: 768px) {
|
|
.apus-toc {
|
|
position: relative; /* No sticky en mobile */
|
|
max-height: 400px;
|
|
top: auto;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Archivo: `assets/js/toc.js`
|
|
|
|
**Agregar al final del archivo, antes del cierre de función:**
|
|
|
|
```javascript
|
|
/**
|
|
* ScrollSpy para TOC
|
|
* Resalta automáticamente el heading activo basado en scroll position
|
|
* Issue #41
|
|
*/
|
|
function initTOCScrollSpy() {
|
|
const tocLinks = document.querySelectorAll('.apus-toc-link');
|
|
|
|
if (tocLinks.length === 0) {
|
|
return; // No hay TOC en esta página
|
|
}
|
|
|
|
// Configurar IntersectionObserver
|
|
const observerOptions = {
|
|
rootMargin: '-20% 0px -35% 0px', // Activa cuando el heading está en el 20%-65% superior de la pantalla
|
|
threshold: 0
|
|
};
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
const id = entry.target.getAttribute('id');
|
|
const tocLink = document.querySelector(`.apus-toc-link[href="#${id}"]`);
|
|
|
|
if (entry.isIntersecting && tocLink) {
|
|
// Remover active de todos los links
|
|
tocLinks.forEach(link => link.classList.remove('active'));
|
|
|
|
// Agregar active al link actual
|
|
tocLink.classList.add('active');
|
|
|
|
// Scroll suave del TOC para mantener link visible
|
|
tocLink.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'nearest',
|
|
inline: 'nearest'
|
|
});
|
|
}
|
|
});
|
|
}, observerOptions);
|
|
|
|
// Observar todos los headings que tienen ID
|
|
tocLinks.forEach(link => {
|
|
const href = link.getAttribute('href');
|
|
if (href && href.startsWith('#')) {
|
|
const heading = document.querySelector(href);
|
|
if (heading) {
|
|
observer.observe(heading);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Cleanup al salir de la página
|
|
window.addEventListener('beforeunload', () => {
|
|
observer.disconnect();
|
|
});
|
|
}
|
|
|
|
// Inicializar cuando el DOM esté listo
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', initTOCScrollSpy);
|
|
} else {
|
|
initTOCScrollSpy();
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Issue #42: Navbar Underline Hover Animado
|
|
|
|
### Archivo: `assets/css/header.css`
|
|
|
|
**Encontrar la sección de `.navbar-nav .nav-link` y agregar:**
|
|
|
|
```css
|
|
/* ==========================================================================
|
|
NAVBAR UNDERLINE HOVER ANIMADO (Issue #42)
|
|
========================================================================== */
|
|
|
|
/* Desktop Navigation - Underline Effect */
|
|
.navbar-nav .nav-link {
|
|
position: relative;
|
|
padding-bottom: 0.75rem; /* Espacio para underline */
|
|
}
|
|
|
|
/* Underline Pseudo-elemento */
|
|
.navbar-nav .nav-link::after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
width: 0;
|
|
height: 2px;
|
|
background-color: #61c7cd; /* Turquesa RDash */
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
/* Hover State */
|
|
.navbar-nav .nav-link:hover {
|
|
color: #61c7cd;
|
|
background-color: rgba(97, 199, 205, 0.1);
|
|
}
|
|
|
|
.navbar-nav .nav-link:hover::after {
|
|
width: 100%;
|
|
}
|
|
|
|
/* Active/Current Menu Item */
|
|
.navbar-nav .nav-link.active,
|
|
.navbar-nav .current-menu-item > .nav-link,
|
|
.navbar-nav .current_page_item > .nav-link {
|
|
color: #61c7cd;
|
|
}
|
|
|
|
.navbar-nav .nav-link.active::after,
|
|
.navbar-nav .current-menu-item > .nav-link::after,
|
|
.navbar-nav .current_page_item > .nav-link::after {
|
|
width: 100%;
|
|
}
|
|
|
|
/* Focus State (Accesibilidad) */
|
|
.navbar-nav .nav-link:focus {
|
|
color: #61c7cd;
|
|
background-color: rgba(97, 199, 205, 0.1);
|
|
outline: 2px solid #61c7cd;
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.navbar-nav .nav-link:focus::after {
|
|
width: 100%;
|
|
}
|
|
|
|
/* Responsive: Ocultar underline en mobile menu */
|
|
@media (max-width: 767px) {
|
|
.navbar-nav .nav-link::after {
|
|
display: none;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Issue #43: Verificar Colores Notification Bar
|
|
|
|
### Archivo: `assets/css/notification-bar.css`
|
|
|
|
**Reemplazar colores actuales con estos exactos:**
|
|
|
|
```css
|
|
/* ==========================================================================
|
|
NOTIFICATION BAR - COLORES EXACTOS RDASH (Issue #43)
|
|
========================================================================== */
|
|
|
|
.top-notification-bar {
|
|
background-color: #4C5C6B; /* Gris RDash exacto */
|
|
color: #ffffff;
|
|
padding: 0.75rem 1rem;
|
|
font-size: 0.875rem;
|
|
text-align: center;
|
|
position: relative;
|
|
z-index: 1001;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.top-notification-bar p {
|
|
margin: 0;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.top-notification-bar a {
|
|
color: #61c7cd; /* Turquesa hover RDash */
|
|
text-decoration: underline;
|
|
font-weight: 600;
|
|
transition: color 0.3s ease;
|
|
}
|
|
|
|
.top-notification-bar a:hover {
|
|
color: #4fb3b9; /* Turquesa hover oscuro */
|
|
text-decoration: none;
|
|
}
|
|
|
|
.top-notification-bar a:focus {
|
|
outline: 2px solid #61c7cd;
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.notification-close {
|
|
position: absolute;
|
|
right: 1rem;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
background: transparent;
|
|
border: none;
|
|
color: rgba(255, 255, 255, 0.8);
|
|
font-size: 1.25rem;
|
|
cursor: pointer;
|
|
padding: 0.25rem 0.5rem;
|
|
transition: color 0.3s ease;
|
|
line-height: 1;
|
|
}
|
|
|
|
.notification-close:hover {
|
|
color: #ffffff;
|
|
}
|
|
|
|
.notification-close:focus {
|
|
outline: 2px solid #61c7cd;
|
|
outline-offset: 2px;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Issue #44: Botón "Let's Talk" en Header
|
|
|
|
### Archivo: `header.php`
|
|
|
|
**Agregar en el navbar, después de los nav items (buscar `</ul>` del menu):**
|
|
|
|
```php
|
|
<!-- Botón "Let's Talk" CTA (Issue #44) -->
|
|
<?php if ( has_nav_menu( 'primary' ) ) : ?>
|
|
<div class="ms-auto d-none d-lg-block">
|
|
<a href="<?php echo esc_url( get_permalink( get_page_by_path( 'contacto' ) ) ?: '#contacto' ); ?>"
|
|
class="btn btn-lets-talk"
|
|
aria-label="<?php esc_attr_e( 'Contáctanos', 'apus-theme' ); ?>">
|
|
<?php esc_html_e( "Let's Talk", 'apus-theme' ); ?>
|
|
</a>
|
|
</div>
|
|
<?php endif; ?>
|
|
```
|
|
|
|
### Archivo: `assets/css/header.css`
|
|
|
|
**Agregar al final:**
|
|
|
|
```css
|
|
/* ==========================================================================
|
|
BOTÓN "LET'S TALK" CTA (Issue #44)
|
|
========================================================================== */
|
|
|
|
.btn-lets-talk {
|
|
background: linear-gradient(135deg, #FF6B35 0%, #FF8C42 100%);
|
|
color: #ffffff !important;
|
|
padding: 0.875rem 1.75rem;
|
|
border-radius: 8px;
|
|
font-weight: 600;
|
|
font-size: 1rem;
|
|
border: none;
|
|
box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);
|
|
transition: all 0.3s ease;
|
|
text-decoration: none !important;
|
|
display: inline-block;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.btn-lets-talk:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 6px 20px rgba(255, 107, 53, 0.4);
|
|
background: linear-gradient(135deg, #FF5722 0%, #FF7043 100%);
|
|
color: #ffffff !important;
|
|
text-decoration: none !important;
|
|
}
|
|
|
|
.btn-lets-talk:active {
|
|
transform: translateY(0);
|
|
box-shadow: 0 2px 8px rgba(255, 107, 53, 0.3);
|
|
}
|
|
|
|
.btn-lets-talk:focus {
|
|
outline: 2px solid #FF8C42;
|
|
outline-offset: 3px;
|
|
box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);
|
|
}
|
|
|
|
/* Responsive: Ocultar en tablets y móviles */
|
|
@media (max-width: 991px) {
|
|
.btn-lets-talk {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* Opcional: Versión mobile en el menú hamburguesa */
|
|
.mobile-menu .btn-lets-talk-mobile {
|
|
display: block;
|
|
width: 100%;
|
|
margin: 1rem 1.5rem;
|
|
width: calc(100% - 3rem);
|
|
text-align: center;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Issue #45: Related Posts Cards Grises
|
|
|
|
### Archivo: `assets/css/related-posts.css`
|
|
|
|
**Reemplazar la sección `.related-post-card` con:**
|
|
|
|
```css
|
|
/* ==========================================================================
|
|
RELATED POST CARD - DISEÑO GRIS CON BORDE LATERAL (Issue #45)
|
|
========================================================================== */
|
|
|
|
.related-post-card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
background: #f7fafc; /* Gris claro de fondo */
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
position: relative;
|
|
border: 1px solid #e2e8f0;
|
|
}
|
|
|
|
/* Borde lateral izquierdo con gradiente */
|
|
.related-post-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 4px;
|
|
height: 100%;
|
|
background: linear-gradient(180deg, #1e3a5f 0%, #1a73e8 100%);
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
z-index: 10;
|
|
}
|
|
|
|
/* Hover State */
|
|
.related-post-card:hover {
|
|
background: #ffffff; /* Cambiar a blanco en hover */
|
|
border-color: #1a73e8;
|
|
transform: translateY(-8px); /* Más pronunciado */
|
|
box-shadow: 0 12px 32px rgba(26, 115, 232, 0.15);
|
|
}
|
|
|
|
.related-post-card:hover::before {
|
|
opacity: 1; /* Mostrar borde lateral */
|
|
}
|
|
|
|
/* Ajustar padding del contenido para el borde */
|
|
.related-post-content {
|
|
padding: 1.25rem;
|
|
padding-left: calc(1.25rem + 4px); /* Compensar borde */
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
/* Título con transición de color */
|
|
.related-post-title {
|
|
font-size: 1.125rem;
|
|
font-weight: 600;
|
|
color: #212529;
|
|
margin: 0 0 0.75rem 0;
|
|
line-height: 1.4;
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
transition: color 0.3s ease;
|
|
}
|
|
|
|
.related-post-card:hover .related-post-title {
|
|
color: #1a73e8;
|
|
}
|
|
|
|
/* Imagen con zoom sutil */
|
|
.related-post-thumbnail img {
|
|
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
.related-post-card:hover .related-post-thumbnail img {
|
|
transform: scale(1.08); /* Zoom más pronunciado */
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 767.98px) {
|
|
.related-post-card:hover {
|
|
transform: translateY(-4px); /* Menos pronunciado en mobile */
|
|
}
|
|
}
|
|
|
|
/* Reducir movimiento para usuarios que lo prefieren */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.related-post-card,
|
|
.related-post-card::before,
|
|
.related-post-thumbnail img {
|
|
transition: none;
|
|
}
|
|
|
|
.related-post-card:hover {
|
|
transform: none;
|
|
}
|
|
|
|
.related-post-card:hover .related-post-thumbnail img {
|
|
transform: none;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Issue #46: Paginación Profesional
|
|
|
|
### Archivo: `style.css`
|
|
|
|
**Reemplazar la sección de paginación (líneas 437-479) con:**
|
|
|
|
```css
|
|
/* ==========================================================================
|
|
PAGINACIÓN PROFESIONAL (Issue #46)
|
|
========================================================================== */
|
|
|
|
.pagination,
|
|
.posts-pagination {
|
|
margin-top: var(--spacing-xxl);
|
|
margin-bottom: var(--spacing-xxl);
|
|
}
|
|
|
|
.nav-links {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.nav-links .page-numbers {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-width: 44px;
|
|
min-height: 44px;
|
|
padding: 0.5rem 0.75rem;
|
|
background: #ffffff;
|
|
border: 2px solid #e2e8f0; /* Borde más grueso */
|
|
border-radius: 8px; /* Más redondeado */
|
|
color: #4a5568;
|
|
font-weight: 600;
|
|
text-decoration: none;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); /* Curva de animación mejorada */
|
|
}
|
|
|
|
/* Hover State */
|
|
.nav-links .page-numbers:hover {
|
|
background: #1a73e8;
|
|
border-color: #1a73e8;
|
|
color: #ffffff;
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(26, 115, 232, 0.3);
|
|
text-decoration: none;
|
|
}
|
|
|
|
/* Current/Active Page */
|
|
.nav-links .page-numbers.current {
|
|
background: linear-gradient(135deg, #1e3a5f 0%, #2c5282 100%);
|
|
border-color: transparent;
|
|
color: #ffffff;
|
|
box-shadow: 0 4px 12px rgba(30, 58, 95, 0.3);
|
|
cursor: default;
|
|
}
|
|
|
|
/* Dots (ellipsis) */
|
|
.nav-links .page-numbers.dots {
|
|
border: none;
|
|
pointer-events: none;
|
|
color: #cbd5e0;
|
|
cursor: default;
|
|
}
|
|
|
|
/* Prev/Next Arrows */
|
|
.nav-links .page-numbers.prev,
|
|
.nav-links .page-numbers.next {
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* Focus State (Accesibilidad) */
|
|
.nav-links .page-numbers:focus {
|
|
outline: 2px solid #1a73e8;
|
|
outline-offset: 2px;
|
|
box-shadow: 0 0 0 0.2rem rgba(26, 115, 232, 0.25);
|
|
}
|
|
|
|
/* Active State */
|
|
.nav-links .page-numbers:active {
|
|
transform: translateY(0);
|
|
box-shadow: 0 2px 4px rgba(26, 115, 232, 0.2);
|
|
}
|
|
|
|
/* Reducir movimiento para usuarios que lo prefieren */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.nav-links .page-numbers {
|
|
transition: color 0.3s ease, background-color 0.3s ease;
|
|
}
|
|
|
|
.nav-links .page-numbers:hover {
|
|
transform: none;
|
|
}
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 575px) {
|
|
.nav-links .page-numbers {
|
|
min-width: 40px;
|
|
min-height: 40px;
|
|
padding: 0.375rem 0.625rem;
|
|
font-size: 0.875rem;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Issue #47: Modal Contacto Refinamiento
|
|
|
|
### Archivo: `assets/css/modal-contact.css`
|
|
|
|
**Agregar/Reemplazar estilos del modal:**
|
|
|
|
```css
|
|
/* ==========================================================================
|
|
MODAL CONTACTO REFINADO (Issue #47)
|
|
========================================================================== */
|
|
|
|
.contact-modal .modal-content {
|
|
border-radius: 16px; /* Más redondeado */
|
|
border: none;
|
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); /* Sombra más profunda */
|
|
overflow: hidden;
|
|
}
|
|
|
|
.contact-modal .modal-header {
|
|
background: linear-gradient(135deg, #1e3a5f 0%, #2c5282 100%);
|
|
color: #ffffff;
|
|
border-radius: 16px 16px 0 0;
|
|
padding: 1.5rem 2rem;
|
|
border-bottom: none;
|
|
}
|
|
|
|
.contact-modal .modal-title {
|
|
font-size: 1.5rem;
|
|
font-weight: 700;
|
|
color: #ffffff;
|
|
}
|
|
|
|
/* Botón Close Blanco */
|
|
.contact-modal .btn-close {
|
|
filter: brightness(0) invert(1); /* Convertir a blanco */
|
|
opacity: 1;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.contact-modal .btn-close:hover {
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.contact-modal .btn-close:focus {
|
|
outline: 2px solid #ffffff;
|
|
outline-offset: 2px;
|
|
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.25);
|
|
}
|
|
|
|
/* Body del Modal */
|
|
.contact-modal .modal-body {
|
|
padding: 2rem;
|
|
}
|
|
|
|
/* Form Controls */
|
|
.contact-modal .form-control,
|
|
.contact-modal .form-select {
|
|
border-radius: 8px;
|
|
border: 2px solid #e2e8f0;
|
|
padding: 0.75rem 1rem;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.contact-modal .form-control:focus,
|
|
.contact-modal .form-select:focus {
|
|
border-color: #1a73e8;
|
|
box-shadow: 0 0 0 0.25rem rgba(26, 115, 232, 0.15);
|
|
}
|
|
|
|
/* Labels */
|
|
.contact-modal .form-label {
|
|
font-weight: 600;
|
|
color: #2d3748;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
/* Botón Submit */
|
|
.contact-modal .btn-primary {
|
|
background: linear-gradient(135deg, #1e3a5f 0%, #2c5282 100%);
|
|
border: none;
|
|
padding: 0.875rem 2rem;
|
|
font-weight: 600;
|
|
border-radius: 8px;
|
|
transition: all 0.3s ease;
|
|
width: 100%;
|
|
}
|
|
|
|
.contact-modal .btn-primary:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 6px 20px rgba(30, 58, 95, 0.3);
|
|
background: linear-gradient(135deg, #152e4a 0%, #1e3a5f 100%);
|
|
}
|
|
|
|
.contact-modal .btn-primary:active {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.contact-modal .btn-primary:focus {
|
|
box-shadow: 0 0 0 0.25rem rgba(30, 58, 95, 0.25);
|
|
}
|
|
|
|
/* Footer del Modal */
|
|
.contact-modal .modal-footer {
|
|
padding: 1.5rem 2rem;
|
|
border-top: 1px solid #e2e8f0;
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 575px) {
|
|
.contact-modal .modal-body {
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.contact-modal .modal-header {
|
|
padding: 1.25rem 1.5rem;
|
|
}
|
|
|
|
.contact-modal .modal-title {
|
|
font-size: 1.25rem;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Issue #48: Animación Pulse CTA Box (Opcional)
|
|
|
|
### Archivo: `assets/css/cta-box-sidebar.css`
|
|
|
|
**Agregar al final:**
|
|
|
|
```css
|
|
/* ==========================================================================
|
|
ANIMACIÓN PULSE (Issue #48)
|
|
========================================================================== */
|
|
|
|
/* Keyframes de la animación */
|
|
@keyframes pulse {
|
|
0%, 100% {
|
|
box-shadow: 0 4px 12px rgba(255, 134, 0, 0.3);
|
|
transform: scale(1);
|
|
}
|
|
50% {
|
|
box-shadow: 0 6px 20px rgba(255, 134, 0, 0.5);
|
|
transform: scale(1.02);
|
|
}
|
|
}
|
|
|
|
/* Aplicar animación al CTA box */
|
|
.cta-box-sidebar {
|
|
animation: pulse 3s ease-in-out infinite;
|
|
transform-origin: center;
|
|
}
|
|
|
|
/* Detener animación al hacer hover (para no interferir con interacción) */
|
|
.cta-box-sidebar:hover {
|
|
animation: none;
|
|
}
|
|
|
|
/* Respetar preferencia de movimiento reducido */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.cta-box-sidebar {
|
|
animation: none;
|
|
}
|
|
}
|
|
|
|
/* Pausar animación cuando el tab no está activo (performance) */
|
|
@media (prefers-reduced-motion: no-preference) {
|
|
.cta-box-sidebar {
|
|
animation-play-state: running;
|
|
}
|
|
}
|
|
|
|
/* Pausar si el usuario está inactivo (opcional - requiere JS) */
|
|
body.user-inactive .cta-box-sidebar {
|
|
animation-play-state: paused;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Issue #49: Hero Section Padding
|
|
|
|
### Archivo: `assets/css/hero-section.css`
|
|
|
|
**Agregar/Modificar:**
|
|
|
|
```css
|
|
/* ==========================================================================
|
|
HERO SECTION - PADDING EXACTO (Issue #49)
|
|
========================================================================== */
|
|
|
|
.hero-section {
|
|
background: linear-gradient(135deg, #1e3a5f 0%, #2c5282 100%);
|
|
color: #ffffff;
|
|
padding: 3rem 1rem; /* Padding exacto del template */
|
|
text-align: center;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.hero-content {
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
/* Responsive: Reducir padding en mobile */
|
|
@media (max-width: 767px) {
|
|
.hero-section {
|
|
padding: 2rem 1rem;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 575px) {
|
|
.hero-section {
|
|
padding: 1.5rem 0.75rem;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Utilidades Adicionales
|
|
|
|
### Variable CSS para Colores RDash
|
|
|
|
**Agregar en `style.css` en `:root`:**
|
|
|
|
```css
|
|
:root {
|
|
/* Colores RDash */
|
|
--rdash-navy: #0E2337;
|
|
--rdash-blue-dark: #1e3a5f;
|
|
--rdash-blue-light: #2c5282;
|
|
--rdash-turquoise: #61c7cd;
|
|
--rdash-turquoise-dark: #4fb3b9;
|
|
--rdash-orange-start: #FF6B35;
|
|
--rdash-orange-end: #FF8C42;
|
|
--rdash-orange-sidebar-start: #FF8600;
|
|
--rdash-orange-sidebar-end: #FFB800;
|
|
--rdash-gray-notification: #4C5C6B;
|
|
--rdash-gray-card: #f7fafc;
|
|
--rdash-gray-border: #e2e8f0;
|
|
}
|
|
```
|
|
|
|
### Mixins SCSS (si usas Sass)
|
|
|
|
**Crear archivo `_rdash-mixins.scss`:**
|
|
|
|
```scss
|
|
// Gradiente Hero
|
|
@mixin gradient-hero {
|
|
background: linear-gradient(135deg, #1e3a5f 0%, #2c5282 100%);
|
|
}
|
|
|
|
// Gradiente Botón "Let's Talk"
|
|
@mixin gradient-cta-button {
|
|
background: linear-gradient(135deg, #FF6B35 0%, #FF8C42 100%);
|
|
}
|
|
|
|
// Gradiente CTA Box Sidebar
|
|
@mixin gradient-cta-box {
|
|
background: linear-gradient(135deg, #FF8600 0%, #FFB800 100%);
|
|
}
|
|
|
|
// Hover Effect con Transform
|
|
@mixin hover-lift($distance: -2px, $shadow-color: rgba(0, 0, 0, 0.15)) {
|
|
transition: all 0.3s ease;
|
|
|
|
&:hover {
|
|
transform: translateY($distance);
|
|
box-shadow: 0 6px 20px $shadow-color;
|
|
}
|
|
}
|
|
|
|
// Scrollbar Personalizado
|
|
@mixin custom-scrollbar($width: 6px, $thumb-color: #cbd5e0, $track-color: #f1f3f4) {
|
|
&::-webkit-scrollbar {
|
|
width: $width;
|
|
}
|
|
|
|
&::-webkit-scrollbar-track {
|
|
background: $track-color;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
&::-webkit-scrollbar-thumb {
|
|
background: $thumb-color;
|
|
border-radius: 3px;
|
|
|
|
&:hover {
|
|
background: darken($thumb-color, 15%);
|
|
}
|
|
}
|
|
|
|
scrollbar-width: thin;
|
|
scrollbar-color: $thumb-color $track-color;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Snippets
|
|
|
|
### JavaScript para Verificar ScrollSpy
|
|
|
|
**Agregar temporalmente para debug:**
|
|
|
|
```javascript
|
|
// Debug ScrollSpy
|
|
document.querySelectorAll('.apus-toc-link').forEach(link => {
|
|
link.addEventListener('click', (e) => {
|
|
console.log('TOC Link clicked:', link.textContent);
|
|
});
|
|
});
|
|
|
|
// Verificar que IntersectionObserver está funcionando
|
|
const headings = document.querySelectorAll('h2[id], h3[id]');
|
|
console.log(`Observing ${headings.length} headings for ScrollSpy`);
|
|
```
|
|
|
|
### CSS para Debug Visual
|
|
|
|
**Agregar temporalmente para verificar posiciones:**
|
|
|
|
```css
|
|
/* DEBUG: Visualizar áreas sticky */
|
|
.apus-toc {
|
|
outline: 2px dashed red !important;
|
|
}
|
|
|
|
/* DEBUG: Visualizar ::after elements */
|
|
.navbar-nav .nav-link::after {
|
|
background-color: lime !important;
|
|
}
|
|
|
|
/* DEBUG: Visualizar ::before en related posts */
|
|
.related-post-card::before {
|
|
opacity: 1 !important;
|
|
background: red !important;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Comandos Git Útiles
|
|
|
|
### Crear Branch para Issue
|
|
|
|
```bash
|
|
# Issue #41
|
|
git checkout -b issue-41-toc-sticky-scrollspy
|
|
git add assets/css/toc.css assets/js/toc.js
|
|
git commit -m "Issue #41: Implementar TOC sticky con scrollspy
|
|
|
|
- Agregar position sticky con top offset
|
|
- Implementar IntersectionObserver para active link
|
|
- Scrollbar personalizado webkit y firefox
|
|
- Respetar prefers-reduced-motion"
|
|
git push origin issue-41-toc-sticky-scrollspy
|
|
|
|
# Issue #42
|
|
git checkout -b issue-42-navbar-underline
|
|
git add assets/css/header.css
|
|
git commit -m "Issue #42: Agregar underline animado en navbar
|
|
|
|
- ::after pseudo-elemento con width transition
|
|
- Hover color turquesa #61c7cd
|
|
- Background color hover rgba
|
|
- Estados active y current"
|
|
git push origin issue-42-navbar-underline
|
|
```
|
|
|
|
### Crear PR desde CLI
|
|
|
|
```bash
|
|
gh pr create --title "Issue #41: TOC Sticky con ScrollSpy" --body "Implementa TOC sticky con IntersectionObserver para scrollspy automático.
|
|
|
|
Cambios:
|
|
- Position sticky con top 5.5rem
|
|
- IntersectionObserver con rootMargin optimizado
|
|
- Scrollbar personalizado
|
|
- Active link highlighting
|
|
- Responsive: static en mobile
|
|
|
|
Testing:
|
|
- ✅ Chrome, Firefox, Safari, Edge
|
|
- ✅ Mobile responsive
|
|
- ✅ Keyboard navigation
|
|
- ✅ Reduced motion support"
|
|
```
|
|
|
|
---
|
|
|
|
**Última actualización:** 2025-11-04
|
|
**Issues cubiertos:** #41-#49
|
|
**Tiempo total estimado:** 3.85 días
|