[COMPONENTE 11] Implementar Sidebar TOC con ScrollSpy custom - Issue #121
- CREAR: template-parts/content-toc.php
* Función PHP apu_generate_toc() para generar TOC automáticamente
* Regex para buscar H2 con atributo ID
* Solo se muestra en is_single()
- MODIFICAR: single.php (sidebar)
* Agregar div.sidebar-sticky wrapper
* Integrar get_template_part('template-parts/content', 'toc')
* Preparar espacio para CTA Box (componente 12)
- MODIFICAR: style.css (+87 líneas)
* 9 selectores CSS + 4 pseudo-elementos scrollbar
* Sticky positioning (top: 85px)
* Max-height calculado con calc()
* Scroll interno con overflow-y: auto
* Min-height: 0 (crítico para scroll en flexbox)
* Border-left indicator (navy, NO naranja)
* Scrollbar personalizado 6px (solo Webkit)
- MODIFICAR: main.js (+66 líneas)
* Función updateActiveSection() para ScrollSpy
* Algoritmo SIMPLE: verifica si pasaste el top
* Offset scroll: navbarHeight + 100
* Smooth scroll: navbarHeight + 40
* Selector .toc-container a (NO .toc-link)
* NO tiene auto-scroll del TOC
* NO actualiza URL con history.pushState()
Características:
✅ Generación automática desde H2 con ID
✅ ScrollSpy custom (JavaScript vanilla, NO Bootstrap)
✅ Sticky positioning con flexbox
✅ Scroll interno solo en lista
✅ Border-left indicator activo
✅ Scrollbar delgado personalizado
Selectores REALES usados:
- .toc-container a (NO .toc-link)
- .toc-container h4 (NO .toc-title)
- .toc-container li (NO .toc-list li)
🎨 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -265,3 +265,69 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
|
||||
console.log('%c APU México ', 'background: #1e3a5f; color: #FF8600; font-size: 16px; font-weight: bold; padding: 10px;');
|
||||
|
||||
// === SIDEBAR TOC - ScrollSpy ===
|
||||
|
||||
// Table of Contents - ScrollSpy
|
||||
function updateActiveSection() {
|
||||
const tocLinks = document.querySelectorAll('.toc-container a');
|
||||
if (!tocLinks.length) return;
|
||||
|
||||
const navbar = document.querySelector('.navbar');
|
||||
const navbarHeight = navbar ? navbar.offsetHeight : 0;
|
||||
|
||||
const sectionIds = Array.from(tocLinks).map(link => {
|
||||
const href = link.getAttribute('href');
|
||||
return href ? href.substring(1) : null;
|
||||
}).filter(id => id !== null);
|
||||
|
||||
const sections = sectionIds.map(id => document.getElementById(id)).filter(el => el !== null);
|
||||
const scrollPosition = window.scrollY + navbarHeight + 100;
|
||||
|
||||
let activeSection = null;
|
||||
|
||||
for (let i = 0; i < sections.length; i++) {
|
||||
const section = sections[i];
|
||||
const sectionTop = section.offsetTop;
|
||||
|
||||
if (scrollPosition >= sectionTop) {
|
||||
activeSection = section.getAttribute('id');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tocLinks.forEach(link => {
|
||||
link.classList.remove('active');
|
||||
const href = link.getAttribute('href');
|
||||
if (href === '#' + activeSection) {
|
||||
link.classList.add('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Smooth scroll for TOC links
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.toc-container a').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const targetId = this.getAttribute('href');
|
||||
const targetElement = document.querySelector(targetId);
|
||||
|
||||
if (targetElement) {
|
||||
const navbar = document.querySelector('.navbar');
|
||||
const navbarHeight = navbar ? navbar.offsetHeight : 0;
|
||||
const offsetTop = targetElement.offsetTop - navbarHeight - 40;
|
||||
|
||||
window.scrollTo({
|
||||
top: offsetTop,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
updateActiveSection();
|
||||
});
|
||||
|
||||
window.addEventListener('scroll', updateActiveSection);
|
||||
|
||||
Reference in New Issue
Block a user