diff --git a/src/assets/scripts/app.js b/src/assets/scripts/app.js deleted file mode 100644 index f8e00e0..0000000 --- a/src/assets/scripts/app.js +++ /dev/null @@ -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); diff --git a/src/assets/scripts/masonry.js b/src/assets/scripts/masonry.js new file mode 100644 index 0000000..5965d89 --- /dev/null +++ b/src/assets/scripts/masonry.js @@ -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 + ); + } +} diff --git a/src/assets/scripts/theme-toggle.js b/src/assets/scripts/theme-toggle.js new file mode 100644 index 0000000..0d44b0f --- /dev/null +++ b/src/assets/scripts/theme-toggle.js @@ -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(); + });