fix: a11y id confict between desktop and mobile

This commit is contained in:
ZhenShuo Leo
2025-07-21 21:44:29 +08:00
parent 5b376cc116
commit 9f07989148
2 changed files with 64 additions and 48 deletions

View File

@@ -99,10 +99,12 @@
applyA11ySettings(); applyA11ySettings();
}; };
const toggleA11yPanel = () => { window.toggleA11yPanel = function (prefix = "") {
const panel = document.getElementById("a11y-panel"); const panel = document.getElementById(`${prefix}a11y-panel`);
const overlay = document.getElementById("a11y-overlay"); const overlay = document.getElementById(`${prefix}a11y-overlay`);
const button = document.getElementById("a11y-toggle"); const button = document.getElementById(`${prefix}a11y-toggle`);
if (!panel || !overlay || !button) return;
if (overlay.classList.contains("hidden")) { if (overlay.classList.contains("hidden")) {
overlay.classList.remove("hidden"); overlay.classList.remove("hidden");
@@ -117,51 +119,59 @@
} }
}; };
const initA11yPanel = () => { window.initA11yPanel = function (prefix = "") {
const settings = getA11ySettings(); const settings = getA11ySettings();
document.getElementById("disable-blur").checked = settings.disableBlur; const checkboxBlur = document.getElementById(`${prefix}disable-blur`);
document.getElementById("disable-images").checked = settings.disableImages; const checkboxImages = document.getElementById(`${prefix}disable-images`);
const checkboxUnderline = document.getElementById(`${prefix}underline-links`);
const fontSizeSelect = document.getElementById(`${prefix}font-size-select`);
const fontSizeSelect = document.getElementById("font-size-select"); if (!checkboxBlur || !checkboxImages || !checkboxUnderline || !fontSizeSelect) return;
checkboxBlur.checked = settings.disableBlur;
checkboxImages.checked = settings.disableImages;
fontSizeSelect.value = settings.fontSize; fontSizeSelect.value = settings.fontSize;
checkboxUnderline.checked = settings.underlineLinks;
document.getElementById("underline-links").checked = settings.underlineLinks; checkboxBlur.addEventListener("change", (e) => {
document.getElementById("disable-blur").addEventListener("change", (e) => {
updateA11ySetting("disableBlur", e.target.checked); updateA11ySetting("disableBlur", e.target.checked);
}); });
document.getElementById("disable-images").addEventListener("change", (e) => { checkboxImages.addEventListener("change", (e) => {
updateA11ySetting("disableImages", e.target.checked); updateA11ySetting("disableImages", e.target.checked);
}); });
document.getElementById("font-size-select").addEventListener("change", (e) => { fontSizeSelect.addEventListener("change", (e) => {
updateA11ySetting("fontSize", e.target.value); updateA11ySetting("fontSize", e.target.value);
}); });
document.getElementById("underline-links").addEventListener("change", (e) => { checkboxUnderline.addEventListener("change", (e) => {
updateA11ySetting("underlineLinks", e.target.checked); updateA11ySetting("underlineLinks", e.target.checked);
}); });
document.querySelectorAll(".ios-toggle").forEach((toggle) => { document.querySelectorAll(".ios-toggle").forEach((toggle) => {
toggle.addEventListener("click", () => {
const checkbox = toggle.querySelector('input[type="checkbox"]'); const checkbox = toggle.querySelector('input[type="checkbox"]');
if (!checkbox || !checkbox.id.startsWith(prefix)) return;
toggle.addEventListener("click", () => {
checkbox.checked = !checkbox.checked; checkbox.checked = !checkbox.checked;
checkbox.dispatchEvent(new Event("change")); checkbox.dispatchEvent(new Event("change"));
}); });
}); });
const overlay = document.getElementById(`${prefix}a11y-overlay`);
const button = document.getElementById(`${prefix}a11y-toggle`);
if (overlay && button) {
document.addEventListener("click", (e) => { document.addEventListener("click", (e) => {
const overlay = document.getElementById("a11y-overlay");
const button = document.getElementById("a11y-toggle");
if (e.target === overlay) { if (e.target === overlay) {
overlay.classList.add("hidden"); overlay.classList.add("hidden");
document.getElementById("a11y-panel").classList.add("hidden"); const panel = document.getElementById(`${prefix}a11y-panel`);
if (panel) panel.classList.add("hidden");
button.setAttribute("aria-pressed", "false"); button.setAttribute("aria-pressed", "false");
button.setAttribute("aria-expanded", "false"); button.setAttribute("aria-expanded", "false");
} }
}); });
}
}; };
scripts.forEach((script) => { scripts.forEach((script) => {
@@ -187,12 +197,13 @@
} }
}); });
window.toggleA11yPanel = toggleA11yPanel;
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
applyA11ySettings(); applyA11ySettings();
if (document.getElementById("a11y-panel")) {
initA11yPanel(); const allPanels = document.querySelectorAll('[id$="a11y-panel"]');
} allPanels.forEach((panel) => {
const prefix = panel.id.replace("a11y-panel", "");
window.initA11yPanel(prefix);
});
}); });
})(); })();

View File

