| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896 |
- // Initialize particles.js
- if (typeof particlesJS !== 'undefined' && document.getElementById('particles-js')) {
- particlesJS('particles-js', particlesConfig);
- }
- // Load SVG icon sprites
- (function loadIconSprite() {
- const script = document.createElement('script');
- script.src = 'assets/data/icons-sprite.js';
- script.async = false;
- document.head.appendChild(script);
- })();
- // Initialize all components when DOM loads
- document.addEventListener('DOMContentLoaded', async function() {
- try {
- // Load services data for Typed.js
- if (typeof Typed !== 'undefined' && document.getElementById('typed-element')) {
- try {
- // Initialize Typed.js
- const typed = new Typed('#typed-element', {
- strings: servicesData.services,
- typeSpeed: servicesData.typewriterConfig.typeSpeed,
- backSpeed: servicesData.typewriterConfig.deleteSpeed,
- startDelay: 1500,
- backDelay: servicesData.typewriterConfig.deleteDelay,
- loop: servicesData.typewriterConfig.loop,
- showCursor: servicesData.typewriterConfig.showCursor,
- cursorChar: servicesData.typewriterConfig.cursorChar,
- autoInsertCss: true,
- });
- window.serviceTyped = typed;
- } catch (error) {
- // Fallback with default strings
- const typed = new Typed('#typed-element', {
- strings: ['Web Development', 'Digital Marketing', 'SEO Optimization'],
- typeSpeed: 50,
- backSpeed: 30,
- backDelay: 1500,
- loop: true,
- showCursor: true,
- cursorChar: '|'
- });
- window.serviceTyped = typed;
- }
- }
- // Initialize Portfolio
- initPortfolioIsotope();
- // Refresh AOS
- setTimeout(() => {
- if (typeof AOS !== 'undefined') {
- AOS.refresh();
- }
- }, 100);
-
- } catch (error) {
- // Initialize AOS as fallback
- try {
- if (typeof AOS !== 'undefined') {
- AOS.init({
- duration: 800,
- delay: 100,
- once: false,
- mirror: true,
- offset: 50,
- easing: 'ease-out-cubic'
- });
- }
- } catch (aosError) {
- // Silent fail
- }
- }
- });
- /**
- * Enhanced portfolio initialization function
- */
- function initPortfolioIsotope() {
- const portfolioGrid = document.querySelector('.portfolio-grid');
- const filterButtons = document.querySelectorAll('.filter-btn');
-
- if (!portfolioGrid) {
- return;
- }
-
- if (filterButtons.length === 0) {
- console.warn('⚠️ No filter buttons found');
- return;
- }
-
- // Wait for images to load
- waitForImages(portfolioGrid).then(() => {
-
- // Create CustomIsotope instance
- const customIsotope = new CustomIsotope(portfolioGrid, {
- itemSelector: '.portfolio-item',
- gutter: 24, // Match your CSS gap
- transitionDuration: 500,
- hiddenStyle: {
- opacity: 0,
- transform: 'scale(0.9) translateY(20px)'
- },
- visibleStyle: {
- opacity: 1,
- transform: 'scale(1) translateY(0px)'
- }
- });
-
- // Store instance globally
- window.portfolioIsotope = customIsotope;
- window.customIsotope = customIsotope; // Additional alias
-
- // Setup filter buttons
- setupFilterButtons(customIsotope, filterButtons);
-
- // Refresh AOS after initial layout
- setTimeout(() => {
- if (typeof AOS !== 'undefined') {
- AOS.refresh();
- }
- }, 1000);
-
- }).catch(error => {
- console.error('❌ Error loading images:', error);
- // Initialize anyway after timeout
- setTimeout(() => {
- const customIsotope = new CustomIsotope(portfolioGrid);
- window.portfolioIsotope = customIsotope;
- setupFilterButtons(customIsotope, filterButtons);
- }, 1000);
- });
- }
- // Typed.js control functions
- function pauseTyping() {
- if (window.serviceTyped) {
- window.serviceTyped.stop();
- }
- }
- function resumeTyping() {
- if (window.serviceTyped) {
- window.serviceTyped.start();
- }
- }
- function resetTyping() {
- if (window.serviceTyped) {
- window.serviceTyped.reset();
- }
- }
- // AOS control functions
- function refreshAOS() {
- if (typeof AOS !== 'undefined') {
- AOS.refresh();
- }
- }
- function disableAOS() {
- if (typeof AOS !== 'undefined') {
- AOS.init({ disable: true });
- }
- }
- function enableAOS() {
- if (typeof AOS !== 'undefined') {
- AOS.init({
- duration: 800,
- delay: 100,
- once: false,
- mirror: true,
- offset: 50,
- easing: 'ease-out-cubic'
- });
- }
- }
- // Handle page visibility changes
- document.addEventListener('visibilitychange', function() {
- if (document.hidden) {
- pauseTyping();
- } else {
- resumeTyping();
- refreshAOS();
- }
- });
- // Expose utility functions globally
- window.AOSUtils = {
- refresh: refreshAOS,
- disable: disableAOS,
- enable: enableAOS
- };
- window.TypingUtils = {
- pause: pauseTyping,
- resume: resumeTyping,
- reset: resetTyping
- };
- // ==========================================================================
- // RESPONSIVE HEADER
- // ==========================================================================
- function initResponsiveHeader() {
- const header = document.querySelector('.header');
- const mobileMenuToggle = document.getElementById('mobile-menu-toggle');
- const navbar = document.getElementById('navbar');
- const body = document.body;
- const dropdownToggles = document.querySelectorAll('.dropdown-toggle');
- const dropdownMenus = document.querySelectorAll('.dropdown-menu');
- if (!header || !mobileMenuToggle || !navbar) return;
- // Funciones del menú móvil
- function openMobileMenu() {
- navbar.classList.add('mobile-menu-open');
- mobileMenuToggle.classList.add('active');
- body.style.overflow = 'hidden';
- }
- function closeMobileMenu() {
- navbar.classList.remove('mobile-menu-open');
- mobileMenuToggle.classList.remove('active');
- body.style.overflow = '';
- closeAllDropdowns();
- }
- function toggleMobileMenu() {
- if (navbar.classList.contains('mobile-menu-open')) {
- closeMobileMenu();
- } else {
- openMobileMenu();
- }
- }
- // Event listeners del menú móvil
- mobileMenuToggle.addEventListener('click', function(e) {
- e.preventDefault();
- e.stopPropagation();
- toggleMobileMenu();
- });
- document.addEventListener('click', function(e) {
- const isClickInsideMenu = navbar.contains(e.target);
- const isClickOnToggle = mobileMenuToggle.contains(e.target);
-
- if (!isClickInsideMenu && !isClickOnToggle && navbar.classList.contains('mobile-menu-open')) {
- closeMobileMenu();
- }
- });
- const navLinks = document.querySelectorAll('.nav-link');
- navLinks.forEach(link => {
- link.addEventListener('click', function() {
- if (window.innerWidth <= 992) {
- closeMobileMenu();
- }
- });
- });
- function closeAllDropdowns() {
- dropdownMenus.forEach(menu => {
- menu.classList.remove('dropdown-open');
- });
- dropdownToggles.forEach(toggle => {
- toggle.classList.remove('active');
- });
- }
- function toggleDropdown(dropdownId, toggleElement) {
- const dropdownMenu = document.getElementById(dropdownId);
-
- if (!dropdownMenu) return;
- const isOpen = dropdownMenu.classList.contains('dropdown-open');
- closeAllDropdowns();
-
- if (!isOpen) {
- dropdownMenu.classList.add('dropdown-open');
- toggleElement.classList.add('active');
- }
- }
- // Event listeners de dropdown
- dropdownToggles.forEach(toggle => {
- toggle.addEventListener('click', function(e) {
- e.preventDefault();
- e.stopPropagation();
-
- const dropdownId = this.getAttribute('data-dropdown');
- toggleDropdown(dropdownId, this);
- });
- });
- document.addEventListener('click', function(e) {
- if (window.innerWidth <= 992) {
- const isClickInsideDropdown = Array.from(dropdownMenus).some(menu =>
- menu.contains(e.target)
- );
- const isClickOnToggle = Array.from(dropdownToggles).some(toggle =>
- toggle.contains(e.target)
- );
-
- if (!isClickInsideDropdown && !isClickOnToggle) {
- closeAllDropdowns();
- }
- }
- });
- const dropdownItems = document.querySelectorAll('.dropdown-item');
- dropdownItems.forEach(item => {
- item.addEventListener('click', function() {
- if (window.innerWidth <= 992) {
- closeAllDropdowns();
- closeMobileMenu();
- }
- });
- });
- function handleHeaderScroll() {
- if (window.scrollY > 100) {
- header.classList.add('header-scrolled');
- header.classList.remove('header-transparent');
- //修改logo
- var that= document.getElementById("lmdlogo");
- that.src="assets/images/lmdlogo/lmd22.png";
- } else {
- header.classList.remove('header-scrolled');
- header.classList.add('header-transparent');
- var that= document.getElementById("lmdlogo");
- that.src="assets/images/lmdlogo/lmd2.png";
- }
- }
- if (window.scrollY > 100) {
- header.classList.add('header-scrolled');
- } else {
- header.classList.add('header-transparent');
- }
- window.addEventListener('scroll', handleHeaderScroll);
- function handleWindowResize() {
- if (window.innerWidth > 992) {
- closeMobileMenu();
- closeAllDropdowns();
- }
- }
- window.addEventListener('resize', handleWindowResize);
- document.addEventListener('keydown', function(e) {
- if (e.key === 'Escape') {
- if (navbar.classList.contains('mobile-menu-open')) {
- closeMobileMenu();
- }
- closeAllDropdowns();
- }
- });
- }
- initResponsiveHeader();
- // ==========================================================================
- // CUSTOMERS CAROUSEL
- // ==========================================================================
- document.addEventListener('DOMContentLoaded', function() {
- if (typeof UniversalSlider !== 'undefined' && document.querySelector('.customers-carousel2')) {
- const customersSlider = new UniversalSlider('.customers-carousel2', {
- slidesPerView: {
- desktop: 3,
- tablet: 3,
- mobile: 2
- },
- slideBy: 1,
- breakpoints: {
- mobile: 576,
- tablet: 992
- },
- autoplay: true,
- autoplayDelay: 3000,
- pagination: false,
- arrows: false,
- loop: true,
- touchEnabled: true,
- });
- }
- });
- // ==========================================================================
- // NEWSLETTER FORM SUBMISSION
- // ==========================================================================
- const newsletterForm = document.getElementById('newsletterForm');
- if (newsletterForm) {
- newsletterForm.addEventListener('submit', function(e) {
- e.preventDefault();
- const checkbox = this.querySelector('input[name="newsletter-agreement"]');
-
- if (checkbox && !checkbox.checked) {
- alert('Please agree to the Privacy Policy');
- return;
- }
-
- alert('Thank you for subscribing to our newsletter!');
- this.reset();
- });
- }
- // ==========================================================================
- // SCROLL TO TOP FUNCTIONALITY
- // ==========================================================================
- const scrollToTop = document.getElementById('scrollToTop');
- if (scrollToTop) {
- window.addEventListener('scroll', function() {
- if (window.pageYOffset > 300) {
- scrollToTop.classList.add('show');
- } else {
- scrollToTop.classList.remove('show');
- }
- });
- scrollToTop.addEventListener('click', function() {
- window.scrollTo({
- top: 0,
- behavior: 'smooth'
- });
- });
- }
- // Smooth scrolling for footer links
- document.querySelectorAll('.footer-link[href^="#"]').forEach(link => {
- link.addEventListener('click', function(e) {
- e.preventDefault();
- const target = document.querySelector(this.getAttribute('href'));
- if (target) {
- target.scrollIntoView({
- behavior: 'smooth',
- block: 'start'
- });
- }
- });
- });
- /**
- * Page Loader Controller - MultiIT
- * Handles the loading screen until all resources are loaded
- */
- class PageLoader {
- constructor() {
- this.loader = document.getElementById('page-loader');
- this.progressBar = document.querySelector('.progress-bar');
- this.isLoaded = false;
- this.minLoadTime = 1500; // Minimum loading time in ms
- this.maxLoadTime = 8000; // Maximum loading time in ms (fallback)
- this.startTime = Date.now();
- this.currentProgress = 0;
- this.loadingSteps = [];
- this.completedSteps = 0;
-
- // Only initialize if loader exists
- if (this.loader) {
- this.init();
- } else {
- console.warn('MultiIT Loader: #page-loader element not found');
- }
- }
- init() {
- try {
- // Add loading class to body
- document.body.classList.add('loading');
-
- // Start progress animation
- this.animateProgress();
-
- // Wait for page to load completely
- this.waitForPageLoad();
-
- // Safety timeout to prevent infinite loading
- this.setSafetyTimeout();
-
- } catch (error) {
- this.forceHide();
- }
- }
- waitForPageLoad() {
- const promises = [];
-
- // Wait for DOM to be ready
- if (document.readyState === 'loading') {
- promises.push(new Promise(resolve => {
- document.addEventListener('DOMContentLoaded', resolve, { once: true });
- this.loadingSteps.push('DOM Content Loaded');
- }));
- }
-
- // Wait for all resources (images, CSS, JS) to load
- if (document.readyState !== 'complete') {
- promises.push(new Promise(resolve => {
- window.addEventListener('load', resolve, { once: true });
- this.loadingSteps.push('Window Load');
- }));
- }
-
- // Wait for all images to load
- promises.push(this.waitForImages());
- this.loadingSteps.push('Images Loaded');
-
- // Wait for fonts to load (if using web fonts)
- if (document.fonts && document.fonts.ready) {
- promises.push(document.fonts.ready.catch(() => {
- console.warn('MultiIT Loader: Fonts failed to load');
- }));
- this.loadingSteps.push('Fonts Loaded');
- }
- // Wait for critical CSS to load
- promises.push(this.waitForCriticalAssets());
- this.loadingSteps.push('Critical Assets');
-
- // Execute when everything is loaded
- Promise.allSettled(promises).then((results) => {
- // Log any failed promises
- results.forEach((result, index) => {
- if (result.status === 'rejected') {
- console.warn(`MultiIT Loader: Step "${this.loadingSteps[index]}" failed:`, result.reason);
- }
- });
-
- this.isLoaded = true;
- this.checkMinimumLoadTime();
- });
- }
- waitForImages() {
- return new Promise(resolve => {
- const images = document.querySelectorAll('img[src], img[data-src]');
-
- if (images.length === 0) {
- resolve();
- return;
- }
-
- let loadedImages = 0;
- const totalImages = images.length;
-
- const imagePromises = Array.from(images).map((img, index) => {
- return new Promise(imageResolve => {
- const handleImageLoad = () => {
- loadedImages++;
- // Update progress based on image loading
- const imageProgress = (loadedImages / totalImages) * 30; // Images contribute 30% to progress
- this.updateProgressStep(imageProgress);
- imageResolve();
- };
- if (img.complete && img.naturalHeight !== 0) {
- handleImageLoad();
- } else {
- img.addEventListener('load', handleImageLoad, { once: true });
- img.addEventListener('error', () => {
- console.warn(`MultiIT Loader: Image failed to load: ${img.src || img.dataset.src}`);
- handleImageLoad(); // Continue even if image fails
- }, { once: true });
-
- // Timeout fallback for stuck images
- setTimeout(handleImageLoad, 3000);
- }
- });
- });
-
- Promise.all(imagePromises).then(resolve);
- });
- }
- waitForCriticalAssets() {
- return new Promise(resolve => {
- // Check for critical CSS files
- const criticalStylesheets = document.querySelectorAll('link[rel="stylesheet"][href*="critical"], link[rel="stylesheet"][href*="main"]');
-
- if (criticalStylesheets.length === 0) {
- resolve();
- return;
- }
- let loadedSheets = 0;
- const totalSheets = criticalStylesheets.length;
- criticalStylesheets.forEach(sheet => {
- if (sheet.sheet) {
- loadedSheets++;
- if (loadedSheets === totalSheets) resolve();
- } else {
- sheet.addEventListener('load', () => {
- loadedSheets++;
- if (loadedSheets === totalSheets) resolve();
- }, { once: true });
-
- sheet.addEventListener('error', () => {
- console.warn('MultiIT Loader: Critical stylesheet failed to load:', sheet.href);
- loadedSheets++;
- if (loadedSheets === totalSheets) resolve();
- }, { once: true });
- }
- });
- // Timeout fallback
- setTimeout(resolve, 2000);
- });
- }
- setSafetyTimeout() {
- setTimeout(() => {
- if (!this.isLoaded) {
- this.isLoaded = true;
- this.checkMinimumLoadTime();
- }
- }, this.maxLoadTime);
- }
- checkMinimumLoadTime() {
- const elapsed = Date.now() - this.startTime;
- const remaining = Math.max(0, this.minLoadTime - elapsed);
-
- // Complete progress bar
- this.setProgress(100);
-
- setTimeout(() => {
- this.hideLoader();
- }, remaining);
- }
- animateProgress() {
- const progressInterval = setInterval(() => {
- if (this.isLoaded) {
- this.setProgress(100);
- clearInterval(progressInterval);
- return;
- }
-
- // More realistic progress simulation
- const increment = Math.random() * 8 + 2; // 2-10% increments
- this.currentProgress = Math.min(this.currentProgress + increment, 85);
- this.setProgress(this.currentProgress);
-
- if (this.currentProgress >= 85) {
- clearInterval(progressInterval);
- }
- }, 300);
- }
- updateProgressStep(stepProgress) {
- // Update progress based on completed steps
- const baseProgress = (this.completedSteps / this.loadingSteps.length) * 70;
- this.currentProgress = Math.min(baseProgress + stepProgress, 90);
- this.setProgress(this.currentProgress);
- }
- setProgress(percentage) {
- if (this.progressBar) {
- // Smooth progress animation
- this.progressBar.style.width = `${Math.min(100, Math.max(0, percentage))}%`;
- }
- }
- hideLoader() {
- if (!this.loader) return;
-
- const loadTime = Date.now() - this.startTime;
- // Add loaded class for animation
- this.loader.classList.add('loaded');
- document.body.classList.remove('loading');
- document.body.classList.add('loaded');
-
- // Remove loader from DOM after animation
- setTimeout(() => {
- if (this.loader && this.loader.parentNode) {
- this.loader.parentNode.removeChild(this.loader);
- }
- }, 800);
-
- // Trigger custom event for other scripts
- this.dispatchLoadedEvent(loadTime);
- }
- dispatchLoadedEvent(loadTime) {
- try {
- const event = new CustomEvent('pageLoaded', {
- detail: {
- loadTime,
- timestamp: Date.now(),
- userAgent: navigator.userAgent,
- connection: navigator.connection ? {
- effectiveType: navigator.connection.effectiveType,
- downlink: navigator.connection.downlink
- } : null
- }
- });
- window.dispatchEvent(event);
- } catch (error) {
- console.warn('MultiIT Loader: Failed to dispatch pageLoaded event', error);
- }
- }
- // Public method to force hide loader
- forceHide() {
- this.isLoaded = true;
- this.hideLoader();
- }
- // Public method to show loader (for dynamic content loading)
- show() {
- if (this.loader) {
- this.loader.classList.remove('loaded');
- document.body.classList.add('loading');
- document.body.classList.remove('loaded');
- this.currentProgress = 0;
- this.setProgress(0);
- }
- }
- // Public method to update progress manually
- updateProgress(percentage) {
- this.setProgress(percentage);
- }
- }
- /* ========================================
- INITIALIZATION
- ======================================== */
- let pageLoader;
- function initializePageLoader() {
- try {
- pageLoader = new PageLoader();
- } catch (error) {
- console.error('MultiIT Loader: Failed to initialize', error);
- }
- }
- // Start immediately if DOM is already ready, otherwise wait
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', initializePageLoader, { once: true });
- } else {
- initializePageLoader();
- }
- /* ========================================
- GLOBAL LOADER API
- ======================================== */
- // Enhanced global API
- window.MultiITLoader = {
- hide: () => pageLoader?.forceHide(),
- show: () => pageLoader?.show(),
- setProgress: (percentage) => pageLoader?.updateProgress(percentage),
- isLoaded: () => pageLoader?.isLoaded || false,
- getInstance: () => pageLoader
- };
- /* ========================================
- EVENT LISTENERS
- ======================================== */
- // Listen for page loaded event with enhanced logging
- window.addEventListener('pageLoaded', (event) => {
- const { loadTime, connection } = event.detail;
- const connectionInfo = connection ? `(${connection.effectiveType}, ${connection.downlink}Mbps)` : '';
- });
- // ✅ Inicializar AOS cuando el loader termine
- window.addEventListener('pageLoaded', () => {
- if (typeof AOS !== 'undefined') {
- AOS.init({
- duration: 800,
- delay: 100,
- once: false,
- mirror: true,
- offset: 50,
- easing: 'ease-out-cubic'
- });
- }
- });
- // Handle page visibility change (when user switches tabs)
- document.addEventListener('visibilitychange', () => {
- if (document.visibilityState === 'visible' && pageLoader) {
- // Page became visible again, ensure loader behavior is correct
- setTimeout(() => {
- if (pageLoader && document.readyState === 'complete') {
- pageLoader.forceHide();
- }
- }, 100);
- }
- });
- // Handle network connection changes (if supported)
- if (navigator.connection) {
- navigator.connection.addEventListener('change', () => {
- if (pageLoader && !pageLoader.isLoaded) {
- }
- });
- }
- // Handle errors globally
- window.addEventListener('error', (event) => {
- return;
- });
- // Performance timing
- window.addEventListener('load', () => {
- if (window.performance) {
- try {
- // Método moderno con Navigation Timing API Level 2
- if (performance.getEntriesByType && performance.getEntriesByType('navigation').length > 0) {
- const navigationEntry = performance.getEntriesByType('navigation')[0];
- }
- // Fallback para navegadores que no soportan Navigation Timing Level 2
- else if (performance.timing) {
- // Solo usar si es absolutamente necesario para compatibilidad
- const timing = performance.timing;
- const loadTime = timing.loadEventEnd - timing.fetchStart;
- }
- } catch (error) {
- console.warn('MultiIt Performance: Could not measure performance timing', error);
- }
- }
- });
- // --- THEME SWITCHER LOGIC ---
- // Wait for the initial HTML document to be completely loaded and parsed
- document.addEventListener('DOMContentLoaded', () => {
- // Select the DOM elements
- const themeToggleBtn = document.getElementById('theme-toggle');
- const themeToggleDarkIcon = document.getElementById('theme-toggle-dark-icon');
- const themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
- // Function to update the visibility of the icons
- const updateIcons = (isDarkMode) => {
- if (isDarkMode) {
- // If dark mode is active, show the light mode icon (sun)
- themeToggleDarkIcon.classList.add('hidden');
- themeToggleLightIcon.classList.remove('hidden');
- } else {
- // Otherwise, show the dark mode icon (moon)
- themeToggleDarkIcon.classList.remove('hidden');
- themeToggleLightIcon.classList.add('hidden');
- }
- };
- // Checks for a saved theme, defaulting to light mode.
- const applyInitialTheme = () => {
- // The new logic: The theme is light by default, and dark ONLY if explicitly saved as 'dark'.
- if (localStorage.getItem('theme') === 'dark') {
- document.body.classList.add('dark-mode');
- updateIcons(true);
- } else {
- // For all other cases (first visit or theme saved as 'light'), default to light mode.
- document.body.classList.remove('dark-mode');
- updateIcons(false);
- }
- };
- // Only add the event listener if the toggle button exists on the page
- if (themeToggleBtn) {
- themeToggleBtn.addEventListener('click', () => {
- // Toggle the 'dark-mode' class on the body.
- // .toggle() returns true if the class was added, false if removed.
- const isDarkMode = document.body.classList.toggle('dark-mode');
- // Save the user's preference to localStorage
- if (isDarkMode) {
- localStorage.setItem('theme', 'dark');
- } else {
- localStorage.setItem('theme', 'light');
- }
- // Update the button's icon to reflect the new state
- updateIcons(isDarkMode);
- });
- }
- applyInitialTheme();
- });
|