Files
roi-theme/_planeacion/theme-template/THEME-DOCUMENTATION.md
FrankZamora ea38a12055 [NIVEL 2 AVANCE] Issues #49-#53 - Componentes Principales Verificados
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>
2025-11-04 20:01:07 -06:00

63 KiB

Documentación del Tema WordPress - Análisis de Precios Unitarios

📋 Índice

  1. Visión General
  2. Estructura de Archivos del Tema
  3. Componentes del Diseño
  4. Implementación en WordPress
  5. Funcionalidades Especiales
  6. Optimizaciones SEO
  7. Guía de Desarrollo
  8. Nuevas Funcionalidades de Conversión

📖 Visión General

Propósito del Tema

Tema WordPress personalizado para un sitio de consulta de Análisis de Precios Unitarios (APUs) en el sector de construcción en México. El tema está diseñado para artículos de blog con contenido técnico denso, tablas de datos complejas y optimización SEO avanzada.

Características Principales

  • Idioma: Español (México) - es-MX
  • Framework CSS: Bootstrap 5.3.2
  • Iconos: Bootstrap Icons 1.11.3
  • Tipografía: Poppins (Google Fonts)
  • Arquitectura: Single Page Application con navegación mejorada
  • SEO: Schema.org completo (Article, HowTo, FAQ, Video, BreadcrumbList)
  • A/B Testing: Sistema integrado para CTAs

Público Objetivo

Profesionales de la construcción: ingenieros civiles, arquitectos, constructores, presupuestistas que necesitan consultar estructuras de APUs, insumos y dosificaciones.


📁 Estructura de Archivos del Tema

wp-content/themes/apu-mexico/
├── style.css                          # Hoja de estilos principal (requerido por WP)
├── functions.php                      # Funciones del tema
├── index.php                          # Template principal
├── single.php                         # Template para posts individuales (usar aquí el diseño)
├── header.php                         # Encabezado del sitio
├── footer.php                         # Pie de página
├── sidebar.php                        # Sidebar (si se usa layout 2 columnas)
├── screenshot.png                     # Captura del tema (1200x900px)
│
├── assets/
│   ├── css/
│   │   └── custom-style.css          # Estilos personalizados (del archivo style.css actual)
│   ├── js/
│   │   └── main.js                   # JavaScript personalizado (del archivo actual)
│   └── images/
│       └── (imágenes del tema)
│
├── template-parts/
│   ├── content-single.php            # Contenido del post individual
│   ├── content-hero.php              # Sección hero con título
│   ├── content-toc.php               # Tabla de contenidos
│   ├── content-categories.php        # Badges de categorías
│   ├── content-share.php             # Botones de compartir
│   ├── content-cta.php               # CTA con A/B testing
│   └── content-related-posts.php     # Posts relacionados
│
└── inc/
    ├── schema-markup.php             # Generación de Schema.org
    ├── ab-testing.php                # Lógica de A/B testing
    └── custom-widgets.php            # Widgets personalizados

🎨 Componentes del Diseño

1. NAVBAR (Navegación Superior)

Ubicación: header.php

Características:

  • Sticky (fijo al hacer scroll)
  • Fondo blanco con sombra dinámica
  • Logo/Título del sitio
  • Menú de navegación con dropdowns
  • Responsive con hamburger menu en móvil

Estilos CSS:

.navbar {
    position: sticky;
    top: 0;
    z-index: 1030;
    background: white;
    box-shadow: 0 2px 4px rgba(0,0,0,0.08);
}

.navbar.scrolled {
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}

.nav-link {
    position: relative;
    transition: all 0.3s ease;
}

.nav-link::after {
    /* Animación de línea inferior en hover */
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%) scaleX(0);
    width: 80%;
    height: 2px;
    background: linear-gradient(90deg, #0d6efd, #0dcaf0);
    transition: transform 0.3s ease;
}

.nav-link:hover::after {
    transform: translateX(-50%) scaleX(1);
}

JavaScript:

// Añadir clase 'scrolled' al hacer scroll
window.addEventListener('scroll', function() {
    const navbar = document.querySelector('.navbar');
    if (window.scrollY > 50) {
        navbar.classList.add('scrolled');
    } else {
        navbar.classList.remove('scrolled');
    }
});

Implementación WordPress:

// En functions.php
register_nav_menus(array(
    'primary' => __('Menú Principal', 'apu-mexico'),
));

// En header.php
wp_nav_menu(array(
    'theme_location' => 'primary',
    'container' => false,
    'menu_class' => 'navbar-nav mb-2 mb-lg-0',
    'walker' => new Bootstrap_Nav_Walker(), // Custom walker para Bootstrap
));

2. HERO SECTION (Sección de Título Principal)

Ubicación: template-parts/content-hero.php

Características:

  • Fondo degradado azul oscuro (#1e3a5f → #2c5282)
  • Badges de categorías en la parte superior
  • H1 del artículo centrado
  • Texto blanco con sombra para legibilidad

Estructura HTML:

<div class="container-fluid py-5 mb-4 hero-title">
    <div class="container">
        <!-- Categories Section -->
        <div class="mb-3 d-flex justify-content-center">
            <div class="d-flex gap-2 flex-wrap justify-content-center">
                <!-- Badges de categorías -->
                <a href="#" class="category-badge category-badge-hero">
                    <i class="bi bi-folder-fill me-1"></i>
                    Análisis de Precios
                </a>
                <!-- Repetir para cada categoría -->
            </div>
        </div>

        <!-- Título del Post -->
        <h1 class="display-5 fw-bold text-center">
            <?php the_title(); ?>
        </h1>
    </div>
</div>

Estilos CSS:

.hero-title {
    background: linear-gradient(135deg, #1e3a5f 0%, #2c5282 100%);
    box-shadow: 0 4px 16px rgba(30, 58, 95, 0.25);
}

.hero-title h1 {
    color: #ffffff !important;
    font-weight: 700;
    line-height: 1.4;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
}

.category-badge-hero {
    background: rgba(255, 255, 255, 0.15);
    backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.2);
    color: rgba(255, 255, 255, 0.95);
    padding: 0.375rem 0.875rem;
    border-radius: 20px;
    font-size: 0.813rem;
    font-weight: 500;
    pointer-events: none; /* No clicable, solo visual */
}

Implementación WordPress:

// En template-parts/content-hero.php
<div class="container-fluid py-5 mb-4 hero-title">
    <div class="container">
        <!-- Categorías del post -->
        <div class="mb-3 d-flex justify-content-center">
            <div class="d-flex gap-2 flex-wrap justify-content-center">
                <?php
                $categories = get_the_category();
                foreach ($categories as $category) {
                    echo '<span class="category-badge category-badge-hero">';
                    echo '<i class="bi bi-folder-fill me-1"></i>';
                    echo esc_html($category->name);
                    echo '</span>';
                }
                ?>
            </div>
        </div>

        <!-- Título -->
        <h1 class="display-5 fw-bold text-center">
            <?php the_title(); ?>
        </h1>
    </div>
</div>

3. LAYOUT PRINCIPAL (Contenido + Sidebar)

Ubicación: single.php

Características:

  • Grid de Bootstrap: 9 columnas (contenido) + 3 columnas (sidebar)
  • Responsive: En móvil el sidebar va abajo
  • Sidebar con TOC sticky

Estructura HTML:

<div class="container">
    <div class="row">
        <!-- Columna de Contenido (9/12) -->
        <div class="col-lg-9">
            <!-- Imagen destacada -->
            <div class="featured-image-container my-4">
                <?php the_post_thumbnail('large', ['class' => 'img-fluid']); ?>
            </div>

            <!-- Contenido del post -->
            <div class="post-content">
                <?php the_content(); ?>
            </div>

            <!-- Compartir en redes -->
            <?php get_template_part('template-parts/content', 'share'); ?>

            <!-- CTA con A/B Testing -->
            <?php get_template_part('template-parts/content', 'cta'); ?>

            <!-- Posts relacionados -->
            <?php get_template_part('template-parts/content', 'related-posts'); ?>
        </div>

        <!-- Sidebar / TOC (3/12) -->
        <div class="col-lg-3">
            <?php get_template_part('template-parts/content', 'toc'); ?>
        </div>
    </div>
</div>

4. TABLA DE CONTENIDOS (TOC)

Ubicación: template-parts/content-toc.php

Características:

  • Sticky (se mantiene visible al hacer scroll)
  • Generación automática desde los H2 del contenido
  • Resaltado del elemento activo con ScrollSpy
  • Smooth scroll al hacer clic

Estructura HTML:

<div class="toc-container position-sticky" style="top: 5rem;">
    <h4>Tabla de Contenido</h4>
    <ol class="list-unstyled">
        <li><a href="#introduccion">Introducción</a></li>
        <li><a href="#alternativas">Alternativas</a></li>
        <li><a href="#proceso">Proceso de Elaboración</a></li>
        <!-- Generado automáticamente desde H2s -->
    </ol>
</div>

Estilos CSS:

.toc-container {
    top: 5rem;
    background: #f8f9fa;
    border: 1px solid #e9ecef;
    border-radius: 12px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.08);
    padding: 1rem 1.25rem;
}

