← back to Dw Theme Toggle

snippets/theme-toggle.liquid

98 lines

{%- comment -%}
  DW Theme Toggle — sun/moon button in upper-right corner of every page.
  Drop this snippet into theme.liquid, just inside <head>:
      {% render 'theme-toggle' %}
  Self-contained — no other edits required.
{%- endcomment -%}
<script>
  /* Anti-flash: set data-theme on <html> before paint so the page never flashes the wrong theme on reload. */
  (function () {
    try {
      var saved = localStorage.getItem('dw-theme');
      if (!saved) {
        saved = (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) ? 'light' : 'dark';
      }
      document.documentElement.setAttribute('data-theme', saved);
    } catch (e) {
      document.documentElement.setAttribute('data-theme', 'dark');
    }
  })();
</script>
<style>
  /* Toggle button — upper-right of viewport, sticky so it floats over the header on every page. */
  .dw-theme-toggle {
    position: fixed; top: 14px; right: 16px;
    width: 38px; height: 38px; border-radius: 50%;
    background: rgba(0,0,0,0.45); color: #fff;
    border: 1px solid rgba(255,255,255,0.22);
    cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
    font-size: 16px; line-height: 1; padding: 0;
    transition: background 200ms, transform 200ms, color 200ms, border-color 200ms;
    backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
    z-index: 99999;
  }
  .dw-theme-toggle:hover { background: rgba(0,0,0,0.65); transform: scale(1.06); }
  .dw-theme-toggle:focus-visible { outline: 2px solid #DDAB1E; outline-offset: 2px; }
  .dw-theme-toggle .dw-icon-sun  { display: none; }
  .dw-theme-toggle .dw-icon-moon { display: inline; }

  /* LIGHT theme — invert page colors but double-invert images/video so they stay correct.
     This works on any Shopify theme without needing to know the theme's specific CSS vars. */
  html[data-theme="light"] body {
    filter: invert(1) hue-rotate(180deg);
    background: #f5f1e8;
  }
  html[data-theme="light"] img,
  html[data-theme="light"] video,
  html[data-theme="light"] picture,
  html[data-theme="light"] svg,
  html[data-theme="light"] iframe,
  html[data-theme="light"] [style*="background-image"],
  html[data-theme="light"] .product-card img,
  html[data-theme="light"] .product__media,
  html[data-theme="light"] .media,
  html[data-theme="light"] .image-bg,
  html[data-theme="light"] .dw-theme-toggle {
    filter: invert(1) hue-rotate(180deg);
  }
  html[data-theme="light"] .dw-theme-toggle {
    background: rgba(255,255,255,0.55); color: #0a0a0a; border-color: rgba(0,0,0,0.18);
  }
  html[data-theme="light"] .dw-theme-toggle:hover { background: rgba(255,255,255,0.78); }
  html[data-theme="light"] .dw-theme-toggle .dw-icon-sun  { display: inline; }
  html[data-theme="light"] .dw-theme-toggle .dw-icon-moon { display: none; }

  /* Mobile sizing */
  @media (max-width: 600px) {
    .dw-theme-toggle { top: 10px; right: 12px; width: 34px; height: 34px; font-size: 14px; }
  }
</style>
<script>
  /* Inject the toggle button as soon as DOM is ready, then wire the click handler. */
  (function () {
    function build() {
      if (document.getElementById('dw-theme-toggle')) return;
      var btn = document.createElement('button');
      btn.id = 'dw-theme-toggle';
      btn.type = 'button';
      btn.className = 'dw-theme-toggle';
      btn.setAttribute('aria-label', 'Toggle dark/light theme');
      btn.title = 'Toggle theme';
      btn.innerHTML = '<span class="dw-icon-moon" aria-hidden="true">🌙</span><span class="dw-icon-sun" aria-hidden="true">☀️</span>';
      btn.addEventListener('click', function () {
        var cur = document.documentElement.getAttribute('data-theme') || 'dark';
        var next = cur === 'dark' ? 'light' : 'dark';
        document.documentElement.setAttribute('data-theme', next);
        try { localStorage.setItem('dw-theme', next); } catch (e) {}
        btn.setAttribute('aria-label', 'Switch to ' + (next === 'dark' ? 'light' : 'dark') + ' theme');
      });
      document.body.appendChild(btn);
    }
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', build);
    } else {
      build();
    }
  })();
</script>