update scripts
This commit is contained in:
parent
b9b47dfab7
commit
d02b5acd76
9 changed files with 149 additions and 95 deletions
25
src/assets/scripts/bundle/details.js
Normal file
25
src/assets/scripts/bundle/details.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
const container = document.querySelector('.details');
|
||||
const expandAllButton = container.querySelector('#expandAll');
|
||||
const collapseAllButton = container.querySelector('#collapseAll');
|
||||
const details = container.querySelectorAll('details');
|
||||
|
||||
expandAllButton.addEventListener('click', () => {
|
||||
details.forEach(detail => (detail.open = true));
|
||||
});
|
||||
|
||||
collapseAllButton.addEventListener('click', () => {
|
||||
details.forEach(detail => (detail.open = false));
|
||||
});
|
||||
|
||||
details.forEach(detail => {
|
||||
detail.addEventListener('toggle', () => {
|
||||
const hash = detail.open ? `#${detail.id}` : '#';
|
||||
history.pushState(null, null, hash);
|
||||
});
|
||||
});
|
||||
|
||||
const id = window.location.hash.slice(1);
|
||||
if (id) {
|
||||
const detail = container.querySelector(`#${CSS.escape(id)}`);
|
||||
if (detail) detail.open = true;
|
||||
}
|
||||
20
src/assets/scripts/bundle/gallery.js
Normal file
20
src/assets/scripts/bundle/gallery.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
const buttons = document.querySelectorAll('button[data-index]');
|
||||
const modals = document.querySelectorAll('dialog');
|
||||
const closeButtons = document.querySelectorAll('dialog button');
|
||||
buttons.forEach((button, index) => {
|
||||
button.addEventListener('click', () => {
|
||||
modals[index].showModal();
|
||||
});
|
||||
});
|
||||
closeButtons.forEach((button, index) => {
|
||||
button.addEventListener('click', () => {
|
||||
modals[index].close();
|
||||
});
|
||||
});
|
||||
window.addEventListener('click', event => {
|
||||
modals.forEach(modal => {
|
||||
if (event.target === modal) {
|
||||
modal.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
1
src/assets/scripts/bundle/is-land.js
Normal file
1
src/assets/scripts/bundle/is-land.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import '@11ty/is-land/is-land';
|
||||
|
|
@ -15,7 +15,6 @@ window.onload = () => {
|
|||
return;
|
||||
}
|
||||
|
||||
switcher.removeAttribute('hidden');
|
||||
reflectPreference();
|
||||
|
||||
lightThemeToggle.addEventListener('click', () => onClick('light'));
|
||||
|
|
@ -26,21 +25,15 @@ window.onload = () => {
|
|||
};
|
||||
|
||||
// sync with system changes
|
||||
window
|
||||
.matchMedia('(prefers-color-scheme: dark)')
|
||||
.addEventListener('change', ({matches: isDark}) => {
|
||||
theme.value = isDark ? 'dark' : 'light';
|
||||
setPreference();
|
||||
});
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ({matches: isDark}) => {
|
||||
theme.value = isDark ? 'dark' : 'light';
|
||||
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');
|
||||
document.querySelector('#light-theme-toggle').setAttribute('aria-pressed', themeValue === 'light');
|
||||
document.querySelector('#dark-theme-toggle').setAttribute('aria-pressed', themeValue === 'dark');
|
||||
setPreference();
|
||||
}
|
||||
|
||||
56
src/assets/scripts/components/custom-easteregg.js
Normal file
56
src/assets/scripts/components/custom-easteregg.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
class customEasteregg extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
// Initialize with default keywords
|
||||
this.keywords = ['eleventy', 'excellent'];
|
||||
// Add any custom keyword passed as an attribute
|
||||
const customKeyword = this.getAttribute('keyword');
|
||||
if (customKeyword) {
|
||||
this.keywords.push(customKeyword);
|
||||
}
|
||||
|
||||
this.shape = this.getAttribute('shape') || '⭐️';
|
||||
this.particleCount = parseInt(this.getAttribute('particle-count'), 10) || 30;
|
||||
this.codes = this.keywords.map(keyword => keyword.split(''));
|
||||
this.indexes = new Array(this.keywords.length).fill(0);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
document.addEventListener('keydown', this.handleKeydown.bind(this));
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
document.removeEventListener('keydown', this.handleKeydown.bind(this));
|
||||
}
|
||||
|
||||
handleKeydown(event) {
|
||||
const key = event.key.toLowerCase();
|
||||
this.codes.forEach((code, idx) => {
|
||||
if (code[this.indexes[idx]] === key) {
|
||||
this.indexes[idx]++;
|
||||
if (this.indexes[idx] === code.length) {
|
||||
this.triggerEffect(this.keywords[idx]);
|
||||
this.indexes[idx] = 0; // Reset index after triggering
|
||||
}
|
||||
} else {
|
||||
this.indexes[idx] = 0; // Reset index if sequence breaks
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
triggerEffect(keyword) {
|
||||
console.log(`Hooray ${keyword}!`);
|
||||
import('https://esm.run/canvas-confetti').then(({default: confetti}) => {
|
||||
const scalar = 4;
|
||||
const customShape = confetti.shapeFromText({text: this.shape, scalar});
|
||||
|
||||
confetti({
|
||||
shapes: [customShape],
|
||||
scalar,
|
||||
particleCount: this.particleCount
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('custom-easteregg', customEasteregg);
|
||||
41
src/assets/scripts/components/custom-masonry.js
Normal file
41
src/assets/scripts/components/custom-masonry.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
class CustomMasonry extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.layoutMasonry = this.layoutMasonry.bind(this);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
// Defer initial layout to ensure styles are applied
|
||||
requestAnimationFrame(() => {
|
||||
this.layoutMasonry();
|
||||
window.addEventListener('resize', this.debounceLayout.bind(this, 100));
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
window.removeEventListener('resize', this.debounceLayout);
|
||||
}
|
||||
|
||||
debounceLayout(delay) {
|
||||
clearTimeout(this.timeoutId);
|
||||
this.timeoutId = setTimeout(this.layoutMasonry, delay);
|
||||
}
|
||||
|
||||
layoutMasonry() {
|
||||
const columnCount = getComputedStyle(this).gridTemplateColumns.split(' ').length;
|
||||
const items = Array.from(this.children);
|
||||
items.forEach((item, index) => {
|
||||
item.style.marginTop = '0px'; // Reset before calculation
|
||||
if (index >= columnCount) {
|
||||
const previousItem = items[index - columnCount];
|
||||
const previousItemBottom =
|
||||
previousItem.offsetTop + previousItem.offsetHeight + parseFloat(getComputedStyle(this).rowGap);
|
||||
const currentItemTop = item.offsetTop;
|
||||
const marginTop = previousItemBottom - currentItemTop;
|
||||
item.style.marginTop = `${marginTop}px`;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('custom-masonry', CustomMasonry);
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
const eleventyCode = ['e', 'l', 'e', 'v', 'e', 'n', 't', 'y'];
|
||||
const excellentCode = ['e', 'x', 'c', 'e', 'l', 'l', 'e', 'n', 't'];
|
||||
|
||||
let indexEleventy = 0;
|
||||
let indexExcellent = 0;
|
||||
|
||||
// Trigger confetti if someone enters "eleventy" or "excellent"
|
||||
document.addEventListener('keydown', event => {
|
||||
if (eleventyCode[indexEleventy] === event.key.toLowerCase()) {
|
||||
++indexEleventy;
|
||||
} else {
|
||||
indexEleventy = 0;
|
||||
}
|
||||
|
||||
if (excellentCode[indexExcellent] === event.key.toLowerCase()) {
|
||||
++indexExcellent;
|
||||
} else {
|
||||
indexExcellent = 0;
|
||||
}
|
||||
|
||||
if (indexEleventy === eleventyCode.length || indexExcellent === excellentCode.length) {
|
||||
console.log('Hooray Eleventy!');
|
||||
indexEleventy = 0;
|
||||
indexExcellent = 0;
|
||||
import('https://esm.run/canvas-confetti').then(module => {
|
||||
const confetti = module.default;
|
||||
const scalar = 4;
|
||||
const particleCount = 30;
|
||||
const star = confetti.shapeFromText({text: '⭐️', scalar});
|
||||
|
||||
confetti({
|
||||
shapes: [star],
|
||||
scalar,
|
||||
particleCount
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
// ----- 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
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue