Dark Light Switch

Hey guys,

I know it was discussed already, but I can’t make it to work.
I am using Typo theme.
I managed to add a switch button and it toggles the mode.
But I have a few problems:

  1. The site still cages its mode based on system
  2. Site does not remembers the mode, so when I go to a different page it switches to light
  3. I have logo (x2 images) dark and light it switches only when use system switch. When I use mu button no affect.

If you have time or had this issue before much appreciate you help.

Here is my custom darkmode-switch.html

<!-- layouts/partials/darkmode-switch.html -->
<button id="dark-mode-toggle" aria-label="Toggle dark mode">
    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <path class="sun" d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42M12 17.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11z"></path>
      <path class="moon" d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
    </svg>
  </button>
  
  <style>
    #dark-mode-toggle {
      background: none;
      border: none;
      padding: 0;
      color: inherit;
      cursor: pointer;
      margin-left: 0.5rem;
      vertical-align: middle;
    }
    
    #dark-mode-toggle .sun,
    #dark-mode-toggle .moon {
      display: none;
    }

    html[data-theme="light"] #dark-mode-toggle .moon {
      display: block;
    }
    html[data-theme="dark"] #dark-mode-toggle .sun {
      display: block;
    }
  </style>
  
  <script>
    const darkModeToggle = document.getElementById('dark-mode-toggle');
    
    darkModeToggle.addEventListener('click', () => {
      invertBody(); // This toggles body dark/light using Typo theme-switch.js
      updateTheme(); // Update logo and icons manually
    });
    
    function updateTheme() {
      const isDark = document.body.classList.contains('dark');
      const html = document.documentElement;
      html.setAttribute('data-theme', isDark ? 'dark' : 'light');
    
      // Also update logo
      const logoImg = document.querySelector('.header-title img');
      if (logoImg) {
        logoImg.src = isDark
          ? "{{ (resources.Get site.Params.logo.dark).RelPermalink }}"
          : "{{ (resources.Get site.Params.logo.light).RelPermalink }}";
      }
    }
    
    // When page loads, set correct theme
    document.addEventListener('DOMContentLoaded', updateTheme);
    </script>

and my header.html

{{/* Header */}}

<div class="header">

  {{ if or (not (.Param "hideHeader")) .IsHome }}

    <h1 class="header-title">
      <a href="{{ site.Home.RelPermalink }}">
        <picture>
          <source srcset="{{ (resources.Get site.Params.logo.dark).RelPermalink }}" media="(prefers-color-scheme: dark)">
          <source srcset="{{ (resources.Get site.Params.logo.light).RelPermalink }}" media="(prefers-color-scheme: light)">
          <img 
            src="{{ (resources.Get site.Params.logo.light).RelPermalink }}" 
            alt="{{ site.Params.logo.alt }}" 
            style="height: 200px; width:auto; margin-left: -15px;">
        </picture>
      </a>
    </h1>

  {{ end }}

  <div class="flex">
    {{ $currentPage := . }}
  
    {{ with site.Params.menu }}
    {{ range . }}
      <p class="small {{ if eq .name (lower $currentPage.Name) }} bold {{end}}">
        <a href="{{ .url }}" {{ if and (isset . "newTab") .newTab }}target="_blank" rel="noopener noreferrer"{{ end }}>
          /{{.name }}
        </a>
      </p>
    {{ end }}
    {{ end }}
  
    <p class="small">
      <a href="/about">/about</a>
      {{ partial "darkmode-switch.html" . }}
    </p>
  
  </div>


</div>

I don’t know if I’m on the right track here. However to my understanding the browser needs a way to know what theme you have it set to that is persistent. The only way I know of to do this is either via a cookie or localstorage. The latter speaking from personal experience is relatively simple and works well.