.toc-container h4 {
    color: #2c3e50;
    padding-bottom: 12px;
    border-bottom: 3px solid #0d6efd;
    margin-bottom: 1rem;
    font-weight: 700;
    text-align: center;
    font-style: normal;
}

.toc-container li {
    margin-bottom: 0.25rem;
}

.toc-container a {
    display: block;
    padding: 0.375rem 1rem;
    color: #495057;
    text-decoration: none;
    border-left: 3px solid transparent;
    transition: all 0.3s ease;
    border-radius: 4px;
}

.toc-container a:hover {
    background: linear-gradient(90deg, rgba(13, 110, 253, 0.08), transparent);
    border-left-color: #0d6efd;
    color: #0d6efd;
    padding-left: 1.5rem;
}

.toc-container a.active {
    background: linear-gradient(90deg, rgba(13, 110, 253, 0.12), transparent);
    border-left-color: #0d6efd;
    color: #0d6efd;
    font-weight: 600;
}

JavaScript (ScrollSpy Mejorado):

// ScrollSpy mejorado para TOC
function updateActiveSection() {
    const tocLinks = document.querySelectorAll('.toc-container a');
    const navbar = document.querySelector('.navbar');
    const navbarHeight = navbar ? navbar.offsetHeight : 0;

    // Obtener todas las secciones referenciadas en el TOC
    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);

    // Punto de activación: navbar + 100px
    const scrollPosition = window.scrollY + navbarHeight + 100;

    let activeSection = null;

    // Recorrer secciones de arriba hacia abajo
    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;
        }
    }

    // Actualizar clases active
    tocLinks.forEach(link => {
        link.classList.remove('active');
        const href = link.getAttribute('href');
        if (href === '#' + activeSection) {
            link.classList.add('active');
        }
    });
}

// Smooth scroll para TOC links
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 navbarHeight = document.querySelector('.navbar').offsetHeight;
            const offsetTop = targetElement.offsetTop - navbarHeight - 40;
            window.scrollTo({
                top: offsetTop,
                behavior: 'smooth'
            });
        }
    });
});

window.addEventListener('scroll', updateActiveSection);
document.addEventListener('DOMContentLoaded', updateActiveSection);

Implementación WordPress:

// En functions.php - Generar TOC automáticamente
function generate_table_of_contents($content) {
    preg_match_all('/<h2[^>]*id="([^"]*)"[^>]*>(.*?)<\/h2>/i', $content, $matches);

    if (empty($matches[1])) {
        return '';
    }

    $toc = '<div class="toc-container position-sticky" style="top: 5rem;">';
    $toc .= '<h4>Tabla de Contenido</h4>';
    $toc .= '<ol class="list-unstyled">';

    foreach ($matches[1] as $index => $id) {
        $title = strip_tags($matches[2][$index]);
        $toc .= '<li><a href="#' . esc_attr($id) . '">' . esc_html($title) . '</a></li>';
    }

    $toc .= '</ol></div>';

    return $toc;
}

// En template-parts/content-toc.php
<?php
global $post;
$toc = generate_table_of_contents($post->post_content);
echo $toc;
?>

5. TABLAS DE ANÁLISIS DE PRECIOS UNITARIOS

CARACTERÍSTICAS CRÍTICAS:

Estructura HTML Semántica:

<div class="analisis">
    <table>
        <thead>
            <tr>
                <th scope="col">Clave</th>
                <th scope="col">Descripción</th>
                <th scope="col">Unidad</th>
                <th scope="col">Cantidad</th>
                <th scope="col">Costo</th>
                <th scope="col">Importe</th>
            </tr>
        </thead>
        <tbody>
            <!-- Encabezado de sección -->
            <tr class="section-header">
                <td></td>
                <td>Material</td>
                <td class="c3"></td>
                <td class="c4"></td>
                <td class="c5"></td>
                <td class="c6"></td>
            </tr>

            <!-- Fila de datos -->
            <tr>
                <td>AGRE-016</td>
                <td>Agua potable</td>
                <td class="c3">m3</td>
                <td class="c4">0.237500</td>
                <td class="c5">$19.14</td>
                <td class="c6">$4.55</td>
            </tr>

            <!-- Subtotal -->
            <tr class="subtotal-row">
                <td></td>
                <td>Suma de Material</td>
                <td class="c3"></td>
                <td class="c4"></td>
                <td class="c5"></td>
                <td class="c6">$2,956.51</td>
            </tr>

            <!-- Total final -->
            <tr class="total-row">
                <td></td>
                <td>Costo Directo</td>
                <td class="c3"></td>
                <td class="c4"></td>
                <td class="c5"></td>
                <td class="c6">$3,283.52</td>
            </tr>
        </tbody>
    </table>
</div>

Estilos CSS (MUY IMPORTANTE - NO MODIFICAR SIN CUIDADO):

.analisis {
    margin: 2rem 0;
    overflow-x: auto;
}

.analisis table {
    width: 100%;
    border-collapse: collapse;
    background: #ffffff;
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
    border-radius: 8px;
    overflow: hidden;
    border: none;
    border-spacing: 0;
}

/* CRÍTICO: Eliminar todos los bordes */
.analisis table td,
.analisis table tbody,
.analisis table tr {
    border: none;
}

/* Anchos fijos para columnas */
.analisis table td:nth-child(1) { width: 150px; }      /* Clave */
.analisis table td:nth-child(2) { width: auto; min-width: 300px; } /* Descripción */
.analisis table td:nth-child(3) { width: 80px; }       /* Unidad */
.analisis table td:nth-child(4) { width: 110px; }      /* Cantidad */
.analisis table td:nth-child(5) { width: 120px; }      /* Costo */
.analisis table td:nth-child(6) { width: 120px; }      /* Importe */

