<header class="header-profesional fixed-top">
<div class="container-xl">
<div class="header-content">
{# Logo y marca - Lado izquierdo #}
<div class="header-brand">
{# Botón hamburguesa solo móvil #}
<button class="mobile-toggle d-lg-none" type="button" aria-label="Menú principal">
<span class="toggle-bar"></span>
<span class="toggle-bar"></span>
<span class="toggle-bar"></span>
</button>
<a href="{{ path('home_index') }}" class="brand-link">
<div class="brand-logo">
<img src="{{ asset('images/logo-clinica.png') }}"
data-logo-light="{{ asset('images/logo-clinica.png') }}"
data-logo-dark="{{ asset('images/logo-clinica-dark.png') }}"
alt="ImagingPro - Centro de Diagnóstico"
class="logo-img">
</div>
</a>
</div>
{# Navegación principal - Centro #}
<nav class="header-nav d-none d-lg-flex">
<ul class="nav-menu">
<li class="nav-item">
<a href="{{ path('home_index') }}" class="nav-link active">
<i class="bi bi-house-door"></i>
<span class="nav-text" data-lang="es">Inicio</span>
<span class="nav-text" data-lang="en" style="display:none;">Home</span>
</a>
</li>
<li class="nav-item">
<a href="{{ path('home_index') }}#servicios" class="nav-link">
<i class="bi bi-cpu-fill"></i>
<span class="nav-text" data-lang="es">Servicios</span>
<span class="nav-text" data-lang="en" style="display:none;">Services</span>
</a>
</li>
<li class="nav-item">
<a href="{{ path('home_index') }}#experiencia" class="nav-link">
<i class="bi bi-heart-pulse"></i>
<span class="nav-text" data-lang="es">Excelencia Médica</span>
<span class="nav-text" data-lang="en" style="display:none;">Medical Excellence</span>
</a>
</li>
<li class="nav-item">
<a href="{{ path('home_index') }}#contacto" class="nav-link">
<i class="bi bi-telephone"></i>
<span class="nav-text" data-lang="es">Contacto</span>
<span class="nav-text" data-lang="en" style="display:none;">Contact</span>
</a>
</li>
<li class="nav-item">
<a href="{{ path('home_index') }}#formas-medicas" class="nav-link">
<i class="fa fa-file-medical"></i>
<span class="nav-text" data-lang="es">Formas Médicas</span>
<span class="nav-text" data-lang="en" style="display:none;">Medical Forms</span>
</a>
</li>
</ul>
</nav>
{# Acciones - Lado derecho #}
<div class="header-actions">
{# Selector de idioma circular moderno #}
<div class="language-selector-wrapper">
<button class="language-trigger" id="languageTrigger">
<span class="current-language">
<span class="language-flag"></span>
</span>
<i class="bi bi-chevron-down language-chevron"></i>
</button>
<div class="language-dropdown">
<div class="language-option" data-lang="es">
<span class="option-flag"></span>
<div class="option-content">
<span class="option-name" data-lang="es">Español</span>
<span class="option-name" data-lang="en" style="display:none;">Spanish</span>
<span class="option-code">ES</span>
</div>
<i class="bi bi-check2 option-check"></i>
</div>
<div class="language-option" data-lang="en">
<span class="option-flag"></span>
<div class="option-content">
<span class="option-name" data-lang="es">Inglés</span>
<span class="option-name" data-lang="en" style="display:none;">English</span>
<span class="option-code">US</span>
</div>
<i class="bi bi-check2 option-check"></i>
</div>
</div>
</div>
{# Botón modo oscuro/claro #}
<button class="theme-toggle" id="themeToggle" aria-label="Cambiar tema">
<i class="bi bi-sun-fill theme-icon"></i>
</button>
{# Botón agendar cita #}
<button class="btn-agendar btn-primary" data-bs-toggle="modal" data-bs-target="#agendarCitaModal">
<i class="bi bi-calendar-check"></i>
<span class="btn-text" data-lang="es">Agendar Cita</span>
<span class="btn-text" data-lang="en" style="display:none;">Book Appointment</span>
</button>
{# Botón portal médico #}
<a href="{{ path('app_login') }}" class="btn-portal btn-outline">
<i class="bi bi-speedometer2"></i>
<span class="btn-text" data-lang="es">Portal Médico</span>
<span class="btn-text" data-lang="en" style="display:none;">Medical Portal</span>
</a>
</div>
</div>
</div>
{# Panel lateral móvil #}
<div class="mobile-sidebar d-lg-none">
<div class="sidebar-header">
<div class="sidebar-brand">
<div class="brand-logo">
<img src="{{ asset('images/logo-clinica.png') }}"
data-logo-light="{{ asset('images/logo-clinica.png') }}"
data-logo-dark="{{ asset('images/logo-clinica-dark.png') }}"
alt="ImagingPro - Centro de Diagnóstico"
class="logo-img">
</div>
</div>
<button class="sidebar-close">
<i class="bi bi-x-lg"></i>
</button>
</div>
<nav class="sidebar-nav">
<ul class="sidebar-menu">
<li class="sidebar-item">
<a href="{{ path('home_index') }}" class="sidebar-link active">
<i class="bi bi-house-door-fill"></i>
<span data-lang="es">Inicio</span>
<span data-lang="en" style="display:none;">Home</span>
</a>
</li>
<li class="sidebar-item">
<a href="{{ path('home_index') }}#servicios" class="sidebar-link">
<i class="bi bi-heart-pulse"></i>
<span data-lang="es">Servicios Médicos</span>
<span data-lang="en" style="display:none;">Medical Services</span>
</a>
</li>
<li class="sidebar-item">
<a href="{{ path('home_index') }}#experiencia" class="sidebar-link">
<i class="bi bi-award"></i>
<span data-lang="es">Excelencia Médica</span>
<span data-lang="en" style="display:none;">Medical Excellence</span>
</a>
</li>
<li class="sidebar-item">
<a href="{{ path('home_index') }}#contacto" class="sidebar-link">
<i class="bi bi-telephone"></i>
<span data-lang="es">Contacto</span>
<span data-lang="en" style="display:none;">Contact</span>
</a>
</li>
<li class="sidebar-item">
<a href="{{ path('home_index') }}#formas-medicas" class="sidebar-link">
<i class="fa fa-file-medical"></i>
<span data-lang="es">Formas Médicas</span>
<span data-lang="en" style="display:none;">Medical Forms</span>
</a>
</li>
<li class="sidebar-divider"></li>
<li class="sidebar-item">
<a href="{{ path('app_login') }}" class="sidebar-link">
<i class="bi bi-speedometer2"></i>
<span data-lang="es">Portal Médico</span>
<span data-lang="en" style="display:none;">Medical Portal</span>
</a>
</li>
</ul>
</nav>
<div class="sidebar-footer">
<button class="btn-agendar-sidebar" data-bs-toggle="modal" data-bs-target="#agendarCitaModal">
<i class="bi bi-calendar-check"></i>
<span data-lang="es">Agendar Cita Rápida</span>
<span data-lang="en" style="display:none;">Quick Appointment</span>
</button>
</div>
</div>
<div class="sidebar-overlay"></div>
</header>
<style>
/* ========== SELECTOR DE IDIOMA CIRCULAR PROFESIONAL ========== */
.language-selector-wrapper {
position: relative;
display: inline-block;
}
/* BOTÓN CIRCULAR ELEGANTE - SOLO BANDERA */
.language-trigger {
display: flex;
align-items: center;
justify-content: center;
width: 35px;
height: 35px;
background: var(--bg-white);
border: 2px solid var(--border-light);
border-radius: 50%;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
color: var(--text-dark);
font-weight: 500;
position: relative;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
padding: 0;
}
.language-trigger:hover {
background: var(--bg-light);
border-color: var(--primary-blue);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(26, 75, 140, 0.15);
}
.language-trigger.active {
background: var(--bg-light);
border-color: var(--primary-blue);
box-shadow: 0 4px 12px rgba(26, 75, 140, 0.2);
}
.language-trigger.active .language-chevron {
transform: rotate(180deg);
color: var(--primary-blue);
}
.current-language {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.language-flag {
width: 20px;
height: 15px;
background-size: cover;
background-position: center;
border-radius: 2px;
color: transparent;
display: inline-block;
}
.language-chevron {
position: absolute;
bottom: 2px;
right: 2px;
font-size: 0.6rem;
color: var(--text-light);
background: var(--bg-white);
border-radius: 50%;
width: 14px;
height: 14px;
display: none;
align-items: center;
justify-content: center;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
border: 1px solid var(--border-light);
}
/* DROPDOWN COMPACTO Y ELEGANTE */
.language-dropdown {
position: absolute;
top: 100%;
right: 0;
margin-top: 0.75rem;
background: var(--bg-white);
border: 1.5px solid var(--border-light);
border-radius: 16px;
box-shadow: 0 12px 32px rgba(0,0,0,0.18);
min-width: 140px;
opacity: 0;
visibility: hidden;
transform: translateY(-12px) scale(0.95);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
z-index: 1000;
overflow: hidden;
backdrop-filter: blur(10px);
}
.language-selector-wrapper.active .language-dropdown {
opacity: 1;
visibility: visible;
transform: translateY(0) scale(1);
}
.language-option {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
background: none;
border: none;
cursor: pointer;
transition: all 0.2s ease;
color: var(--text-dark);
width: 100%;
text-align: left;
border-bottom: 1px solid var(--border-light);
}
.language-option:last-child {
border-bottom: none;
}
.language-option:hover {
background: var(--bg-light);
transform: translateX(4px);
}
.language-option.active {
background: var(--primary-blue);
color: white;
}
.language-option.active .option-code {
color: rgba(255, 255, 255, 0.8);
}
.language-option.active .option-check {
opacity: 1;
color: white;
}
.option-content {
display: flex;
flex-direction: column;
gap: 0.1rem;
flex: 1;
}
.option-flag {
width: 20px;
height: 15px;
background-size: cover;
background-position: center;
border-radius: 2px;
display: inline-block;
}
.option-name {
font-weight: 500;
font-size: 0.8rem;
line-height: 1.2;
}
.option-code {
font-size: 0.7rem;
color: var(--text-light);
font-weight: 600;
line-height: 1;
}
.option-check {
font-size: 0.75rem;
color: var(--primary-blue);
opacity: 0;
transition: all 0.2s ease;
flex-shrink: 0;
}
/* ========== VARIABLES PARA MODO OSCURO MEJORADAS ========== */
:root {
/* Colores modo claro (default) */
--bg-white: #ffffff;
--bg-light: #f8f9fa;
--text-dark: #2d3748;
--text-light: #718096;
--border-light: #e2e8f0;
--primary-blue: #1a4b8c;
--primary-blue-dark: #0d3a6e;
--shadow: 0 2px 10px rgba(0,0,0,0.08);
--shadow-hover: 0 4px 20px rgba(0,0,0,0.12);
}
[data-theme="dark"] {
/* Colores modo oscuro - TEXTO MÁS VISIBLE */
--bg-white: #1a202c;
--bg-light: #2d3748;
--text-dark: #e2e8f0; /* TEXTO BLANCO GRISÁCEO PARA MEJOR VISIBILIDAD */
--text-light: #a0aec0; /* Texto secundario visible */
--border-light: #4a5568;
--primary-blue: #63b3ed; /* Azul claro para elementos principales */
--primary-blue-dark: #4299e1;
--shadow: 0 2px 10px rgba(0,0,0,0.3);
--shadow-hover: 0 4px 20px rgba(0,0,0,0.4);
}
/* Modo oscuro mejorado para el selector de idioma */
[data-theme="dark"] .language-trigger {
border-color: #4a5568;
background: #2d3748;
}
[data-theme="dark"] .language-trigger:hover {
border-color: var(--primary-blue);
background: #4a5568;
}
[data-theme="dark"] .language-chevron {
background: #4a5568;
color: #a0aec0;
border-color: #4a5568;
}
[data-theme="dark"] .language-dropdown {
background: #2d3748;
border-color: #4a5568;
box-shadow: 0 12px 32px rgba(0,0,0,0.4);
}
[data-theme="dark"] .language-option {
border-bottom-color: #4a5568;
}
[data-theme="dark"] .language-option:hover {
background: #4a5568;
}
/* ========== LOGO CON DEGRADADO SOLO EN MODO OSCURO ========== */
.brand-logo {
width: 250px;
height: 110px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
/* ========== BOTÓN TOGGLE ========== */
.theme-toggle {
background: none;
border: none;
padding: 0.5rem;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
transition: all 0.3s ease;
color: var(--text-dark);
}
.theme-toggle:hover {
background: var(--bg-light);
transform: scale(1.1);
}
.theme-icon {
font-size: 1.1rem;
transition: all 0.3s ease;
}
/* ========== HEADER MÁS COMPACTO ========== */
.header-profesional {
background: var(--bg-white);
box-shadow: var(--shadow);
border-bottom: 1px solid var(--border-light);
padding: 0.75rem 0;
transition: all 0.3s ease;
z-index: 1030;
}
/* CONTENEDOR PRINCIPAL - ESPACIO JUSTO */
.header-content {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem; /* Reducido para dar espacio al selector de idioma */
}
/* NAVEGACIÓN - ITEMS MÁS COMPACTOS */
.nav-menu {
display: flex;
align-items: center;
gap: 0.25rem;
list-style: none;
margin: 0;
padding: 0;
flex-wrap: nowrap;
white-space: nowrap;
}
.nav-link {
display: flex;
align-items: center;
gap: 0.3rem;
padding: 0.5rem 0.8rem;
color: var(--text-dark); /* Texto visible en ambos modos */
text-decoration: none;
font-weight: 500;
border-radius: 6px;
transition: all 0.3s ease;
font-size: 0.85rem;
white-space: nowrap;
}
[data-theme="dark"] .nav-link {
color: var(--primary-blue);
}
.nav-link i {
color: var(--primary-blue); /* ICONOS AZUL CLARO en ambos modos */
transition: all 0.3s ease;
}
/* HOVER: SE PONEN BLANCOS en modo oscuro */
[data-theme="dark"] .nav-link:hover,
[data-theme="dark"] .nav-link.active {
background: var(--primary-blue);
color: white !important; /* Texto blanco en hover */
transform: translateY(-1px);
}
[data-theme="dark"] .nav-link:hover i,
[data-theme="dark"] .nav-link.active i {
color: white !important; /* Iconos blancos en hover */
}
/* Estilos normales para modo claro */
.nav-link:hover,
.nav-link.active {
background: var(--primary-blue);
color: white;
transform: translateY(-1px);
}
.nav-link:hover i,
.nav-link.active i {
color: white;
}
/* BOTONES - MÁS COMPACTOS */
.header-actions {
display: flex;
align-items: center;
gap: 0.5rem; /* Reducido para mejor acomodo */
flex-shrink: 0;
}
.btn-agendar,
.btn-portal {
display: flex;
align-items: center;
gap: 0.3rem;
padding: 0.5rem 0.9rem;
border-radius: 6px;
font-weight: 600;
text-decoration: none;
transition: all 0.3s ease;
border: none;
font-size: 0.85rem;
white-space: nowrap;
}
.btn-agendar {
background: linear-gradient(135deg, var(--primary-blue), var(--primary-blue-dark));
color: white;
box-shadow: 0 2px 10px rgba(26, 75, 140, 0.3);
}
.btn-agendar:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(26, 75, 140, 0.4);
color: white;
}
.btn-portal {
background: transparent;
color: var(--primary-blue);
border: 2px solid var(--primary-blue);
}
.btn-portal:hover {
background: var(--primary-blue);
color: white;
transform: translateY(-1px);
}
.brand-link {
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
color: inherit;
transition: all 0.3s ease;
}
.brand-link:hover {
transform: translateY(-2px);
}
.logo-img {
width: 100%;
height: auto;
object-fit: contain;
}
.header-nav {
flex: 1;
display: flex;
justify-content: center;
}
.nav-item {
position: relative;
}
.mobile-toggle {
background: none;
border: none;
padding: 0.5rem;
cursor: pointer;
display: flex;
flex-direction: column;
gap: 4px;
width: 32px;
height: 32px;
justify-content: center;
}
.toggle-bar {
width: 100%;
height: 2px;
background: var(--primary-blue);
border-radius: 2px;
transition: all 0.3s ease;
}
/* ========== SIDEBAR MÓVIL MEJORADO ========== */
.mobile-sidebar {
position: fixed;
top: 0;
left: -100%;
width: 320px;
height: 100vh;
background: var(--bg-white);
box-shadow: var(--shadow-hover);
transition: left 0.3s ease;
z-index: 1040;
display: flex;
flex-direction: column;
}
.mobile-sidebar.active {
left: 0;
}
.sidebar-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.5rem;
border-bottom: 1px solid var(--border-light);
}
.sidebar-close {
background: none;
border: none;
font-size: 1.25rem;
color: var(--text-light);
cursor: pointer;
padding: 0.25rem;
}
.sidebar-nav {
flex: 1;
padding: 1rem 0;
}
.sidebar-menu {
list-style: none;
margin: 0;
padding: 0;
}
.sidebar-item {
margin-bottom: 0.25rem;
}
.sidebar-link {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem 1.5rem;
color: var(--text-dark); /* Texto visible en ambos modos */
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
border-left: 3px solid transparent;
}
.sidebar-link i {
color: var(--primary-blue); /* ICONOS AZUL CLARO en ambos modos */
transition: all 0.3s ease;
}
/* HOVER EN SIDEBAR: SE PONEN BLANCOS en modo oscuro */
[data-theme="dark"] .sidebar-link:hover,
[data-theme="dark"] .sidebar-link.active {
background: var(--primary-blue);
color: white !important;
border-left-color: white;
}
[data-theme="dark"] .sidebar-link:hover i,
[data-theme="dark"] .sidebar-link.active i {
color: white !important;
}
/* Estilos normales para modo claro */
.sidebar-link:hover,
.sidebar-link.active {
background: var(--bg-light);
color: var(--primary-blue);
border-left-color: var(--primary-blue);
}
.sidebar-link:hover i,
.sidebar-link.active i {
color: var(--primary-blue);
}
.sidebar-divider {
height: 1px;
background: var(--border-light);
margin: 1rem 0;
}
.sidebar-footer {
padding: 1.5rem;
border-top: 1px solid var(--border-light);
}
.btn-agendar-sidebar {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 1rem;
background: linear-gradient(135deg, var(--primary-blue), var(--primary-blue-dark));
color: white;
border: none;
border-radius: 8px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-agendar-sidebar:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(26, 75, 140, 0.4);
}
.sidebar-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1035;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.sidebar-overlay.active {
opacity: 1;
visibility: visible;
}
/* Responsive */
@media (max-width: 1199.98px) {
.header-nav {
flex: 0.8;
}
}
@media (max-width: 991.98px) {
.header-content {
gap: 1rem;
}
.btn-text {
display: none;
}
.language-trigger {
width: 40px;
height: 40px;
}
.language-flag {
font-size: 1.2rem;
}
.language-chevron {
width: 12px;
height: 12px;
font-size: 0.5rem;
}
}
@media (max-width: 767.98px) {
.btn-agendar,
.btn-portal {
display: none;
}
.language-selector-wrapper {
order: -1;
}
}
@media (max-width: 575.98px) {
.header-profesional {
padding: 0.5rem 0;
}
.mobile-sidebar {
width: 280px;
}
.header-actions {
gap: 0.25rem;
}
.language-trigger {
width: 36px;
height: 36px;
}
.language-flag {
font-size: 1.1rem;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// ========== SELECTOR DE IDIOMA - CLIENTE MANDRA ==========
const languageTrigger = document.getElementById('languageTrigger');
const languageOptions = document.querySelectorAll('.language-option');
const currentLangFlag = languageTrigger.querySelector('.language-flag');
const languageWrapper = document.querySelector('.language-selector-wrapper');
// Definir las banderas SVG
const flagES = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 480'%3E%3Cpath fill='%23c60b1e' d='M0 0h640v480H0z'/%3E%3Cpath fill='%23ffc400' d='M0 120h640v240H0z'/%3E%3C/svg%3E";
const flagUS = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 480'%3E%3Cpath fill='%23bd3d44' d='M0 0h640v480H0z'/%3E%3Cpath stroke='%23fff' stroke-width='37' d='M0 55.3h640M0 129h640M0 203h640M0 277h640M0 351h640'/%3E%3Cpath fill='%23192f5d' d='M0 0h364.8v258.5H0z'/%3E%3Cpath fill='%23fff' d='m71 7 7 21.5L98 16l-12 17.5 21-2.5-14.5 16 19.5-7-16 13 16.5 12.5-20-1 12 18L89 57l6.5 20.5-15-15-2 21.5-9-19-10 19-1.5-21.5-15 15L43 57 29.5 68.5l12-18-20 1L38 39 22 52l19.5 7L27 42.5 48 45 36 27.5 50 33 35.5 17 57 24.5 36 16l15 12.5L71 7z'/%3E%3C/svg%3E";
// 1. PRIMERO: Obtener idioma del CLIENTE (localStorage)
const clientLang = localStorage.getItem('language') || 'es';
console.log('🚀 Idioma del CLIENTE:', clientLang);
// 2. INICIALIZAR con el idioma del cliente (NO siempre España)
initializeLanguageSelector(clientLang);
// 3. INMEDIATAMENTE: Aplicar idioma del cliente
applyLanguage(clientLang);
// 4. LUEGO: Sincronizar Symfony con el cliente (en segundo plano)
forceSymfonyLanguage(clientLang);
// Toggle del dropdown
languageTrigger.addEventListener('click', function(e) {
e.stopPropagation();
languageWrapper.classList.toggle('active');
});
// Cambiar idioma al seleccionar una opción
languageOptions.forEach(option => {
option.addEventListener('click', function() {
const lang = this.getAttribute('data-lang');
changeLanguage(lang);
});
});
// Cerrar dropdown al hacer clic fuera
document.addEventListener('click', function(e) {
if (!languageWrapper.contains(e.target)) {
languageWrapper.classList.remove('active');
}
});
// FUNCIÓN CORREGIDA: Inicializar con el idioma del cliente
function initializeLanguageSelector(lang) {
console.log('🎨 Inicializando banderas con idioma:', lang);
// Bandera inicial del trigger según el idioma guardado
if (lang === 'es') {
currentLangFlag.style.backgroundImage = `url("${flagES}")`;
} else {
currentLangFlag.style.backgroundImage = `url("${flagUS}")`;
}
// Configurar banderas de las opciones
languageOptions.forEach(option => {
const optionFlag = option.querySelector('.option-flag');
const optionLang = option.getAttribute('data-lang');
// Configurar bandera según cada opción
if (optionLang === 'es') {
optionFlag.style.backgroundImage = `url("${flagES}")`;
} else {
optionFlag.style.backgroundImage = `url("${flagUS}")`;
}
});
}
// FUNCIÓN PRINCIPAL: Cambiar idioma (CLIENTE MANDRA)
async function changeLanguage(lang) {
try {
console.log('🔥 FORZANDO idioma:', lang);
// 1. GUARDAR en localStorage (cliente)
localStorage.setItem('language', lang);
// 2. INICIALIZAR banderas con el nuevo idioma
initializeLanguageSelector(lang);
// 3. APLICAR INMEDIATAMENTE en frontend
applyLanguage(lang);
// 4. FORZAR a Symfony a aceptar nuestro idioma
await forceSymfonyLanguage(lang);
console.log('✅ Idioma forzado exitosamente:', lang);
} catch (error) {
console.error('❌ Error al forzar idioma:', error);
// IMPORTANTE: El frontend YA tiene el idioma correcto
} finally {
// Cerrar dropdown
languageWrapper.classList.remove('active');
}
}
// FUNCIÓN AGGRESIVA: Forzar idioma en Symfony
async function forceSymfonyLanguage(lang) {
try {
const response = await fetch('/change-language', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({
language: lang,
force: true,
source: 'client_override'
})
});
if (!response.ok) {
throw new Error('Symfony rechazó el idioma');
}
const result = await response.json();
console.log('🔄 Symfony sincronizado:', result);
} catch (error) {
console.warn('⚠️ Symfony no respondió, pero el frontend está ok');
}
}
// FUNCIÓN MEJORADA: Aplicar idioma (SIN DEPENDER DE SYMFONY)
function applyLanguage(lang) {
console.log('🎯 APLICANDO idioma del CLIENTE:', lang);
// 1. Bandera principal (ya está configurada en initializeLanguageSelector)
if (lang === 'es') {
languageTrigger.setAttribute('aria-label', 'Cambiar idioma a English');
} else {
languageTrigger.setAttribute('aria-label', 'Change language to Spanish');
}
// 2. Actualizar textos del DROPDOWN
updateDropdownTexts(lang);
// 3. Actualizar checkmarks en las opciones
languageOptions.forEach(option => {
const optionLang = option.getAttribute('data-lang');
if (optionLang === lang) {
option.classList.add('active');
} else {
option.classList.remove('active');
}
});
// 4. Actualizar TODOS los textos de la página
document.querySelectorAll('[data-lang]').forEach(element => {
// Excluir elementos dentro del language selector
if (element.closest('.language-selector-wrapper')) {
return;
}
const elementLang = element.getAttribute('data-lang');
const isNavText = element.classList.contains('nav-text');
const isBtnText = element.classList.contains('btn-text');
if (elementLang === lang) {
element.style.display = isNavText || isBtnText ? 'inline' : 'block';
} else {
element.style.display = 'none';
}
});
// 5. Forzar atributo HTML
document.documentElement.lang = lang;
// 6. Placeholders
updateDynamicPlaceholders(lang);
console.log('✅ Idioma del CLIENTE aplicado exitosamente');
}
// NUEVA FUNCIÓN: Actualizar textos del dropdown
function updateDropdownTexts(lang) {
languageOptions.forEach(option => {
const optionLang = option.getAttribute('data-lang');
const optionNames = option.querySelectorAll('.option-name');
optionNames.forEach(optionName => {
const nameLang = optionName.getAttribute('data-lang');
if (nameLang === lang) {
optionName.style.display = 'block';
} else {
optionName.style.display = 'none';
}
});
});
}
// Función para actualizar placeholders dinámicamente
function updateDynamicPlaceholders(lang) {
const placeholders = {
'es': {
'firstName': 'Tu nombre',
'lastName': 'Tus apellidos',
'age': 'Tu edad',
'phone': '+15555555555',
'email': 'ejemplo@dominio.com',
'observaciones': 'Información adicional que consideres relevante'
},
'en': {
'firstName': 'Your name',
'lastName': 'Your last name',
'age': 'Your age',
'phone': '+15555555555',
'email': 'example@domain.com',
'observaciones': 'Additional information you consider relevant'
}
};
const currentPlaceholders = placeholders[lang] || placeholders['es'];
Object.keys(currentPlaceholders).forEach(fieldId => {
const element = document.getElementById(fieldId);
if (element) {
element.placeholder = currentPlaceholders[fieldId];
}
});
}
// ========== FUNCIONALIDAD: MODO OSCURO ==========
const themeToggle = document.getElementById('themeToggle');
const themeIcon = themeToggle.querySelector('.theme-icon');
const html = document.documentElement;
// Verificar preferencia guardada
const savedTheme = localStorage.getItem('theme') || 'light';
// Aplicar tema al cargar
applyTheme(savedTheme);
// Toggle del tema
themeToggle.addEventListener('click', function() {
const currentTheme = html.getAttribute('data-theme') || 'light';
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
applyTheme(newTheme);
localStorage.setItem('theme', newTheme);
});
function applyTheme(theme) {
html.setAttribute('data-theme', theme);
if (theme === 'dark') {
themeIcon.className = 'bi bi-moon-fill theme-icon';
themeToggle.setAttribute('aria-label', 'Cambiar a modo claro');
} else {
themeIcon.className = 'bi bi-sun-fill theme-icon';
themeToggle.setAttribute('aria-label', 'Cambiar a modo oscuro');
}
updateLogoForDarkMode();
}
function updateLogoForDarkMode() {
const logos = document.querySelectorAll('.logo-img[data-logo-dark]');
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
const isDarkMode = currentTheme === 'dark';
logos.forEach(logo => {
const darkSrc = logo.getAttribute('data-logo-dark');
const lightSrc = logo.getAttribute('data-logo-light') || logo.src;
if (isDarkMode && darkSrc) {
logo.src = darkSrc;
} else if (lightSrc) {
logo.src = lightSrc;
}
});
}
updateLogoForDarkMode();
// ========== FUNCIONALIDAD EXISTENTE DEL HEADER ==========
const mobileToggle = document.querySelector('.mobile-toggle');
const sidebarClose = document.querySelector('.sidebar-close');
const mobileSidebar = document.querySelector('.mobile-sidebar');
const sidebarOverlay = document.querySelector('.sidebar-overlay');
mobileToggle?.addEventListener('click', function() {
mobileSidebar.classList.add('active');
sidebarOverlay.classList.add('active');
document.body.style.overflow = 'hidden';
});
function closeSidebar() {
mobileSidebar.classList.remove('active');
sidebarOverlay.classList.remove('active');
document.body.style.overflow = '';
}
sidebarClose?.addEventListener('click', closeSidebar);
sidebarOverlay?.addEventListener('click', closeSidebar);
document.querySelectorAll('.sidebar-link').forEach(link => {
link.addEventListener('click', closeSidebar);
});
let lastScroll = 0;
const header = document.querySelector('.header-profesional');
window.addEventListener('scroll', function() {
const currentScroll = window.pageYOffset;
if (currentScroll <= 0) {
header.style.transform = 'translateY(0)';
return;
}
if (currentScroll > lastScroll && currentScroll > 100) {
header.style.transform = 'translateY(-100%)';
} else {
header.style.transform = 'translateY(0)';
}
lastScroll = currentScroll;
});
});
</script>