From f5260e0817c1172e680970ea03f703f2a7a47676 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Wed, 4 Mar 2026 10:12:42 -0800 Subject: [PATCH] feat: move dark/light mode toggle to user profile dropdown Replaced the dark mode checkbox in the My Account modal with a sun/moon toggle directly in the profile dropdown menu. Sun on the left, moon on the right, with a colored slider (amber for light, indigo for dark). Co-Authored-By: Claude Opus 4.6 --- shared/components/rstack-identity.ts | 68 ++++++++++++++++++---------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/shared/components/rstack-identity.ts b/shared/components/rstack-identity.ts index 6c272d8..a7dedb0 100644 --- a/shared/components/rstack-identity.ts +++ b/shared/components/rstack-identity.ts @@ -342,6 +342,15 @@ export class RStackIdentity extends HTMLElement { + + @@ -374,6 +383,17 @@ export class RStackIdentity extends HTMLElement { } }); }); + + const dropdownTheme = this.#shadow.getElementById("dropdown-theme-toggle") as HTMLInputElement; + if (dropdownTheme) { + dropdownTheme.addEventListener("click", (e) => e.stopPropagation()); + dropdownTheme.addEventListener("change", () => { + const newTheme = dropdownTheme.checked ? "dark" : "light"; + localStorage.setItem("canvas-theme", newTheme); + document.documentElement.setAttribute("data-theme", newTheme); + this.dispatchEvent(new CustomEvent("theme-change", { bubbles: true, composed: true, detail: { theme: newTheme } })); + }); + } } else { this.#shadow.innerHTML = ` @@ -676,17 +696,7 @@ export class RStackIdentity extends HTMLElement { } - - -
+
`; attachListeners(); @@ -1150,18 +1160,6 @@ export class RStackIdentity extends HTMLElement { }); } - // Dark Mode toggle - const themeToggle = overlay.querySelector("#acct-theme-toggle") as HTMLInputElement; - if (themeToggle) { - themeToggle.addEventListener("change", (e) => { - e.stopPropagation(); - const newTheme = themeToggle.checked ? "dark" : "light"; - localStorage.setItem("canvas-theme", newTheme); - document.documentElement.setAttribute("data-theme", newTheme); - this.dispatchEvent(new CustomEvent("theme-change", { bubbles: true, composed: true, detail: { theme: newTheme } })); - this.#render(); - }); - } }; document.body.appendChild(overlay); @@ -1368,6 +1366,30 @@ const STYLES = ` .dropdown-divider { height: 1px; margin: 4px 0; } .dropdown-divider { background: var(--rs-border-subtle); } +/* Theme toggle in dropdown */ +.dropdown-theme-row { + display: flex; align-items: center; justify-content: center; + gap: 10px; padding: 8px 16px; +} +.theme-icon { font-size: 0.9rem; line-height: 1; } +.theme-toggle { + position: relative; width: 40px; height: 22px; + display: inline-block; flex-shrink: 0; +} +.theme-toggle input { opacity: 0; width: 0; height: 0; } +.theme-slider { + position: absolute; inset: 0; border-radius: 11px; + background: #fbbf24; cursor: pointer; transition: background 0.25s; +} +.theme-slider::before { + content: ""; position: absolute; + width: 18px; height: 18px; border-radius: 50%; + left: 2px; bottom: 2px; background: white; + transition: transform 0.25s; +} +.theme-toggle input:checked + .theme-slider { background: #6366f1; } +.theme-toggle input:checked + .theme-slider::before { transform: translateX(18px); } + /* Avatar wrapper + notification badge */ .avatar-wrap { position: relative; } .notif-badge {