diff --git a/src/media/css/template.css b/src/media/css/template.css index 737af8e..0ff490b 100644 --- a/src/media/css/template.css +++ b/src/media/css/template.css @@ -13979,7 +13979,6 @@ meter { } .footer { - padding-top: var(--footer-padding-top, 1rem); color: var(--mainmenu-nav-link-color, #fff); background-color: var(--nav-bg-color); padding-bottom: var(--footer-padding-bottom, 80px); @@ -13994,7 +13993,6 @@ meter { -ms-flex-direction: column; flex-direction: column; width: 100%; - padding: var(--footer-grid-padding-y, 2.5rem) var(--footer-grid-padding-x, 0.5em); } .footer a { @@ -17141,6 +17139,107 @@ button#mokoThemeSwitch { color: var(--body-bg, #0e1318); } +/* Auto toggle switch (on/off style) */ +.auto-toggle-wrap { + display: flex; + align-items: center; + gap: .35rem; +} + +.auto-label { + font-size: .75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: .04em; + opacity: .7; + user-select: none; +} + +.auto-switch { + position: relative; + display: inline-flex; + align-items: center; + width: 32px; + height: 18px; + border: none; + border-radius: 999px; + background: var(--secondary-color, #6c757d); + cursor: pointer; + padding: 0; + transition: background .2s; +} + +.auto-switch.on { + background: var(--link-color, #3565e5); +} + +.auto-track { + position: relative; + width: 100%; + height: 100%; +} + +.auto-knob { + position: absolute; + top: 2px; + left: 2px; + width: 14px; + height: 14px; + border-radius: 50%; + background: #fff; + box-shadow: 0 1px 3px rgba(0,0,0,.3); + transition: transform .2s ease; +} + +.auto-switch.on .auto-knob { + transform: translateX(14px); +} + +/* FAB divider between theme controls and a11y */ +.fab-divider { + display: block; + width: 1px; + height: 24px; + background: currentColor; + opacity: .25; + margin: 0 .15rem; +} + +/* Inline a11y toggle inside theme FAB */ +.a11y-toggle-inline { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border-radius: 50%; + border: 1.5px solid currentColor; + background: transparent; + color: inherit; + font-size: 1rem; + cursor: pointer; + padding: 0; + transition: background .2s, color .2s; + opacity: .8; +} + +.a11y-toggle-inline:hover, +.a11y-toggle-inline:focus-visible { + opacity: 1; + background: rgba(255,255,255,.15); +} + +.a11y-toggle-inline.active { + opacity: 1; + background: rgba(255,255,255,.25); +} + +/* Floating a11y panel when inline */ +.a11y-toolbar-floating { + position: fixed; + z-index: 1202; +} + body.site.error-page { margin: 0; padding: 0; @@ -17364,11 +17463,9 @@ html.a11y-pause-animations *::after { right: 2.5rem; } -/* When theme FAB is present, sit a11y toolbar to its left */ +/* When theme FAB is present, a11y toggle is inline — hide standalone toolbar positioning */ body[data-theme-fab-enabled="1"] #mokoA11yToolbar { - right: auto; - left: 2.5rem; - bottom: 1rem; + position: static; } /* Toggle button */ diff --git a/src/media/js/template.js b/src/media/js/template.js index b1d85d1..5345f42 100644 --- a/src/media/js/template.js +++ b/src/media/js/template.js @@ -87,13 +87,40 @@ lblD.className = 'label'; lblD.textContent = 'Dark'; - // Auto button + // Auto toggle (on/off switch style) + var autoWrap = doc.createElement('div'); + autoWrap.className = 'auto-toggle-wrap'; + + var autoLabel = doc.createElement('span'); + autoLabel.className = 'auto-label'; + autoLabel.textContent = 'Auto'; + var auto = doc.createElement('button'); auto.id = 'mokoThemeAuto'; auto.type = 'button'; - auto.className = 'btn btn-sm btn-link text-decoration-none px-2'; - auto.setAttribute('aria-label', 'Follow system theme'); - auto.textContent = 'Auto'; + auto.className = 'auto-switch'; + auto.setAttribute('role', 'switch'); + auto.setAttribute('aria-label', 'Automatic theme (follow system)'); + auto.setAttribute('aria-checked', getStored() ? 'false' : 'true'); + + var autoTrack = doc.createElement('span'); + autoTrack.className = 'auto-track'; + var autoKnob = doc.createElement('span'); + autoKnob.className = 'auto-knob'; + autoTrack.appendChild(autoKnob); + auto.appendChild(autoTrack); + if (!getStored()) auto.classList.add('on'); + + autoWrap.appendChild(autoLabel); + autoWrap.appendChild(auto); + + // Divider before a11y slot + var divider = doc.createElement('span'); + divider.className = 'fab-divider'; + + // A11y slot — buildA11yToolbar will inject its toggle here + var a11ySlot = doc.createElement('span'); + a11ySlot.id = 'mokoA11ySlot'; // Behavior switchWrap.addEventListener('click', function () { @@ -101,6 +128,9 @@ var next = current === 'dark' ? 'light' : 'dark'; applyTheme(next); switchWrap.setAttribute('aria-checked', next === 'dark' ? 'true' : 'false'); + // Turn off auto when manually switching + auto.classList.remove('on'); + auto.setAttribute('aria-checked', 'false'); // Update meta theme color var meta = doc.querySelector('meta[name="theme-color"]'); if (meta) { @@ -109,10 +139,14 @@ }); auto.addEventListener('click', function () { - clearStored(); - var sys = systemTheme(); - applyTheme(sys); - switchWrap.setAttribute('aria-checked', sys === 'dark' ? 'true' : 'false'); + var isAuto = auto.classList.toggle('on'); + auto.setAttribute('aria-checked', isAuto ? 'true' : 'false'); + if (isAuto) { + clearStored(); + var sys = systemTheme(); + applyTheme(sys); + switchWrap.setAttribute('aria-checked', sys === 'dark' ? 'true' : 'false'); + } }); // Respond to OS changes only when not user-forced @@ -134,7 +168,9 @@ wrap.appendChild(lblL); wrap.appendChild(switchWrap); wrap.appendChild(lblD); - wrap.appendChild(auto); + wrap.appendChild(autoWrap); + wrap.appendChild(divider); + wrap.appendChild(a11ySlot); doc.body.appendChild(wrap); // Debug helper @@ -359,23 +395,6 @@ addSwitchOption(showFont, "font", "fa-solid fa-font", "Readable font", applyFont); addSwitchOption(showAnimations, "paused", "fa-solid fa-pause", "Pause animations", applyPaused); - // Toggle panel open/close - toggle.addEventListener("click", function () { - var isOpen = !panel.hidden; - panel.hidden = isOpen; - toggle.setAttribute("aria-expanded", isOpen ? "false" : "true"); - toggle.classList.toggle("active", !isOpen); - }); - - // Close on outside click - doc.addEventListener("click", function (e) { - if (!toolbar.contains(e.target) && !panel.hidden) { - panel.hidden = true; - toggle.setAttribute("aria-expanded", "false"); - toggle.classList.remove("active"); - } - }); - // Apply saved preferences on load if (prefs.fontStep !== defaultStep) applyFontSize(prefs.fontStep); if (prefs.inverted) applyInversion(true); @@ -384,9 +403,55 @@ if (prefs.font) applyFont(true); if (prefs.paused) applyPaused(true); - toolbar.appendChild(toggle); - toolbar.appendChild(panel); - body.appendChild(toolbar); + // If theme FAB is present, mount a11y toggle inside it; otherwise standalone + var fabSlot = doc.getElementById("mokoA11ySlot"); + if (fabSlot) { + toggle.className = "a11y-toggle a11y-toggle-inline"; + fabSlot.appendChild(toggle); + toolbar.className = "a11y-toolbar-floating"; + toolbar.appendChild(panel); + body.appendChild(toolbar); + // Position panel near the FAB + toggle.addEventListener("click", function () { + var isOpen = !panel.hidden; + panel.hidden = isOpen; + toggle.setAttribute("aria-expanded", isOpen ? "false" : "true"); + toggle.classList.toggle("active", !isOpen); + if (!isOpen) { + var rect = toggle.getBoundingClientRect(); + toolbar.style.position = "fixed"; + toolbar.style.bottom = (win.innerHeight - rect.top + 8) + "px"; + toolbar.style.right = (win.innerWidth - rect.right) + "px"; + toolbar.style.zIndex = "1202"; + } + }); + // Close on outside click for inline mode + doc.addEventListener("click", function (e) { + if (!toggle.contains(e.target) && !toolbar.contains(e.target) && !panel.hidden) { + panel.hidden = true; + toggle.setAttribute("aria-expanded", "false"); + toggle.classList.remove("active"); + } + }); + } else { + // Standalone mode — toggle and close handlers + toggle.addEventListener("click", function () { + var isOpen = !panel.hidden; + panel.hidden = isOpen; + toggle.setAttribute("aria-expanded", isOpen ? "false" : "true"); + toggle.classList.toggle("active", !isOpen); + }); + doc.addEventListener("click", function (e) { + if (!toolbar.contains(e.target) && !panel.hidden) { + panel.hidden = true; + toggle.setAttribute("aria-expanded", "false"); + toggle.classList.remove("active"); + } + }); + toolbar.appendChild(toggle); + toolbar.appendChild(panel); + body.appendChild(toolbar); + } } // ========================================================================