/* Encabezados (thead) con fondo azul oscuro */
.analisis table thead tr th {
    background: linear-gradient(135deg, #1e3a5f 0%, #2c5282 100%);
    color: #ffffff;
    font-weight: 600;
    text-align: center !important;
    padding: 1rem;
    border: none;
}

/* Filas de datos normales */
.analisis table tbody td {
    padding: 0.75rem 1rem;
    border: none;
}

/* Zebra striping (filas alternadas) */
.analisis table tbody tr:nth-child(even):not(.section-header):not(.subtotal-row):not(.total-row) {
    background-color: #f8f9fa;
}

.analisis table tbody tr:nth-child(odd):not(.section-header):not(.subtotal-row):not(.total-row) {
    background-color: #ffffff;
}

/* Alineación de columnas */
.analisis table td:nth-child(1),
.analisis table td:nth-child(2) {
    text-align: left;
}

/* Columna Unidad (3) centrada */
.analisis table td:nth-child(3),
.analisis table td.c3 {
    text-align: center !important;
    color: #6c757d;
}

/* Columnas monetarias a la derecha */
.analisis table td:nth-child(4),
.analisis table td.c4,
.analisis table td:nth-child(5),
.analisis table td.c5,
.analisis table td:nth-child(6),
.analisis table td.c6 {
    text-align: right !important;
    font-family: 'Courier New', monospace;
    font-weight: 500;
}

/* Hover en filas de datos */
.analisis table tbody tr:not(.section-header):not(.subtotal-row):not(.total-row):hover {
    background-color: #fff3cd !important;
    transition: background-color 0.2s ease;
    cursor: pointer;
}

/* Encabezados de sección (Material, Mano de Obra, etc.) */
.analisis table tr.section-header {
    background-color: #e9ecef !important;
}

.analisis table tr.section-header td {
    font-weight: 600;
    color: #1e3a5f;
    padding: 0.75rem 1rem;
    border: none !important;
}

/* Filas de subtotales */
.analisis table tr.subtotal-row {
    background-color: #d1e7fd !important;
}

.analisis table tr.subtotal-row td {
    font-weight: 700;
    color: #0d47a1;
    padding: 0.875rem 1rem;
    border: none !important;
}

.analisis table tr.subtotal-row td.c6 {
    font-size: 1.05rem;
}

/* Fila de Costo Directo (Total final) */
.analisis table tr.total-row {
    background: linear-gradient(135deg, #1e3a5f 0%, #2c5282 100%) !important;
}

.analisis table tr.total-row td {
    color: #ffffff !important;
    font-weight: 700;
    font-size: 1.1rem;
    padding: 1.125rem 1rem !important;
    border: none !important;
}

.analisis table tr.total-row td.c6 {
    font-size: 1.25rem;
    letter-spacing: 0.5px;
}

/* Responsive para móviles */
@media (max-width: 768px) {
    .analisis {
        font-size: 0.85rem;
    }

    .analisis table td {
        padding: 0.5rem !important;
    }

    .analisis table tr.total-row td {
        font-size: 1rem !important;
    }
}

⚠️ IMPORTANTE PARA EL DESARROLLADOR:

  • NO usar <caption> - arruina el diseño
  • Los encabezados solo van en <thead>, no en <tbody>
  • Las clases c3, c4, c5, c6 son para alineación específica
  • section-header, subtotal-row, total-row son clases especiales

6. COMPARTIR EN REDES SOCIALES

Ubicación: template-parts/content-share.php

Características:

  • Botones para: Facebook, Instagram, LinkedIn, WhatsApp, X (Twitter), Email
  • Iconos de Bootstrap Icons
  • Estilo outline con colores de marca

Estructura HTML:

<div class="my-5 py-4 border-top">
    <p class="mb-3 text-muted">Compartir:</p>
    <div class="d-flex gap-2 flex-wrap share-buttons">
        <a href="#" class="btn btn-outline-primary btn-sm" aria-label="Compartir en Facebook">
            <i class="bi bi-facebook"></i>
        </a>
        <a href="#" class="btn btn-outline-danger btn-sm" aria-label="Compartir en Instagram">
            <i class="bi bi-instagram"></i>
        </a>
        <a href="#" class="btn btn-outline-info btn-sm" aria-label="Compartir en LinkedIn">
            <i class="bi bi-linkedin"></i>
        </a>
        <a href="#" class="btn btn-outline-success btn-sm" aria-label="Compartir en WhatsApp">
            <i class="bi bi-whatsapp"></i>
        </a>
        <a href="#" class="btn btn-outline-dark btn-sm" aria-label="Compartir en X">
            <i class="bi bi-twitter-x"></i>
        </a>
        <a href="#" class="btn btn-outline-secondary btn-sm" aria-label="Compartir por Email">
            <i class="bi bi-envelope"></i>
        </a>
    </div>
</div>

Estilos CSS:

.share-buttons .btn {
    transition: all 0.3s ease;
    border-width: 2px;
}

.share-buttons .btn:hover {
    transform: translateY(-3px) scale(1.1);
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}

Implementación WordPress (URLs dinámicas):

<?php
$post_url = urlencode(get_permalink());
$post_title = urlencode(get_the_title());
?>
<div class="my-5 py-4 border-top">
    <p class="mb-3 text-muted">Compartir:</p>
    <div class="d-flex gap-2 flex-wrap share-buttons">
        <a href="https://www.facebook.com/sharer/sharer.php?u=<?php echo $post_url; ?>"
           target="_blank"
           class="btn btn-outline-primary btn-sm">
            <i class="bi bi-facebook"></i>
        </a>
        <a href="https://www.linkedin.com/sharing/share-offsite/?url=<?php echo $post_url; ?>"
           target="_blank"
           class="btn btn-outline-info btn-sm">
            <i class="bi bi-linkedin"></i>
        </a>
        <a href="https://wa.me/?text=<?php echo $post_title . ' ' . $post_url; ?>"
           target="_blank"
           class="btn btn-outline-success btn-sm">
            <i class="bi bi-whatsapp"></i>
        </a>
        <a href="https://twitter.com/intent/tweet?text=<?php echo $post_title; ?>&url=<?php echo $post_url; ?>"
           target="_blank"
           class="btn btn-outline-dark btn-sm">
            <i class="bi bi-twitter-x"></i>
        </a>
        <a href="mailto:?subject=<?php echo $post_title; ?>&body=<?php echo $post_url; ?>"
           class="btn btn-outline-secondary btn-sm">
            <i class="bi bi-envelope"></i>
        </a>
    </div>
</div>

7. CTA CON A/B TESTING

Ubicación: template-parts/content-cta.php

Características:

  • Test A/B con 2 variantes:
    • Variante A: Enfoque en catálogo (200,000+ APUs)
    • Variante B: Enfoque en membresía
  • Rotación aleatoria 50/50 en cada carga de página
  • Tracking de clics para Google Analytics
  • Fondo degradado naranja-amarillo

Estructura HTML:

<!-- Variante A -->
<div class="my-5 p-4 rounded cta-section cta-variant-a" data-variant="A" style="display: none;">
    <div class="row align-items-center">
        <div class="col-md-8">
            <h3 class="h4 fw-bold text-white mb-2">Accede a 200,000+ Análisis de Precios Unitarios</h3>
            <p class="text-white mb-md-0">Consulta estructuras completas, insumos y dosificaciones de los APUs más utilizados en construcción en México.</p>
        </div>
        <div class="col-md-4 text-md-end mt-3 mt-md-0">
            <a href="#" class="btn btn-light btn-lg cta-button" data-cta-variant="A">
                Ver Catálogo Completo <i class="bi bi-arrow-right ms-2"></i>
            </a>
        </div>
    </div>
</div>

<!-- Variante B -->
<div class="my-5 p-4 rounded cta-section cta-variant-b" data-variant="B" style="display: none;">
    <div class="row align-items-center">
        <div class="col-md-8">
            <h3 class="h4 fw-bold text-white mb-2">¿Necesitas Consultar Más APUs?</h3>
            <p class="text-white mb-md-0">Accede a nuestra biblioteca de 200,000 análisis de precios unitarios con estructuras detalladas y listados de insumos.</p>
        </div>
        <div class="col-md-4 text-md-end mt-3 mt-md-0">
            <a href="#" class="btn btn-light btn-lg cta-button" data-cta-variant="B">
                Conocer Planes de Membresía <i class="bi bi-arrow-right ms-2"></i>
            </a>
        </div>
    </div>
</div>

Estilos CSS:

.cta-section {
    background: linear-gradient(135deg, #FF8600 0%, #FFB800 100%);
    box-shadow: 0 8px 24px rgba(255, 133, 0, 0.3);
}

JavaScript A/B Testing:

// A/B Test para CTA - Rotación en cada carga de página
document.addEventListener('DOMContentLoaded', function() {
    // Selección aleatoria 50/50 entre A y B
    const ctaVariant = Math.random() < 0.5 ? 'A' : 'B';

    // Mostrar la variante seleccionada
    if (ctaVariant === 'A') {
        document.querySelector('.cta-variant-a').style.display = 'block';
    } else {
        document.querySelector('.cta-variant-b').style.display = 'block';
    }

    // Tracking de clicks para Google Analytics
    document.querySelectorAll('.cta-button').forEach(button => {
        button.addEventListener('click', function(e) {
            const variant = this.getAttribute('data-cta-variant');

            if (typeof gtag !== 'undefined') {
                gtag('event', 'cta_click', {
                    'event_category': 'CTA',
                    'event_label': 'Variant_' + variant,
                    'value': variant
                });
            }

            console.log('CTA clicked - Variant: ' + variant);
        });
    });
});

Implementación WordPress:

// En template-parts/content-cta.php
<div class="my-5 p-4 rounded cta-section cta-variant-a" data-variant="A" style="background: linear-gradient(135deg, #FF8600 0%, #FFB800 100%); display: none;">
    <div class="row align-items-center">
        <div class="col-md-8">
            <h3 class="h4 fw-bold text-white mb-2">Accede a 200,000+ Análisis de Precios Unitarios</h3>
            <p class="text-white mb-md-0">Consulta estructuras completas, insumos y dosificaciones de los APUs más utilizados en construcción en México.</p>
        </div>
        <div class="col-md-4 text-md-end mt-3 mt-md-0">
            <a href="<?php echo home_url('/catalogo'); ?>" class="btn btn-light btn-lg cta-button" data-cta-variant="A">
                Ver Catálogo Completo <i class="bi bi-arrow-right ms-2"></i>
            </a>
        </div>
    </div>
</div>

<div class="my-5 p-4 rounded cta-section cta-variant-b" data-variant="B" style="background: linear-gradient(135deg, #FF8600 0%, #FFB800 100%); display: none;">
    <div class="row align-items-center">
        <div class="col-md-8">
            <h3 class="h4 fw-bold text-white mb-2">¿Necesitas Consultar Más APUs?</h3>
            <p class="text-white mb-md-0">Accede a nuestra biblioteca de 200,000 análisis de precios unitarios con estructuras detalladas y listados de insumos.</p>
        </div>
        <div class="col-md-4 text-md-end mt-3 mt-md-0">
            <a href="<?php echo home_url('/membresia'); ?>" class="btn btn-light btn-lg cta-button" data-cta-variant="B">
                Conocer Planes de Membresía <i class="bi bi-arrow-right ms-2"></i>
            </a>
        </div>
    </div>
</div>

8. POSTS RELACIONADOS

Ubicación: template-parts/content-related-posts.php

Características:

  • Grid de 3 columnas (4 en desktop, 6 en tablet, 12 en móvil)
  • 12 posts relacionados
  • Cards con diseño minimalista gris
  • Borde izquierdo de 4px que cambia a azul en hover
  • Paginación con Bootstrap

Estructura HTML:

<div class="my-5 related-posts">
    <h2 class="h3 mb-4">Descubre Más Contenido</h2>
    <div class="row g-4">
        <!-- Card de post relacionado -->
        <div class="col-md-4">
            <div class="card h-100">
                <div class="card-body">
                    <h3 class="card-title">Título del Post</h3>
                    <p class="card-text text-muted small">Breve descripción...</p>
                </div>
            </div>
        </div>
        <!-- Repetir 12 veces -->
    </div>

    <!-- Paginación -->
    <nav aria-label="Navegación de posts relacionados" class="mt-5">
        <ul class="pagination justify-content-center">
            <li class="page-item"><a class="page-link" href="#">Inicio</a></li>
            <li class="page-item active"><a class="page-link" href="#">1</a></li>
            <li class="page-item"><a class="page-link" href="#">2</a></li>
            <li class="page-item"><a class="page-link" href="#">3</a></li>
            <li class="page-item"><a class="page-link" href="#">4</a></li>
            <li class="page-item"><a class="page-link" href="#">5</a></li>
            <li class="page-item"><a class="page-link" href="#">Ver más</a></li>
            <li class="page-item"><a class="page-link" href="#">Fin</a></li>
        </ul>
    </nav>
</div>

Estilos CSS:

.related-posts .card {
    cursor: pointer;
    background: #f8f9fa !important;
    border: 1px solid #dee2e6 !important;
    border-left: 4px solid #6c757d !important;
    transition: all 0.3s ease;
}

.related-posts .card:hover {
    background: #ffffff !important;
    box-shadow: 0 4px 12px rgba(0,0,0,0.1) !important;
    border-left-color: #0d6efd !important;
}

.related-posts .card-body {
    padding: 2rem !important;
}

.related-posts .card-title {
    color: #495057 !important;
    font-weight: 600;
    font-size: 0.95rem;
}

/* Paginación */
.pagination .page-link {
    color: #495057;
    border: 1px solid #dee2e6;
    padding: 0.5rem 1rem;
    margin: 0 0.25rem;
    border-radius: 4px;
    font-weight: 500;
    transition: all 0.3s ease;
}

.pagination .page-link:hover {
    background-color: #f8f9fa;
    border-color: #0d6efd;
    color: #0d6efd;
}

.pagination .page-item.active .page-link {
    background-color: #1e3a5f;
    border-color: #1e3a5f;
    color: #ffffff;
}

Implementación WordPress:

<?php
// Obtener posts relacionados por categoría
$categories = get_the_category();
$category_ids = array();
foreach($categories as $category) {
    $category_ids[] = $category->term_id;
}

$args = array(
    'category__in' => $category_ids,
    'post__not_in' => array(get_the_ID()),
    'posts_per_page' => 12,
    'orderby' => 'rand'
);

$related_posts = new WP_Query($args);

if ($related_posts->have_posts()) : ?>
    <div class="my-5 related-posts">
        <h2 class="h3 mb-4">Descubre Más Contenido</h2>
        <div class="row g-4">
            <?php while ($related_posts->have_posts()) : $related_posts->the_post(); ?>
                <div class="col-md-4">
                    <div class="card h-100">
                        <div class="card-body">
                            <h3 class="card-title">
                                <a href="<?php the_permalink(); ?>">
                                    <?php the_title(); ?>
                                </a>
                            </h3>
                            <p class="card-text text-muted small">
                                <?php echo wp_trim_words(get_the_excerpt(), 15); ?>
                            </p>
                        </div>
                    </div>
                </div>
            <?php endwhile; ?>
        </div>
    </div>
<?php endif; wp_reset_postdata(); ?>

🔍 Optimizaciones SEO

1. Schema.org / JSON-LD

Ubicación: inc/schema-markup.php

Schemas implementados:

  1. Article - Información básica del artículo
  2. HowTo - Proceso paso a paso (para sección de elaboración)
  3. FAQPage - Preguntas frecuentes
  4. VideoObject - Videos relacionados
  5. BreadcrumbList - Navegación jerárquica

Implementación WordPress:

<?php
// En inc/schema-markup.php

function apu_generate_article_schema() {
    if (!is_single()) return;

    global $post;

    $schema = array(
        '@context' => 'https://schema.org',
        '@type' => 'Article',
        'headline' => get_the_title(),
        'description' => get_the_excerpt(),
        'image' => get_the_post_thumbnail_url($post->ID, 'full'),
        'datePublished' => get_the_date('c'),
        'dateModified' => get_the_modified_date('c'),
        'author' => array(
            '@type' => 'Organization',
            'name' => get_bloginfo('name')
        ),
        'publisher' => array(
            '@type' => 'Organization',
            'name' => get_bloginfo('name'),
            'logo' => array(
                '@type' => 'ImageObject',
                'url' => get_site_icon_url()
            )
        ),
        'mainEntityOfPage' => array(
            '@type' => 'WebPage',
            '@id' => get_permalink()
        ),
        'articleSection' => 'Análisis de Precios Unitarios',
        'keywords' => implode(', ', wp_get_post_tags($post->ID, array('fields' => 'names')))
    );

    echo '<script type="application/ld+json">' . json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . '</script>';
}
add_action('wp_head', 'apu_generate_article_schema');

function apu_generate_breadcrumb_schema() {
    if (!is_single()) return;

    $categories = get_the_category();
    $category = !empty($categories) ? $categories[0] : null;

    $schema = array(
        '@context' => 'https://schema.org',
        '@type' => 'BreadcrumbList',
        'itemListElement' => array(
            array(
                '@type' => 'ListItem',
                'position' => 1,
                'name' => 'Inicio',
                'item' => home_url('/')
            ),
            array(
                '@type' => 'ListItem',
                'position' => 2,
                'name' => 'Blog',
                'item' => home_url('/blog')
            )
        )
    );

    if ($category) {
        $schema['itemListElement'][] = array(
            '@type' => 'ListItem',
            'position' => 3,
            'name' => $category->name,
            'item' => get_category_link($category->term_id)
        );
    }

    $schema['itemListElement'][] = array(
        '@type' => 'ListItem',
        'position' => 4,
        'name' => get_the_title(),
        'item' => get_permalink()
    );

    echo '<script type="application/ld+json">' . json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . '</script>';
}
add_action('wp_head', 'apu_generate_breadcrumb_schema');

// FAQ Schema
function apu_generate_faq_schema() {
    if (!is_single()) return;

    // Buscar H3 que contengan "?" en el contenido
    global $post;
    preg_match_all('/<h3[^>]*>(.*?\?[^<]*)<\/h3>\s*<p>(.*?)<\/p>/is', $post->post_content, $matches);

    if (empty($matches[1])) return;

    $faq_items = array();
    for ($i = 0; $i < count($matches[1]); $i++) {
        $faq_items[] = array(
            '@type' => 'Question',
            'name' => strip_tags($matches[1][$i]),
            'acceptedAnswer' => array(
                '@type' => 'Answer',
                'text' => strip_tags($matches[2][$i])
            )
        );
    }

    if (empty($faq_items)) return;

    $schema = array(
        '@context' => 'https://schema.org',
        '@type' => 'FAQPage',
        'mainEntity' => $faq_items
    );

    echo '<script type="application/ld+json">' . json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . '</script>';
}
add_action('wp_head', 'apu_generate_faq_schema');

2. Meta Tags

En header.php:

<head>
    <meta charset="<?php bloginfo('charset'); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <?php if (is_single()) : ?>
        <meta name="description" content="<?php echo esc_attr(wp_trim_words(get_the_excerpt(), 30)); ?>">
        <meta property="og:type" content="article">
        <meta property="og:title" content="<?php the_title(); ?>">
        <meta property="og:description" content="<?php echo esc_attr(get_the_excerpt()); ?>">
        <meta property="og:image" content="<?php echo get_the_post_thumbnail_url(get_the_ID(), 'large'); ?>">
        <meta property="og:url" content="<?php the_permalink(); ?>">
        <link rel="canonical" href="<?php the_permalink(); ?>">
    <?php endif; ?>

    <?php wp_head(); ?>
</head>

⚙️ Implementación en WordPress

1. Enqueue de Assets

En functions.php:

function apu_enqueue_assets() {
    // Bootstrap CSS
    wp_enqueue_style('bootstrap', 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css');

    // Bootstrap Icons
    wp_enqueue_style('bootstrap-icons', 'https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css');

    // Google Fonts
    wp_enqueue_style('google-fonts-poppins', 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');

    // Custom CSS
    wp_enqueue_style('apu-custom-style', get_template_directory_uri() . '/assets/css/custom-style.css', array(), '1.0.0');

    // Bootstrap JS
    wp_enqueue_script('bootstrap-js', 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js', array(), '5.3.2', true);

    // Custom JS
    wp_enqueue_script('apu-main-js', get_template_directory_uri() . '/assets/js/main.js', array(), '1.0.0', true);
}
add_action('wp_enqueue_scripts', 'apu_enqueue_assets');

2. Soporte de Características

En functions.php:

function apu_theme_support() {
    // Título dinámico
    add_theme_support('title-tag');

    // Imagen destacada
    add_theme_support('post-thumbnails');
    set_post_thumbnail_size(1200, 630, true);

    // HTML5
    add_theme_support('html5', array('search-form', 'comment-form', 'comment-list', 'gallery', 'caption'));

    // Menús
    register_nav_menus(array(
        'primary' => __('Menú Principal', 'apu-mexico'),
        'footer' => __('Menú Footer', 'apu-mexico')
    ));
}
add_action('after_setup_theme', 'apu_theme_support');

3. Custom Post Meta (si necesitas)

function apu_add_custom_meta_boxes() {
    add_meta_box(
        'apu_details',
        'Detalles del APU',
        'apu_meta_box_callback',
        'post',
        'normal',
        'high'
    );
}
add_action('add_meta_boxes', 'apu_add_custom_meta_boxes');

function apu_meta_box_callback($post) {
    // Campos personalizados para el APU
    $apu_code = get_post_meta($post->ID, '_apu_code', true);
    $apu_unit = get_post_meta($post->ID, '_apu_unit', true);
    ?>
    <p>
        <label>Código APU:</label>
        <input type="text" name="apu_code" value="<?php echo esc_attr($apu_code); ?>" />
    </p>
    <p>
        <label>Unidad:</label>
        <input type="text" name="apu_unit" value="<?php echo esc_attr($apu_unit); ?>" />
    </p>
    <?php
}

📝 Guía de Desarrollo

Paso 1: Configuración Inicial

  1. Crear carpeta del tema en wp-content/themes/apu-mexico/
  2. Crear style.css con header requerido:
/*
Theme Name: APU México
Theme URI: https://analisisdepreciosunitarios.com
Author: Tu Nombre
Description: Tema personalizado para análisis de precios unitarios
Version: 1.0
License: GNU General Public License v2 or later
Text Domain: apu-mexico
*/
  1. Crear functions.php e index.php básicos

Paso 2: Estructura HTML Base

  1. Crear header.php con:

    • Meta tags
    • Enqueue de assets
    • Navbar
  2. Crear footer.php con:

    • Footer content
    • wp_footer()
  3. Crear single.php como template principal para posts

Paso 3: Template Parts

Crear todos los archivos en template-parts/:

  • content-hero.php
  • content-toc.php
  • content-share.php
  • content-cta.php
  • content-related-posts.php

Paso 4: Assets

  1. Copiar todos los estilos CSS del archivo actual a assets/css/custom-style.css
  2. Copiar JavaScript a assets/js/main.js
  3. Asegurar que los paths sean correctos

Paso 5: Schema.org

Crear inc/schema-markup.php con todas las funciones de generación de schemas

Paso 6: Testing

  1. Validar HTML: https://validator.w3.org/
  2. Validar Schema: https://search.google.com/test/rich-results
  3. Test responsive con DevTools
  4. Test A/B del CTA
  5. Test ScrollSpy del TOC

Paso 7: Optimizaciones Finales

  1. Minificar CSS y JS para producción
  2. Optimizar imágenes
  3. Configurar cache
  4. Test de velocidad con PageSpeed Insights

🚨 Notas Importantes para el Desarrollador

CRÍTICO - NO MODIFICAR:

  1. Estructura de tablas: Los estilos CSS de .analisis table son muy específicos y fueron ajustados múltiples veces. NO cambiar sin probar exhaustivamente.

  2. A/B Testing: El JavaScript debe ejecutarse en DOMContentLoaded y NO usar sessionStorage (debe rotar en cada carga).

  3. TOC ScrollSpy: El algoritmo de detección de sección activa es específico y funciona correctamente. No simplificar.

  4. Schema.org: Todos los schemas deben ser JSON-LD, NO microdata.

  5. Idioma: Siempre es-MX, no es genérico.

RECOMENDACIONES:

  1. Usar un child theme para customizaciones futuras
  2. Implementar cache de Schema.org para mejorar performance
  3. Considerar lazy loading para imágenes de posts relacionados
  4. Implementar sistema de comentarios con Disqus o similar
  5. Agregar breadcrumbs visuales opcionales (actualmente solo están en Schema)

📊 Métricas de Éxito

SEO:

  • Schema.org validado sin errores
  • Core Web Vitals en verde
  • Meta descriptions únicas en todos los posts

UX:

  • TOC funcional con smooth scroll
  • Tables responsive en móvil
  • Tiempo de carga < 3 segundos

Conversión:

  • CTR del CTA > 5%
  • Tasa de rebote < 60%
  • Tiempo en página > 3 minutos

🆕 Nuevas Funcionalidades Implementadas

1. Botón "Let's Talk" en Navbar

Descripción: Botón CTA (Call-to-Action) destacado en color naranja/coral ubicado en el navbar que abre un modal de contacto.

Ubicación en el código:

  • HTML: index.html - línea 304-306
  • CSS: css/style.css - líneas 491-516
  • JS: js/main.js - líneas 122-143

Características:

  • Color naranja vibrante (#FF6B35) que contrasta con la paleta azul del sitio
  • Icono de rayo para llamar la atención
  • Efecto hover con elevación y cambio de sombra
  • Responsive: se adapta a móvil (width: 100%)
  • Abre modal de contacto al hacer click

Código HTML:

<button class="btn btn-lets-talk ms-lg-3" data-bs-toggle="modal" data-bs-target="#contactModal">
    <i class="bi bi-lightning-charge-fill me-2"></i>Let's Talk
</button>

2. CTA Box "¿Listo para potenciar tus proyectos?" en Sidebar

Descripción: Caja de llamada a la acción ubicada debajo de la Tabla de Contenidos (TOC) en el sidebar derecho, con diseño atractivo en gradiente naranja-amarillo.

Ubicación en el código:

  • HTML: index.html - líneas 1175-1185
  • CSS: css/style.css - líneas 554-649

Características:

  • Gradiente naranja-amarillo (#FF8600 → #FFB800) alineado con industria de construcción
  • Animación de pulso sutil en el fondo
  • Icono animado con efecto bounce
  • Botón blanco con texto naranja que invierte colores al hover
  • Efecto elevación al pasar el mouse
  • Sticky junto con la TOC

Código HTML:

<div class="cta-box-sidebar mt-4">
    <div class="cta-box-icon">
        <i class="bi bi-lightning-charge-fill"></i>
    </div>
    <h5 class="cta-box-title">¿Listo para potenciar tus proyectos?</h5>
    <p class="cta-box-text">Accede a nuestra biblioteca completa de APUs y herramientas profesionales.</p>
    <button class="btn btn-cta-box w-100" data-bs-toggle="modal" data-bs-target="#contactModal">
        <i class="bi bi-calendar-check me-2"></i>Solicitar Demo
    </button>
</div>

3. Modal de Contacto con Envío a Webhook

Descripción: Formulario de contacto en modal emergente que se carga dinámicamente desde un archivo independiente y envía datos a un webhook mediante JavaScript.

Archivos:

  • Modal HTML: modal-contact.html (archivo independiente)
  • JavaScript: js/main.js - líneas 145-256
  • CSS: css/style.css - líneas 651-735
  • Contenedor: index.html - línea 1240

Características del formulario:

  • Campos:

    • Nombre completo* (requerido)
    • Empresa (opcional)
    • WhatsApp* (requerido)
    • Correo electrónico* (requerido)
    • Comentarios (opcional)
  • Validaciones:

    • Campos obligatorios
    • Formato de email válido
    • Formato de WhatsApp válido (10-15 dígitos)
    • Mensajes de error descriptivos
  • Envío a Webhook:

    • Método: POST con fetch API
    • Headers: Content-Type: application/json
    • Body: JSON con todos los datos del formulario + timestamp + source
    • Manejo de errores con try/catch
    • Spinner en botón durante envío
    • Cierre automático del modal tras éxito (2 segundos)

Configuración del Webhook:

  1. Abre el archivo js/main.js
  2. Busca la línea 198:
    const WEBHOOK_URL = 'https://tu-webhook.com/contacto';
    
  3. Reemplaza con tu URL de webhook real

Ejemplo de datos enviados al webhook:

{
  "fullName": "Juan Pérez",
  "company": "Constructora XYZ",
  "whatsapp": "+52 55 1234 5678",
  "email": "juan@ejemplo.com",
  "comments": "Me interesa conocer más sobre sus servicios",
  "timestamp": "2025-01-15T10:30:00.000Z",
  "source": "APU Website - Let's Talk Button"
}

Servicios de Webhook recomendados:


4. Optimización de la Tabla de Contenidos (TOC)

Mejoras implementadas:

A) Max-height con scroll:

  • Altura máxima: 450px (desktop), 300px (móvil)
  • Scroll vertical automático cuando el contenido excede
  • Scrollbar personalizado:
    • Ancho: 6px
    • Color: azul Bootstrap (#0d6efd)
    • Track: gris claro
    • Hover: azul más oscuro

B) Reducción de espaciado:

  • Margin entre items: 0.15rem (antes: 0.25rem)
  • Padding de links: 0.3rem 0.85rem (antes: 0.375rem 1rem)
  • Font-size: 0.9rem (antes: 0.95rem)
  • Clase agregada: toc-list en el <ol>

Ubicación en el código:

  • HTML: index.html - línea 1155 (clase toc-list agregada)
  • CSS: css/style.css - líneas 518-552

Código CSS clave:

.toc-list {
    max-height: 450px;
    overflow-y: auto;
    padding-right: 0.5rem;
}

.toc-list::-webkit-scrollbar {
    width: 6px;
}

.toc-list::-webkit-scrollbar-thumb {
    background: #0d6efd;
    border-radius: 3px;
}

Paleta de Colores para CTAs

Decisión de diseño: Se eligieron colores naranjas/cálidos para los CTAs por las siguientes razones:

  1. Contraste visual: Destacan perfectamente sobre la base azul-gris del sitio
  2. Industria de construcción: El naranja es el color universal de la construcción en México (Cemex, señalización, equipos de seguridad)
  3. Psicología del color: Naranja = acción, urgencia, energía (ideal para CTAs)
  4. Consistencia: El template ya tenía un gradiente naranja-amarillo existente

Colores específicos:

  • Botón "Let's Talk": #FF6B35#FF8C42 (gradiente)
  • CTA Box: #FF8600#FFB800 (gradiente existente)
  • Botón Submit: #FF5722#FF6B35 (gradiente)

Integración con Google Analytics

Las nuevas funcionalidades incluyen tracking automático si tienes Google Analytics instalado:

Eventos rastreados:

  1. Click en botón "Let's Talk": No requiere código adicional
  2. Click en botón CTA Box: Event name: cta_click
  3. Envío de formulario: Event name: form_submission

Código de ejemplo en main.js:

if (typeof gtag !== 'undefined') {
    gtag('event', 'form_submission', {
        'event_category': 'Contact Form',
        'event_label': 'Contact Form Submitted',
        'value': 1
    });
}

Testing y Debugging

Para probar el formulario sin webhook real:

  1. Usa Webhook.site para testing:

    • Ve a https://webhook.site
    • Copia la URL única que te dan
    • Pégala en main.js línea 198
    • Envía el formulario y verás los datos en tiempo real
  2. Console logs:

    • Abre DevTools (F12) → Console
    • Verás mensajes de carga del modal
    • Verás errores si el webhook falla
  3. Testing de validación:

    • Intenta enviar formulario vacío
    • Intenta con email inválido
    • Intenta con WhatsApp inválido
    • Verifica mensajes de error

Responsive Design

Todas las funcionalidades son completamente responsive:

Mobile (<768px):

  • Botón "Let's Talk": width 100%, margin-top
  • CTA Box: fuentes más pequeñas
  • TOC: max-height reducido a 300px
  • Modal: padding reducido, fuentes ajustadas

Tablet (768px - 991px):

  • Layout intermedio con ajustes específicos

Desktop (>992px):

  • Diseño completo con todas las animaciones

🆕 Nuevas Funcionalidades de Conversión

Resumen

Se implementaron funcionalidades clave para mejorar la conversión y captura de leads en el sitio, basadas en el diseño de referencia de RDash. Estas funcionalidades incluyen múltiples puntos de contacto estratégicos a lo largo de la página.

Funcionalidades Implementadas

1. Top Notification Bar

Barra de notificaciones delgada ubicada en la parte superior del sitio, antes del navbar.

Ubicación: Arriba del navbar en index.html (líneas 253-262)

Características:

  • Color de fondo: #4C5C6B (gris azulado - RDash style)
  • Texto destacado en color turquesa: #61c7cd
  • Icono de megáfono con Bootstrap Icons
  • Link subrayado con hover effect
  • Sin botón de login (removido por solicitud del usuario)

Código HTML:

<div class="top-notification-bar">
    <div class="container">
        <div class="d-flex align-items-center justify-content-center">
            <i class="bi bi-megaphone-fill me-2"></i>
            <span><strong>Nuevo:</strong> Accede a más de 200,000 Análisis de Precios Unitarios actualizados para 2025.</span>
            <a href="#" class="ms-2 text-white text-decoration-underline">Ver Catálogo</a>
        </div>
    </div>
</div>

Estilos CSS: (style.css líneas 8-32)

.top-notification-bar {
    background-color: #4C5C6B;
    color: #ffffff;
    padding: 0.5rem 0;
    font-size: 0.9rem;
    text-align: center;
}

.top-notification-bar strong {
    color: #61c7cd;
}

.top-notification-bar i {
    color: #61c7cd;
}

.top-notification-bar a:hover {
    color: #61c7cd;
}

2. Navbar Actualizado con Nuevo Esquema de Colores

El navbar fue actualizado siguiendo la paleta de colores de RDash para mantener consistencia visual profesional.

Paleta de Colores RDash:

  • Navbar Background: #0E2337 (azul navy oscuro)
  • Notification Bar: #4C5C6B (gris azulado)
  • Acentos/Hover: #61c7cd (turquesa/cyan)
  • Texto: #ffffff (blanco)

Cambios Realizados:

  1. Fondo del Navbar:

    • Antes: Gradiente #2C3E50 → #34495E
    • Ahora: Color sólido #0E2337
  2. Hover en Links:

    • Antes: #FFB800 (naranja)
    • Ahora: #61c7cd (turquesa)
  3. Underline Animation:

    • Antes: Gradiente naranja
    • Ahora: #61c7cd sólido
  4. Dropdown Hover:

    • Antes: Fondo naranja con transparencia
    • Ahora: rgba(97, 199, 205, 0.1) con texto #61c7cd

Razón del Cambio: Los colores naranja/amarillo eran apropiados para CTAs (industria de construcción en México), pero para el navbar principal se adoptó la paleta RDash que proporciona:

  • Mayor profesionalismo
  • Mejor contraste con el fondo oscuro
  • Coherencia con sitios de software/SaaS modernos
  • El turquesa/cyan es un color que transmite tecnología y confianza

3. Botón "Let's Talk" en Navbar

Botón CTA prominente en el navbar que abre un modal de contacto.

Ubicación: Navbar, al lado derecho (después de los menús)

Características:

  • Gradiente naranja/coral para destacar: #FF6B35 → #FF8C42
  • Icono de rayo (lightning) de Bootstrap Icons
  • Abre modal de contacto con data-bs-toggle="modal"
  • Animaciones en hover (elevación + brillo)
  • Responsive: 100% width en móviles

Código HTML: (index.html líneas 315-317)

<button class="btn btn-lets-talk ms-lg-3" data-bs-toggle="modal" data-bs-target="#contactModal">
    <i class="bi bi-lightning-charge-fill me-2"></i>Let's Talk
</button>

Estilos CSS: (style.css líneas 491-516)

.btn-lets-talk {
    background: linear-gradient(135deg, #FF6B35 0%, #FF8C42 100%);
    color: #ffffff;
    font-weight: 600;
    padding: 0.5rem 1.5rem;
    border: none;
    border-radius: 6px;
    transition: all 0.3s ease;
    box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);
}

.btn-lets-talk:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(255, 107, 53, 0.4);
}

Razón del Esquema de Color:

  • Naranja para CTAs: Se mantiene el naranja/coral para todos los botones de llamada a la acción (CTAs) porque es el color de la industria de construcción en México (Cemex, cascos de seguridad, señalización)
  • Alto Contraste: El naranja crea un contraste fuerte contra el navbar oscuro #0E2337
  • Jerarquía Visual: Separa claramente la navegación (turquesa) de las acciones de conversión (naranja)

4. CTA Box "Ready to Supercharge" Debajo de TOC

Caja de llamada a la acción ubicada estratégicamente debajo de la tabla de contenidos en el sidebar.

Ubicación: Sidebar, inmediatamente debajo del TOC

Características:

  • Gradiente naranja/amarillo vibrante: #FF8600 → #FFB800
  • Sticky junto con el TOC (ambos en contenedor .sidebar-sticky)
  • Botón con icono de calendario
  • Sin icono superior (removido para ahorrar espacio)
  • Diseño compacto con padding reducido

Código HTML: (index.html líneas 1176-1185)

<div class="sidebar-sticky position-sticky" style="top: 5rem;">
    <div class="toc-container">
        <!-- TOC content -->
    </div>

    <div class="cta-box-sidebar mt-3">
        <h5 class="cta-box-title">¿Listo para potenciar tus proyectos?</h5>
        <p class="cta-box-text">Accede a nuestra biblioteca completa de APUs y herramientas profesionales.</p>
        <button class="btn btn-cta-box w-100" data-bs-toggle="modal" data-bs-target="#contactModal">
            <i class="bi bi-calendar-check me-2"></i>Solicitar Demo
        </button>
    </div>
</div>

Comportamiento Sticky:

  • Tanto el TOC como el CTA Box están dentro del mismo contenedor .sidebar-sticky
  • Esto asegura que se muevan juntos al hacer scroll
  • El CTA Box siempre permanece debajo del TOC
  • top: 5rem proporciona espacio para el navbar sticky

Estilos CSS: (style.css líneas 564-620)

.cta-box-sidebar {
    background: linear-gradient(135deg, #FF8600 0%, #FFB800 100%);
    border-radius: 10px;
    padding: 1.25rem;
    text-align: center;
    box-shadow: 0 6px 20px rgba(255, 133, 0, 0.3);
}

.btn-cta-box {
    background-color: rgba(255, 255, 255, 0.95);
    color: #FF8600;
    font-weight: 600;
    border: 2px solid rgba(255, 255, 255, 0.3);
}

.btn-cta-box:hover {
    background-color: #ffffff;
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

Optimización del TOC: Para evitar que el TOC sea demasiado alto y necesite scroll vertical, se aplicaron los siguientes ajustes:

.toc-container {
    padding: 0.75rem 1rem !important;
}

.toc-container li {
    margin-bottom: 0.1rem !important;
}

.toc-container a {
    padding: 0.25rem 0.75rem !important;
    font-size: 0.875rem !important;
    line-height: 1.3 !important;
}

.toc-list {
    max-height: 600px;
    overflow-y: auto;
}

5. Modal de Contacto (Archivo Independiente)

Modal de Bootstrap 5 cargado dinámicamente desde archivo HTML separado.

Archivo: modal-contact.html (nuevo archivo)

Carga Dinámica: El modal se carga mediante JavaScript al cargar la página:

function loadContactModal() {
    fetch('modal-contact.html')
        .then(response => response.text())
        .then(html => {
            document.getElementById('modalContainer').innerHTML = html;
            initContactForm();
        })
        .catch(error => {
            console.error('Error cargando el modal:', error);
        });
}

Campos del Formulario:

Campo Tipo Requerido Validación
Nombre completo text No vacío
Empresa text No -
WhatsApp tel 10-15 dígitos, formato internacional
Correo email Formato email válido (regex)
Comentarios textarea No -

Validaciones Implementadas:

// Email validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(formData.email)) {
    showFormMessage('Por favor ingresa un correo electrónico válido', 'danger');
    return;
}

// WhatsApp validation
const whatsappRegex = /^\+?[0-9]{10,15}$/;
if (!whatsappRegex.test(formData.whatsapp.replace(/\s/g, ''))) {
    showFormMessage('Por favor ingresa un número de WhatsApp válido', 'danger');
    return;
}

Datos Enviados al Webhook:

{
  "fullName": "Juan Pérez",
  "company": "Constructora XYZ",
  "whatsapp": "+52 55 1234 5678",
  "email": "juan@ejemplo.com",
  "comments": "Comentarios opcionales",
  "timestamp": "2025-01-15T10:30:00.000Z",
  "source": "APU Website - Let's Talk Button"
}

Método: POST Content-Type: application/json

Estados del Botón Submit:

  • Normal: "Enviar Mensaje"
  • Enviando: "Enviando..." con spinner de Bootstrap
  • Éxito: Mensaje verde, formulario se resetea, modal se cierra después de 2 segundos
  • Error: Mensaje rojo, botón se rehabilita

Sección adicional de contacto antes del footer con diseño limpio y consistente.

Ubicación: Antes del footer principal

Diseño:

  • Fondo: bg-secondary bg-opacity-25 (Bootstrap class)
  • Layout: 2 columnas en desktop (información + formulario)
  • Iconos naranja para información de contacto
  • Mismo sistema de validación que el modal

Código HTML: (index.html líneas 1188-1251)

Características Especiales:

  • Campo source diferente: "APU Website - Footer Contact Form"
  • Permite trackear de dónde viene cada lead
  • Diseño más simple y directo que el modal
  • No requiere interacción de abrir modal

Razón del Diseño: Después de varias iteraciones, se llegó a este diseño porque:

  1. No modifica el footer original (requisito del usuario)
  2. Usa colores de Bootstrap consistentes con el resto del tema
  3. Fondo gris claro que contrasta con el footer oscuro
  4. Iconos naranja mantienen coherencia con los CTAs

Configuración del Webhook

Paso 1: Configurar URL del Webhook

Abre js/main.js y busca la línea 203 (modal) y línea 316 (footer):

const WEBHOOK_URL = 'https://tu-webhook.com/contacto';

Reemplaza con tu URL de webhook real.

Paso 2: Testing Rápido con Webhook.site

Para probar sin webhook real:

  1. Ve a https://webhook.site
  2. Copia la URL única que te proporciona
  3. Pégala en main.js (líneas 203 y 316)
  4. Abre index.html en el navegador
  5. Click en "Let's Talk" → completa formulario → Submit
  6. Verifica los datos en tiempo real en Webhook.site

Servicios de Webhook Recomendados:

Servicio Tipo Precio URL
Webhook.site Testing Gratis https://webhook.site
Make (Integromat) Automatización Gratis/Pago https://www.make.com
Zapier Automatización Gratis/Pago https://zapier.com
n8n Self-hosted Gratis https://n8n.io
Pipedream Serverless Gratis/Pago https://pipedream.com

Integración con CRM: Puedes usar Make.com o Zapier para conectar el webhook con:

  • Google Sheets
  • HubSpot
  • Salesforce
  • Zoho CRM
  • Mailchimp
  • Notion
  • Airtable

Google Analytics Tracking

El código incluye tracking automático para Google Analytics (si está instalado).

Eventos Trackeados:

  1. form_submission - Cuando se envía exitosamente un formulario

    gtag('event', 'form_submission', {
        'event_category': 'Contact Form',
        'event_label': 'Contact Form Submitted',
        'value': 1
    });
    
  2. cta_click - Cuando se hace click en cualquier CTA

    gtag('event', 'cta_click', {
        'event_category': 'CTA',
        'event_label': 'Variant_A', // o 'Variant_B'
        'value': 'A'
    });
    

No requiere configuración adicional si ya tienes Google Analytics (gtag) instalado globalmente.


Responsive Design

Todas las funcionalidades son 100% responsive:

Mobile (<768px):

  • Top notification bar: texto más compacto
  • Navbar: hamburger menu
  • Botón "Let's Talk": width 100%, margin-top
  • CTA Box: fuentes más pequeñas, padding reducido
  • TOC: max-height reducido a 300px
  • Modal: padding reducido, fuentes ajustadas
  • Footer form: columna única

Tablet (768px - 991px):

  • Layout intermedio con ajustes específicos
  • TOC y CTA Box comienzan a aparecer en sidebar
  • Footer form mantiene 2 columnas

Desktop (>992px):

  • Diseño completo con todas las animaciones
  • Sidebar sticky con TOC + CTA Box
  • Footer form en 2 columnas (40% info, 60% form)

Archivos Modificados/Creados

Archivos nuevos:

  • modal-contact.html - Modal de formulario de contacto

Archivos modificados:

  • 📝 index.html - Top notification bar + Navbar + Botón Let's Talk + CTA box + Footer form + contenedor modal
  • 🎨 css/style.css - 500+ líneas agregadas con todos los estilos
  • js/main.js - 200+ líneas agregadas para carga de modal y envío a webhook

Paleta de Colores Final

Navbar y Navegación (RDash Style):

  • 🔵 Navbar Background: #0E2337 (azul navy oscuro)
  • 🔵 Top Notification Bar: #4C5C6B (gris azulado)
  • 💎 Hover/Acentos: #61c7cd (turquesa/cyan)
  • Texto: #ffffff (blanco)

CTAs y Botones de Conversión (Construcción):

  • 🟠 Botón Let's Talk: #FF6B35 → #FF8C42 (gradiente naranja/coral)
  • 🟡 CTA Box: #FF8600 → #FFB800 (gradiente naranja/amarillo)
  • 🔴 Botón Submit: #FF5722 → #FF6B35 (gradiente coral/rojo)

Razón de la Separación:

  • Navegación (turquesa): Transmite tecnología, profesionalismo, modernidad
  • CTAs (naranja): Color de la industria de construcción en México, alta visibilidad, urgencia

Troubleshooting

El modal no aparece:

  • Verifica que Bootstrap JS esté cargado correctamente
  • Abre Console (F12) y busca errores
  • Verifica que modal-contact.html exista en la misma carpeta que index.html

El formulario no envía:

  • Verifica la URL del webhook en main.js líneas 203 y 316
  • Abre DevTools → Network tab y busca el request POST
  • Verifica CORS si el webhook está en otro dominio
  • Usa Webhook.site para testing inicial

Los estilos no se aplican:

  • Haz Ctrl+Shift+R para refrescar sin caché
  • Verifica que css/style.css esté vinculado correctamente en el <head>
  • Verifica que no haya errores de sintaxis en CSS

El botón "Let's Talk" no se ve:

  • Verifica que Bootstrap Icons esté cargado
  • Busca .btn-lets-talk en DevTools → Elements
  • Verifica que el navbar tenga clase navbar-dark

TOC con demasiado scroll vertical:

  • Reduce el margin-bottom de los items del TOC
  • Ajusta max-height del .toc-list
  • Reduce padding de los links <a> dentro del TOC

Próximos Pasos Recomendados

  1. Configura el webhook real (paso 1)
  2. Prueba en local con Webhook.site (paso 2)
  3. Verifica responsive en mobile con DevTools
  4. Integra con tu backend/CRM real
  5. Activa Google Analytics tracking
  6. Monitorea conversiones y ajusta copy según resultados
  7. Realiza A/B testing del copy de los CTAs
  8. Considera agregar reCAPTCHA para prevenir spam

🔗 Referencias


Versión: 2.1 Última actualización: Enero 2025 Última funcionalidad agregada: Navbar y Notification Bar con colores RDash Versión del documento: 2.0 (Nuevas funcionalidades: Let's Talk Button + CTA Box + Modal de Contacto)