@@ -35,7 +35,7 @@
{{ partial "translations.html" . }} {{ partial "translations.html" . }}
{{ if .Site.Params.enableA11y | default false }} {{ if .Site.Params.enableA11y | default false }}
{{ template "HeaderA11y" . }} {{ template "HeaderA11y" (dict "prefix" "desktop-" "Site" .Site) }}
{{ end }} {{ end }}
{{ if .Site.Params.enableSearch | default false }} {{ if .Site.Params.enableSearch | default false }}
@@ -74,7 +74,7 @@
{{ partial "translations.html" . }} {{ partial "translations.html" . }}
{{ if .Site.Params.enableA11y | default false }} {{ if .Site.Params.enableA11y | default false }}
{{ template "HeaderA11y" . }} {{ template "HeaderA11y" (dict "prefix" "mobile-" "Site" .Site) }}
{{ end }} {{ end }}
{{ if .Site.Params.enableSearch | default false }} {{ if .Site.Params.enableSearch | default false }}
@@ -160,33 +160,36 @@
{{ end }} {{ end }}
{{ define "HeaderA11y" }} {{ define "HeaderA11y" }}
{{- $prefix := .prefix | default "" -}}
<div class="flex items-center"> <div class="flex items-center">
<button <button
id="a11y-toggle" id="{{ $prefix }}a11y-toggle"
aria-label="Open accessibility panel" aria-label="Open accessibility panel"
aria-expanded="false" aria-expanded="false"
type="button" type="button"
class="text-base hover:text-primary-600 dark:hover:text-primary-400" class="text-base hover:text-primary-600 dark:hover:text-primary-400"
onclick="toggleA11yPanel()" onclick="toggleA11yPanel('{{ $prefix }}')"
role="button" role="button"
aria-pressed="false"> aria-pressed="false">
{{ partial "icon.html" "a11y" }} {{ partial "icon.html" "a11y" }}
</button> </button>
<div id="a11y-overlay" class="fixed inset-0 z-500 hidden"></div> <div id="{{ $prefix }}a11y-overlay" class="fixed inset-0 z-500 hidden"></div>
<div <div
id="a11y-panel" id="{{ $prefix }}a11y-panel"
role="dialog" role="dialog"
aria-labelledby="a11y-panel-title" aria-labelledby="{{ $prefix }}a11y-panel-title"
class="a11y-panel-enter fixed hidden z-500 p-6 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-80 rounded-lg shadow-xl bg-neutral-50 dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700" class="a11y-panel-enter fixed hidden z-500 p-6 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-80 rounded-lg shadow-xl bg-neutral-50 dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700"
style="min-width: 20rem;"> style="min-width: 20rem;">
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<h3 id="a11y-panel-title" class="text-lg font-semibold text-neutral-900 dark:text-neutral-100"> <h3
id="{{ $prefix }}a11y-panel-title"
class="text-lg font-semibold text-neutral-900 dark:text-neutral-100">
Accessibility settings Accessibility settings
</h3> </h3>
<button <button
onclick="toggleA11yPanel()" onclick="toggleA11yPanel('{{ $prefix }}')"
class="text-neutral-500 hover:text-neutral-700 dark:text-neutral-400 dark:hover:text-neutral-200" class="text-neutral-500 hover:text-neutral-700 dark:text-neutral-400 dark:hover:text-neutral-200"
aria-label="Close a11y panel"> aria-label="Close a11y panel">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -196,13 +199,13 @@
</div> </div>
<div class="space-y-5"> <div class="space-y-5">
{{ $toggles := slice {{- $toggles := slice
(dict "id" "disable-blur" "label" "Disable background blur") (dict "id" (print $prefix "disable-blur") "label" "Disable background blur")
(dict "id" "disable-images" "label" "Disable background image") (dict "id" (print $prefix "disable-images") "label" "Disable background image")
(dict "id" "underline-links" "label" "Show link underline") (dict "id" (print $prefix "underline-links") "label" "Show link underline")
}} -}}
{{ range $toggles }} {{- range $toggles }}
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<label for="{{ .id }}" class="text-sm font-medium text-neutral-700 dark:text-neutral-300"> <label for="{{ .id }}" class="text-sm font-medium text-neutral-700 dark:text-neutral-300">
{{ .label }} {{ .label }}
@@ -211,15 +214,17 @@
<input type="checkbox" id="{{ .id }}"> <input type="checkbox" id="{{ .id }}">
</div> </div>
</div> </div>
{{ end }} {{- end }}
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<label for="font-size-select" class="text-sm font-medium text-neutral-700 dark:text-neutral-300"> <label
for="{{ $prefix }}font-size-select"
class="text-sm font-medium text-neutral-700 dark:text-neutral-300">
Font size Font size
</label> </label>
<select <select
id="font-size-select" id="{{ $prefix }}font-size-select"
class="border rounded-lg px-3 py-1.5 pr-8 text-neutral-900 text-sm dark:bg-neutral-700 dark:text-neutral-200 focus:ring-primary-500 focus:border-primary-500"> class="border rounded-lg px-3 py-1.5 pr-8 text-neutral-900 text-sm dark:bg-neutral-700 dark:text-neutral-200 focus:ring-primary-500 focus:border-primary-500">
{{ $fontSizes := slice "12px" "14px" "16px" "18px" "20px" "22px" "24px" }} {{ $fontSizes := slice "12px" "14px" "16px" "18px" "20px" "22px" "24px" }}
{{ range $fontSizes }} {{ range $fontSizes }}