masonry fallback and theme toggle in, menu drawer out
This commit is contained in:
parent
ec3784a4a0
commit
329c7bb20a
3 changed files with 107 additions and 34 deletions
|
|
@ -1,34 +0,0 @@
|
||||||
// © Manuel Matuzović: https://web.dev/website-navigation/
|
|
||||||
|
|
||||||
const nav = document.querySelector('nav');
|
|
||||||
const list = nav.querySelector('ul');
|
|
||||||
const burgerClone = document.querySelector('#burger-template').content.cloneNode(true);
|
|
||||||
const svg = nav.querySelector('svg');
|
|
||||||
|
|
||||||
const button = burgerClone.querySelector('button');
|
|
||||||
button.addEventListener('click', e => {
|
|
||||||
const isOpen = button.getAttribute('aria-expanded') === 'true';
|
|
||||||
button.setAttribute('aria-expanded', !isOpen);
|
|
||||||
});
|
|
||||||
|
|
||||||
// avoid DRY: disabling menu
|
|
||||||
const disableMenu = () => {
|
|
||||||
button.setAttribute('aria-expanded', false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// close on escape
|
|
||||||
nav.addEventListener('keyup', e => {
|
|
||||||
if (e.code === 'Escape') {
|
|
||||||
disableMenu();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// close if clicked outside of event target
|
|
||||||
document.addEventListener('click', e => {
|
|
||||||
const isClickInsideElement = nav.contains(e.target);
|
|
||||||
if (!isClickInsideElement) {
|
|
||||||
disableMenu();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
nav.insertBefore(burgerClone, list);
|
|
||||||
44
src/assets/scripts/masonry.js
Normal file
44
src/assets/scripts/masonry.js
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
// ----- masonry fallback if CSS masonry not supported, solution by Ana Tudor: https://codepen.io/thebabydino/pen/yLYppjK
|
||||||
|
|
||||||
|
const supportMasonry = CSS.supports('grid-template-rows', 'masonry');
|
||||||
|
|
||||||
|
if (!supportMasonry) {
|
||||||
|
let grids = [...document.querySelectorAll('.grid[data-rows="masonry"]')];
|
||||||
|
|
||||||
|
if (grids.length && getComputedStyle(grids[0]).gridTemplateRows !== 'masonry') {
|
||||||
|
grids = grids.map(grid => ({
|
||||||
|
_el: grid,
|
||||||
|
gap: parseFloat(getComputedStyle(grid).rowGap),
|
||||||
|
items: [...grid.childNodes]
|
||||||
|
.filter(c => c.nodeType === 1 && +getComputedStyle(c).gridColumnEnd !== -1)
|
||||||
|
.map(c => ({_el: c})),
|
||||||
|
ncol: 0
|
||||||
|
}));
|
||||||
|
|
||||||
|
function layout() {
|
||||||
|
grids.forEach(grid => {
|
||||||
|
let ncol = getComputedStyle(grid._el).gridTemplateColumns.split(' ').length;
|
||||||
|
if (grid.ncol !== ncol) {
|
||||||
|
grid.ncol = ncol;
|
||||||
|
grid.items.forEach(c => c._el.style.removeProperty('margin-block-start'));
|
||||||
|
if (grid.ncol > 1) {
|
||||||
|
grid.items.slice(ncol).forEach((c, i) => {
|
||||||
|
let prev_fin = grid.items[i]._el.getBoundingClientRect().bottom,
|
||||||
|
curr_ini = c._el.getBoundingClientRect().top;
|
||||||
|
c._el.style.marginTop = `${prev_fin + grid.gap - curr_ini}px`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener(
|
||||||
|
'load',
|
||||||
|
e => {
|
||||||
|
layout();
|
||||||
|
addEventListener('resize', layout, false);
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/assets/scripts/theme-toggle.js
Normal file
63
src/assets/scripts/theme-toggle.js
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
const storageKey = 'theme-preference';
|
||||||
|
|
||||||
|
// get labels from meta
|
||||||
|
const lightLabel = '{{ meta.themeSwitch.light }}';
|
||||||
|
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 = {
|
||||||
|
value: getColorPreference()
|
||||||
|
};
|
||||||
|
|
||||||
|
// set early so no page flashes / CSS is made aware
|
||||||
|
reflectPreference();
|
||||||
|
|
||||||
|
window.onload = () => {
|
||||||
|
const themeToggle = document.querySelector('[theme-toggle]');
|
||||||
|
const switcher = document.querySelector('[data-theme-switcher]');
|
||||||
|
|
||||||
|
if (!switcher) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switcher.removeAttribute('hidden');
|
||||||
|
|
||||||
|
reflectPreference();
|
||||||
|
|
||||||
|
themeToggle.addEventListener('click', onClick);
|
||||||
|
themeToggle.querySelector('span').innerHTML =
|
||||||
|
theme.value === 'light' ? lightLabel : darkLabel;
|
||||||
|
};
|
||||||
|
|
||||||
|
// sync with system changes
|
||||||
|
window
|
||||||
|
.matchMedia('(prefers-color-scheme: dark)')
|
||||||
|
.addEventListener('change', ({matches: isDark}) => {
|
||||||
|
theme.value = isDark ? 'dark' : 'light';
|
||||||
|
setPreference();
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue