mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-03 20:48:07 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			144 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import { adjustColorForContrast } from '../shared/helpers/colorHelper.js';
 | 
						|
 | 
						|
const getResolvedTheme = theme => {
 | 
						|
  // Helper to get resolved theme (handles 'system' -> 'dark'/'light')
 | 
						|
  if (theme === 'system') {
 | 
						|
    return window.matchMedia('(prefers-color-scheme: dark)').matches
 | 
						|
      ? 'dark'
 | 
						|
      : 'light';
 | 
						|
  }
 | 
						|
  return theme;
 | 
						|
};
 | 
						|
 | 
						|
export const setPortalHoverColor = theme => {
 | 
						|
  // This function is to set the hover color for the portal
 | 
						|
  const resolvedTheme = getResolvedTheme(theme);
 | 
						|
  const portalColor = window.portalConfig.portalColor;
 | 
						|
  const bgColor = resolvedTheme === 'dark' ? '#151718' : 'white';
 | 
						|
  const hoverColor = adjustColorForContrast(portalColor, bgColor);
 | 
						|
 | 
						|
  // Set hover color for border and text dynamically
 | 
						|
  document.documentElement.style.setProperty(
 | 
						|
    '--dynamic-hover-color',
 | 
						|
    hoverColor
 | 
						|
  );
 | 
						|
};
 | 
						|
 | 
						|
export const removeQueryParamsFromUrl = (queryParam = 'theme') => {
 | 
						|
  // This function is to remove the theme query param from the URL
 | 
						|
  // This is done so that the theme is not persisted in the URL
 | 
						|
  // This is called when the theme is switched from the dropdown
 | 
						|
  const url = new URL(window.location.href);
 | 
						|
  const param = url.searchParams.get(queryParam);
 | 
						|
 | 
						|
  if (param) {
 | 
						|
    url.searchParams.delete(queryParam);
 | 
						|
    window.history.replaceState({}, '', url.toString()); // Convert URL to string
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
export const updateThemeInHeader = theme => {
 | 
						|
  // This function is to update the theme selection in the header in real time
 | 
						|
  const themeToggleButton = document.getElementById('toggle-appearance');
 | 
						|
  if (!themeToggleButton) return;
 | 
						|
 | 
						|
  const allThemeButtons = themeToggleButton.querySelectorAll('.theme-button');
 | 
						|
  if (!allThemeButtons.length) return;
 | 
						|
 | 
						|
  allThemeButtons.forEach(button => {
 | 
						|
    const isActive = button.dataset.theme === theme;
 | 
						|
    button.classList.toggle('hidden', !isActive);
 | 
						|
    button.classList.toggle('flex', isActive);
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
export const switchTheme = theme => {
 | 
						|
  // Update localStorage
 | 
						|
  if (theme === 'system') {
 | 
						|
    localStorage.removeItem('theme');
 | 
						|
  } else {
 | 
						|
    localStorage.theme = theme;
 | 
						|
  }
 | 
						|
 | 
						|
  const resolvedTheme = getResolvedTheme(theme);
 | 
						|
  document.documentElement.classList.remove('dark', 'light');
 | 
						|
  document.documentElement.classList.add(resolvedTheme);
 | 
						|
 | 
						|
  setPortalHoverColor(theme);
 | 
						|
  updateThemeInHeader(theme);
 | 
						|
  removeQueryParamsFromUrl();
 | 
						|
  // Update both dropdown data attributes
 | 
						|
  document.querySelectorAll('.appearance-menu').forEach(menu => {
 | 
						|
    menu.dataset.currentTheme = theme;
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
export const initializeThemeHandlers = () => {
 | 
						|
  const toggle = document.getElementById('toggle-appearance');
 | 
						|
  const dropdown = document.getElementById('appearance-dropdown');
 | 
						|
  if (!toggle || !dropdown) return;
 | 
						|
 | 
						|
  // Toggle appearance dropdown
 | 
						|
  toggle.addEventListener('click', e => {
 | 
						|
    e.stopPropagation();
 | 
						|
    dropdown.dataset.dropdownOpen = String(
 | 
						|
      dropdown.dataset.dropdownOpen !== 'true'
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  document.addEventListener('click', ({ target }) => {
 | 
						|
    if (toggle.contains(target)) return;
 | 
						|
 | 
						|
    const themeBtn = target.closest('.appearance-menu button[data-theme]');
 | 
						|
    const menu = themeBtn?.closest('.appearance-menu');
 | 
						|
 | 
						|
    if (themeBtn && menu) {
 | 
						|
      switchTheme(themeBtn.dataset.theme);
 | 
						|
      menu.dataset.dropdownOpen = 'false';
 | 
						|
 | 
						|
      if (menu.id === 'mobile-appearance-dropdown') {
 | 
						|
        // Set the mobile menu toggle to false after a delay to ensure the transition is completed
 | 
						|
        setTimeout(() => {
 | 
						|
          const mobileToggle = document.getElementById('mobile-menu-toggle');
 | 
						|
          if (mobileToggle) mobileToggle.checked = false;
 | 
						|
        }, 300);
 | 
						|
      }
 | 
						|
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    // Close the desktop appearance dropdown if clicked outside
 | 
						|
    if (
 | 
						|
      dropdown.dataset.dropdownOpen === 'true' &&
 | 
						|
      !dropdown.contains(target)
 | 
						|
    ) {
 | 
						|
      dropdown.dataset.dropdownOpen = 'false';
 | 
						|
    }
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
export const initializeMediaQueryListener = () => {
 | 
						|
  const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
 | 
						|
 | 
						|
  mediaQuery.addEventListener('change', () => {
 | 
						|
    if (['light', 'dark'].includes(localStorage.theme)) return;
 | 
						|
 | 
						|
    switchTheme('system');
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
export const initializeTheme = () => {
 | 
						|
  if (window.portalConfig.isPlainLayoutEnabled === 'true') return;
 | 
						|
  // start with updating the theme in the header, this will set the current theme on the button
 | 
						|
  // and set the hover color at the start of init, this is set again when the theme is switched
 | 
						|
  switchTheme(localStorage.theme || 'system');
 | 
						|
 | 
						|
  window.updateThemeInHeader = updateThemeInHeader;
 | 
						|
 | 
						|
  // add the event listeners for the dropdown toggle and theme buttons
 | 
						|
  initializeThemeHandlers();
 | 
						|
 | 
						|
  // add the media query listener to update the theme when the system theme changes
 | 
						|
  initializeMediaQueryListener();
 | 
						|
};
 |