Replace light/dark switch with sun/moon icon button
Some checks failed
Repo Health / Access control (push) Failing after 2s
Repo Health / Release configuration (push) Has been skipped
Repo Health / Scripts governance (push) Has been skipped
Repo Health / Repository health (push) Has been skipped

- Remove toggle switch, Light/Dark labels, knob/track CSS
- Single button with sun (light) and moon (dark) FA icons
- Icons cross-fade with rotation transition on theme change
- Compact circular button matches FAB aesthetic
- Removed duplicate old switch CSS rules

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan Miller
2026-04-14 21:43:28 -05:00
parent 4e66562958
commit 2a7c173f7b
2 changed files with 65 additions and 94 deletions

View File

@@ -17064,7 +17064,7 @@ form .form-select {
display: flex; display: flex;
align-items: center; align-items: center;
gap: .5rem; gap: .5rem;
padding: calc(var(--padding-x, 0.25rem) * 2) calc(var(--padding-y, 0.25rem) * 3) calc(var(--padding-x, 0.25rem) * 2) calc(var(--padding-y, 0.25rem) * 8); padding: .4rem .6rem;
border-radius: 999px; border-radius: 999px;
border: none; border: none;
background: var(--muted-color, #6d757e); background: var(--muted-color, #6d757e);
@@ -17094,46 +17094,47 @@ form .form-select {
top: 1rem; top: 1rem;
} }
#mokoThemeFab .switch { /* Sun/Moon theme toggle button */
display: inline-flex; .theme-icon-btn {
display: flex;
align-items: center; align-items: center;
position: relative; justify-content: center;
width: 44px; width: 32px;
height: 24px; height: 32px;
background: var(--secondary-color, #e6ebf1bf); border: none;
transition: background .2s, border-color .2s; border-radius: 50%;
border-radius: var(--border-radius-xxl, 2rem); background: rgba(255,255,255,.15);
}
#mokoThemeFab .knob {
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
border-radius: var(--border-radius-xxl, 2rem);
background: var(--bs-body-bg, #fff);
box-shadow: var(--box-shadow, 0 .5rem 1rem #00000066);
transition: transform .2s ease;
}
#mokoThemeFab [role="switch"][aria-checked="true"] .knob {
transform: translateX(20px);
}
#mokoThemeFab [role="switch"][aria-checked="true"] .switch {
background: rgba(var(--secondary-color, #e6ebf1bf), .15);
}
button#mokoThemeSwitch {
border: unset;
background-color: unset;
}
#mokoThemeFab .label {
user-select: none;
font-size: .875rem;
color: #fff; color: #fff;
font-size: 1.1rem;
cursor: pointer;
padding: 0;
position: relative;
}
.theme-icon-btn .fa-sun,
.theme-icon-btn .fa-moon {
position: absolute;
transition: opacity .2s, transform .2s;
}
/* Light mode: show sun, hide moon */
.theme-icon-btn.is-light .fa-sun {
opacity: 1;
transform: rotate(0deg);
}
.theme-icon-btn.is-light .fa-moon {
opacity: 0;
transform: rotate(-90deg);
}
/* Dark mode: show moon, hide sun */
.theme-icon-btn.is-dark .fa-moon {
opacity: 1;
transform: rotate(0deg);
}
.theme-icon-btn.is-dark .fa-sun {
opacity: 0;
transform: rotate(90deg);
} }
/* Auto toggle switch (on/off style) */ /* Auto toggle switch (on/off style) */
@@ -17357,37 +17358,6 @@ body.site.error-page {
text-decoration: none; text-decoration: none;
} }
#mokoThemeFab .knob {
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
border-radius: var(--border-radius-xxl, 2rem);
background: var(--bs-body-bg, #fff);
box-shadow: var(--box-shadow, 0 .5rem 1rem #00000066);
transition: transform .2s ease;
}
#mokoThemeFab [role="switch"][aria-checked="true"] .knob {
transform: translateX(20px);
}
#mokoThemeFab [role="switch"][aria-checked="true"] .switch {
background: rgba(var(--secondary-color, #e6ebf1bf), .15);
}
button#mokoThemeSwitch {
border: unset;
background-color: unset;
}
#mokoThemeFab .label {
user-select: none;
font-size: .875rem;
color: #fff;
}
#mokoThemeFab.debug-outline { #mokoThemeFab.debug-outline {
outline: 2px dashed var(--pink, #ff8fc0); outline: 2px dashed var(--pink, #ff8fc0);
outline-offset: 2px; outline-offset: 2px;

View File

@@ -62,30 +62,33 @@
wrap.id = 'mokoThemeFab'; wrap.id = 'mokoThemeFab';
wrap.className = posClassFromBody(); wrap.className = posClassFromBody();
// Light label // Sun/Moon toggle button
var lblL = doc.createElement('span');
lblL.className = 'label';
lblL.textContent = 'Light';
// Switch
var switchWrap = doc.createElement('button'); var switchWrap = doc.createElement('button');
switchWrap.id = 'mokoThemeSwitch'; switchWrap.id = 'mokoThemeSwitch';
switchWrap.type = 'button'; switchWrap.type = 'button';
switchWrap.setAttribute('role', 'switch'); switchWrap.className = 'theme-icon-btn';
switchWrap.setAttribute('aria-label', 'Toggle dark mode'); switchWrap.setAttribute('aria-label', 'Toggle dark mode');
switchWrap.setAttribute('aria-checked', 'false');
var track = doc.createElement('span'); var sunIcon = doc.createElement('i');
track.className = 'switch'; sunIcon.className = 'fa-solid fa-sun';
var knob = doc.createElement('span'); sunIcon.setAttribute('aria-hidden', 'true');
knob.className = 'knob';
track.appendChild(knob);
switchWrap.appendChild(track);
// Dark label var moonIcon = doc.createElement('i');
var lblD = doc.createElement('span'); moonIcon.className = 'fa-solid fa-moon';
lblD.className = 'label'; moonIcon.setAttribute('aria-hidden', 'true');
lblD.textContent = 'Dark';
switchWrap.appendChild(sunIcon);
switchWrap.appendChild(moonIcon);
function updateThemeIcon(theme) {
if (theme === 'dark') {
switchWrap.classList.add('is-dark');
switchWrap.classList.remove('is-light');
} else {
switchWrap.classList.add('is-light');
switchWrap.classList.remove('is-dark');
}
}
// Auto toggle (on/off switch style) // Auto toggle (on/off switch style)
var autoWrap = doc.createElement('div'); var autoWrap = doc.createElement('div');
@@ -127,7 +130,7 @@
var current = (root.getAttribute('data-bs-theme') || 'light').toLowerCase(); var current = (root.getAttribute('data-bs-theme') || 'light').toLowerCase();
var next = current === 'dark' ? 'light' : 'dark'; var next = current === 'dark' ? 'light' : 'dark';
applyTheme(next); applyTheme(next);
switchWrap.setAttribute('aria-checked', next === 'dark' ? 'true' : 'false'); updateThemeIcon(next);
// Turn off auto when manually switching // Turn off auto when manually switching
auto.classList.remove('on'); auto.classList.remove('on');
auto.setAttribute('aria-checked', 'false'); auto.setAttribute('aria-checked', 'false');
@@ -145,7 +148,7 @@
clearStored(); clearStored();
var sys = systemTheme(); var sys = systemTheme();
applyTheme(sys); applyTheme(sys);
switchWrap.setAttribute('aria-checked', sys === 'dark' ? 'true' : 'false'); updateThemeIcon(sys);
} }
}); });
@@ -154,7 +157,7 @@
if (!getStored()) { if (!getStored()) {
var sys = systemTheme(); var sys = systemTheme();
applyTheme(sys); applyTheme(sys);
switchWrap.setAttribute('aria-checked', sys === 'dark' ? 'true' : 'false'); updateThemeIcon(sys);
} }
}; };
if (typeof mql.addEventListener === 'function') mql.addEventListener('change', onMql); if (typeof mql.addEventListener === 'function') mql.addEventListener('change', onMql);
@@ -162,12 +165,10 @@
// Initial state // Initial state
var initial = getStored() || systemTheme(); var initial = getStored() || systemTheme();
switchWrap.setAttribute('aria-checked', initial === 'dark' ? 'true' : 'false'); updateThemeIcon(initial);
// Mount // Mount
wrap.appendChild(lblL);
wrap.appendChild(switchWrap); wrap.appendChild(switchWrap);
wrap.appendChild(lblD);
wrap.appendChild(autoWrap); wrap.appendChild(autoWrap);
wrap.appendChild(divider); wrap.appendChild(divider);
wrap.appendChild(a11ySlot); wrap.appendChild(a11ySlot);