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