theme switch as component, fixed accessibility
This commit is contained in:
parent
010051f823
commit
be5ada8bdf
6 changed files with 69 additions and 57 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "eleventy-excellent",
|
"name": "eleventy-excellent",
|
||||||
"version": "2.1.1",
|
"version": "2.1.2",
|
||||||
"description": "Eleventy starter based on the workflow suggested by Andy Bell's buildexcellentwebsit.es.",
|
"description": "Eleventy starter based on the workflow suggested by Andy Bell's buildexcellentwebsit.es.",
|
||||||
"author": "Lene Saile",
|
"author": "Lene Saile",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
|
|
||||||
16
src/_includes/components/theme-switch.njk
Normal file
16
src/_includes/components/theme-switch.njk
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<div
|
||||||
|
role="region"
|
||||||
|
class="theme-switch | cluster mt-xs"
|
||||||
|
style="--cluster-horizontal-alignment: center; --gutter: 0.5rem"
|
||||||
|
aria-labelledby="theme-switcher-label"
|
||||||
|
data-theme-switcher
|
||||||
|
hidden
|
||||||
|
>
|
||||||
|
<h2 id="theme-switcher-label">{{ meta.themeSwitch.title }}</h2>
|
||||||
|
<button class="button" id="light-theme-toggle" data-theme="light">
|
||||||
|
<span>{{ meta.themeSwitch.light }}</span>
|
||||||
|
</button>
|
||||||
|
<button class="button" id="dark-theme-toggle" data-theme="dark">
|
||||||
|
<span>{{ meta.themeSwitch.dark }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
@ -40,24 +40,9 @@
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<!-- theme switch -->
|
||||||
role="region"
|
{% include 'components/theme-switch.njk' %}
|
||||||
class="theme-switch | cluster mt-xs"
|
|
||||||
style="--cluster-horizontal-alignment: center; --gutter: 0.5rem;"
|
|
||||||
aria-labelledby="theme-switcher-label theme-switcher-value"
|
|
||||||
data-theme-switcher
|
|
||||||
hidden
|
|
||||||
>
|
|
||||||
|
|
||||||
<h2 id="theme-switcher-label">{{ meta.themeSwitch.title }}</h2>
|
|
||||||
<button
|
|
||||||
class="button"
|
|
||||||
theme-toggle
|
|
||||||
>
|
|
||||||
<span id="theme-switcher-value">{{ meta.themeSwitch.initial }}</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="text-center mt-m-l">
|
<div class="text-center mt-m-l">
|
||||||
<a class="creator text-step-min-1" href="{{ meta.creator.website }}"
|
<a class="creator text-step-min-1" href="{{ meta.creator.website }}"
|
||||||
>Made with <span>{% include 'svg/heart.svg' %}</span>
|
>Made with <span>{% include 'svg/heart.svg' %}</span>
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
(()=>{var r="theme-preference",l="{{ meta.themeSwitch.light }}",o="{{ meta.themeSwitch.dark }}",h=()=>{e.value=e.value==="light"?"dark":"light",document.querySelector("[theme-toggle]").querySelector("span").innerHTML=e.value==="light"?l:o,n()},i=()=>localStorage.getItem(r)?localStorage.getItem(r):window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light",n=()=>{localStorage.setItem(r,e.value),c()},c=()=>{document.firstElementChild.setAttribute("data-theme",e.value)},e={value:i()};c();window.onload=()=>{let t=document.querySelector("[theme-toggle]"),a=document.querySelector("[data-theme-switcher]");a&&(a.removeAttribute("hidden"),c(),t.addEventListener("click",h),t.querySelector("span").innerHTML=e.value==="light"?l:o)};window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",({matches:t})=>{e.value=t?"dark":"light",n()});})();
|
(()=>{var r="theme-preference",n="{{ meta.themeSwitch.light }}",d="{{ meta.themeSwitch.dark }}",t={value:s()};window.onload=()=>{let e=document.querySelector("#light-theme-toggle"),l=document.querySelector("#dark-theme-toggle"),o=document.querySelector("[data-theme-switcher]");o&&(o.removeAttribute("hidden"),a(),e.addEventListener("click",()=>c("light")),l.addEventListener("click",()=>c("dark")),e.setAttribute("aria-pressed",t.value==="light"),l.setAttribute("aria-pressed",t.value==="dark"))};window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",({matches:e})=>{t.value=e?"dark":"light",i()});function c(e){t.value=e,document.querySelector("#light-theme-toggle").setAttribute("aria-pressed",e==="light"),document.querySelector("#dark-theme-toggle").setAttribute("aria-pressed",e==="dark"),i()}function s(){return localStorage.getItem(r)?localStorage.getItem(r):window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function i(){localStorage.setItem(r,t.value),a()}function a(){document.firstElementChild.setAttribute("data-theme",t.value),document.querySelector("#light-theme-toggle")?.setAttribute("aria-label",n),document.querySelector("#dark-theme-toggle")?.setAttribute("aria-label",d)}a();})();
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,15 @@
|
||||||
.theme-switch .button {
|
.theme-switch .button {
|
||||||
--button-border: var(--color-bg-accent-2);
|
--button-border: var(--color-bg-accent-2);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
font-size: var(--size-step-min-1);
|
font-size: var(--size-step-min-2);
|
||||||
padding: 0.1rem 0;
|
padding: 0.1rem 0.625rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
min-block-size: 1.5em;
|
min-block-size: 1.5em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-switch .button[aria-pressed='true'] {
|
||||||
|
--button-bg: var(--color-primary);
|
||||||
|
--button-text: var(--color-base-light);
|
||||||
|
--button-border: var(--color-primary);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,14 @@
|
||||||
const storageKey = 'theme-preference';
|
const storageKey = 'theme-preference';
|
||||||
|
|
||||||
// get labels from meta
|
|
||||||
const lightLabel = '{{ meta.themeSwitch.light }}';
|
const lightLabel = '{{ meta.themeSwitch.light }}';
|
||||||
const darkLabel = '{{ meta.themeSwitch.dark }}';
|
const darkLabel = '{{ meta.themeSwitch.dark }}';
|
||||||
|
|
||||||
const onClick = () => {
|
|
||||||
// flip current value
|
|
||||||
theme.value = theme.value === 'light' ? 'dark' : 'light';
|
|
||||||
document.querySelector('[theme-toggle]').querySelector('span').innerHTML =
|
|
||||||
theme.value === 'light' ? lightLabel : darkLabel;
|
|
||||||
setPreference();
|
|
||||||
};
|
|
||||||
|
|
||||||
const getColorPreference = () => {
|
|
||||||
if (localStorage.getItem(storageKey)) return localStorage.getItem(storageKey);
|
|
||||||
else
|
|
||||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
||||||
};
|
|
||||||
|
|
||||||
const setPreference = () => {
|
|
||||||
localStorage.setItem(storageKey, theme.value);
|
|
||||||
reflectPreference();
|
|
||||||
};
|
|
||||||
|
|
||||||
const reflectPreference = () => {
|
|
||||||
document.firstElementChild.setAttribute('data-theme', theme.value);
|
|
||||||
|
|
||||||
// themeToggle.querySelector('span').innerHTML =
|
|
||||||
// theme.value === 'light' ? lightLabel : darkLabel;
|
|
||||||
};
|
|
||||||
|
|
||||||
const theme = {
|
const theme = {
|
||||||
value: getColorPreference()
|
value: getColorPreference()
|
||||||
};
|
};
|
||||||
|
|
||||||
// set early so no page flashes / CSS is made aware
|
|
||||||
reflectPreference();
|
|
||||||
|
|
||||||
window.onload = () => {
|
window.onload = () => {
|
||||||
const themeToggle = document.querySelector('[theme-toggle]');
|
const lightThemeToggle = document.querySelector('#light-theme-toggle');
|
||||||
|
const darkThemeToggle = document.querySelector('#dark-theme-toggle');
|
||||||
const switcher = document.querySelector('[data-theme-switcher]');
|
const switcher = document.querySelector('[data-theme-switcher]');
|
||||||
|
|
||||||
if (!switcher) {
|
if (!switcher) {
|
||||||
|
|
@ -46,12 +16,13 @@ window.onload = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
switcher.removeAttribute('hidden');
|
switcher.removeAttribute('hidden');
|
||||||
|
|
||||||
reflectPreference();
|
reflectPreference();
|
||||||
|
|
||||||
themeToggle.addEventListener('click', onClick);
|
lightThemeToggle.addEventListener('click', () => onClick('light'));
|
||||||
themeToggle.querySelector('span').innerHTML =
|
darkThemeToggle.addEventListener('click', () => onClick('dark'));
|
||||||
theme.value === 'light' ? lightLabel : darkLabel;
|
|
||||||
|
lightThemeToggle.setAttribute('aria-pressed', theme.value === 'light');
|
||||||
|
darkThemeToggle.setAttribute('aria-pressed', theme.value === 'dark');
|
||||||
};
|
};
|
||||||
|
|
||||||
// sync with system changes
|
// sync with system changes
|
||||||
|
|
@ -61,3 +32,36 @@ window
|
||||||
theme.value = isDark ? 'dark' : 'light';
|
theme.value = isDark ? 'dark' : 'light';
|
||||||
setPreference();
|
setPreference();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function onClick(themeValue) {
|
||||||
|
theme.value = themeValue;
|
||||||
|
document
|
||||||
|
.querySelector('#light-theme-toggle')
|
||||||
|
.setAttribute('aria-pressed', themeValue === 'light');
|
||||||
|
document
|
||||||
|
.querySelector('#dark-theme-toggle')
|
||||||
|
.setAttribute('aria-pressed', themeValue === 'dark');
|
||||||
|
setPreference();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColorPreference() {
|
||||||
|
if (localStorage.getItem(storageKey)) {
|
||||||
|
return localStorage.getItem(storageKey);
|
||||||
|
} else {
|
||||||
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPreference() {
|
||||||
|
localStorage.setItem(storageKey, theme.value);
|
||||||
|
reflectPreference();
|
||||||
|
}
|
||||||
|
|
||||||
|
function reflectPreference() {
|
||||||
|
document.firstElementChild.setAttribute('data-theme', theme.value);
|
||||||
|
document.querySelector('#light-theme-toggle')?.setAttribute('aria-label', lightLabel);
|
||||||
|
document.querySelector('#dark-theme-toggle')?.setAttribute('aria-label', darkLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set early so no page flashes / CSS is made aware
|
||||||
|
reflectPreference();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue