first commit

This commit is contained in:
2024-10-17 16:11:58 +08:00
commit b0e800da06
74 changed files with 5251 additions and 0 deletions

93
assets/js/dropdown.js Normal file
View File

@@ -0,0 +1,93 @@
function dropdown() {
const mediaQuery = window.matchMedia('(max-width: 767px)');
const head = document.querySelector('.gh-navigation');
const menu = head.querySelector('.gh-navigation-menu');
const nav = menu?.querySelector('.nav');
if (!nav) return;
const logo = document.querySelector('.gh-navigation-logo');
const navHTML = nav.innerHTML;
if (mediaQuery.matches) {
const items = nav.querySelectorAll('li');
items.forEach(function (item, index) {
item.style.transitionDelay = `${0.03 * (index + 1)}s`;
});
}
const makeDropdown = function () {
if (mediaQuery.matches) return;
const submenuItems = [];
while ((nav.offsetWidth + 64) > menu.offsetWidth) {
if (nav.lastElementChild) {
submenuItems.unshift(nav.lastElementChild);
nav.lastElementChild.remove();
} else {
break;
}
}
if (!submenuItems.length) {
head.classList.add('is-dropdown-loaded');
return;
}
const toggle = document.createElement('button');
toggle.setAttribute('class', 'gh-more-toggle gh-icon-button');
toggle.setAttribute('aria-label', 'More');
toggle.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="currentColor"><path d="M21.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0zM13.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0zM5.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0z"></path></svg>';
const wrapper = document.createElement('div');
wrapper.setAttribute('class', 'gh-dropdown');
if (submenuItems.length >= 10) {
head.classList.add('is-dropdown-mega');
wrapper.style.gridTemplateRows = `repeat(${Math.ceil(submenuItems.length / 2)}, 1fr)`;
} else {
head.classList.remove('is-dropdown-mega');
}
submenuItems.forEach(function (child) {
wrapper.appendChild(child);
});
toggle.appendChild(wrapper);
nav.appendChild(toggle);
const toggleRect = toggle.getBoundingClientRect();
const documentCenter = window.innerWidth / 2;
if (toggleRect.left < documentCenter) {
wrapper.classList.add('is-left');
}
head.classList.add('is-dropdown-loaded');
window.addEventListener('click', function (e) {
if (head.classList.contains('is-dropdown-open')) {
head.classList.remove('is-dropdown-open');
} else if (toggle.contains(e.target)) {
head.classList.add('is-dropdown-open');
}
});
}
imagesLoaded(logo, function () {
makeDropdown();
});
window.addEventListener('load', function () {
if (!logo) {
makeDropdown();
}
});
window.addEventListener('resize', function () {
setTimeout(() => {
nav.innerHTML = navHTML;
makeDropdown();
}, 1);
});
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
assets/js/lib/photoswipe.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
assets/js/lib/reframe.min.js vendored Normal file
View File

@@ -0,0 +1 @@
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).reframe=t()}(this,function(){"use strict";function t(){for(var e=0,t=0,n=arguments.length;t<n;t++)e+=arguments[t].length;for(var i=Array(e),o=0,t=0;t<n;t++)for(var r=arguments[t],f=0,d=r.length;f<d;f++,o++)i[o]=r[f];return i}return function(e,s){return void 0===s&&(s="js-reframe"),("string"==typeof e?t(document.querySelectorAll(e)):"length"in e?t(e):[e]).forEach(function(e){var t,n,i,o,r,f,d,l;-1!==e.className.split(" ").indexOf(s)||-1<e.style.width.indexOf("%")||(i=e.getAttribute("height")||e.offsetHeight,o=e.getAttribute("width")||e.offsetWidth,r=("string"==typeof i?parseInt(i):i)/("string"==typeof o?parseInt(o):o)*100,(f=document.createElement("div")).className=s,(d=f.style).position="relative",d.width="100%",d.paddingTop=r+"%",(l=e.style).position="absolute",l.width="100%",l.height="100%",l.left="0",l.top="0",null!==(t=e.parentNode)&&void 0!==t&&t.insertBefore(f,e),null!==(n=e.parentNode)&&void 0!==n&&n.removeChild(e),f.appendChild(e))})}});

103
assets/js/lightbox.js Normal file
View File

@@ -0,0 +1,103 @@
function lightbox(trigger) {
var onThumbnailsClick = function (e) {
e.preventDefault();
var items = [];
var index = 0;
var prevSibling = e.target.closest('.kg-card').previousElementSibling;
while (prevSibling && (prevSibling.classList.contains('kg-image-card') || prevSibling.classList.contains('kg-gallery-card'))) {
var prevItems = [];
prevSibling.querySelectorAll('img').forEach(function (item) {
prevItems.push({
src: item.getAttribute('src'),
msrc: item.getAttribute('src'),
w: item.getAttribute('width'),
h: item.getAttribute('height'),
el: item,
})
index += 1;
});
prevSibling = prevSibling.previousElementSibling;
items = prevItems.concat(items);
}
if (e.target.classList.contains('kg-image')) {
items.push({
src: e.target.getAttribute('src'),
msrc: e.target.getAttribute('src'),
w: e.target.getAttribute('width'),
h: e.target.getAttribute('height'),
el: e.target,
});
} else {
var reachedCurrentItem = false;
e.target.closest('.kg-gallery-card').querySelectorAll('img').forEach(function (item) {
items.push({
src: item.getAttribute('src'),
msrc: item.getAttribute('src'),
w: item.getAttribute('width'),
h: item.getAttribute('height'),
el: item,
});
if (!reachedCurrentItem && item !== e.target) {
index += 1;
} else {
reachedCurrentItem = true;
}
});
}
var nextSibling = e.target.closest('.kg-card').nextElementSibling;
while (nextSibling && (nextSibling.classList.contains('kg-image-card') || nextSibling.classList.contains('kg-gallery-card'))) {
nextSibling.querySelectorAll('img').forEach(function (item) {
items.push({
src: item.getAttribute('src'),
msrc: item.getAttribute('src'),
w: item.getAttribute('width'),
h: item.getAttribute('height'),
el: item,
})
});
nextSibling = nextSibling.nextElementSibling;
}
var pswpElement = document.querySelectorAll('.pswp')[0];
var options = {
bgOpacity: 0.9,
closeOnScroll: true,
fullscreenEl: false,
history: false,
index: index,
shareEl: false,
zoomEl: false,
getThumbBoundsFn: function(index) {
var thumbnail = items[index].el,
pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
rect = thumbnail.getBoundingClientRect();
return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
}
}
var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options);
gallery.init();
return false;
};
var triggers = document.querySelectorAll(trigger);
triggers.forEach(function (trig) {
trig.addEventListener('click', function (e) {
onThumbnailsClick(e);
});
});
}

60
assets/js/main.js Normal file
View File

@@ -0,0 +1,60 @@
/* Mobile menu burger toggle */
(function () {
const navigation = document.querySelector('.gh-navigation');
const burger = navigation.querySelector('.gh-burger');
if (!burger) return;
burger.addEventListener('click', function () {
if (!navigation.classList.contains('is-open')) {
navigation.classList.add('is-open');
document.documentElement.style.overflowY = 'hidden';
} else {
navigation.classList.remove('is-open');
document.documentElement.style.overflowY = null;
}
});
})();
/* Add lightbox to gallery images */
(function () {
lightbox(
'.kg-image-card > .kg-image[width][height], .kg-gallery-image > img'
);
})();
/* Responsive video in post content */
(function () {
const sources = [
'.gh-content iframe[src*="youtube.com"]',
'.gh-content iframe[src*="youtube-nocookie.com"]',
'.gh-content iframe[src*="player.vimeo.com"]',
'.gh-content iframe[src*="kickstarter.com"][src*="video.html"]',
'.gh-content object',
'.gh-content embed',
];
reframe(document.querySelectorAll(sources.join(',')));
})();
/* Turn the main nav into dropdown menu when there are more than 5 menu items */
(function () {
dropdown();
})();
/* Infinite scroll pagination */
(function () {
if (!document.body.classList.contains('home-template') && !document.body.classList.contains('post-template')) {
pagination();
}
})();
/* Responsive HTML table */
(function () {
const tables = document.querySelectorAll('.gh-content > table:not(.gist table)');
tables.forEach(function (table) {
const wrapper = document.createElement('div');
wrapper.className = 'gh-table';
table.parentNode.insertBefore(wrapper, table);
wrapper.appendChild(table);
});
})();

95
assets/js/pagination.js Normal file
View File

@@ -0,0 +1,95 @@
function pagination(isInfinite = true, done, isMasonry = false) {
const feedElement = document.querySelector('.gh-feed');
if (!feedElement) return;
let loading = false;
const target = document.querySelector('.gh-footer');
const buttonElement = document.querySelector('.gh-loadmore');
if (!document.querySelector('link[rel=next]') && buttonElement) {
buttonElement.remove();
}
const loadNextPage = async function () {
const nextElement = document.querySelector('link[rel=next]');
if (!nextElement) return;
try {
const res = await fetch(nextElement.href);
const html = await res.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const postElements = doc.querySelectorAll('.gh-feed:not(.gh-featured):not(.gh-related) > *');
const fragment = document.createDocumentFragment();
const elems = [];
postElements.forEach(function (post) {
var clonedItem = document.importNode(post, true);
if (isMasonry) {
clonedItem.style.visibility = 'hidden';
}
fragment.appendChild(clonedItem);
elems.push(clonedItem);
});
feedElement.appendChild(fragment);
if (done) {
done(elems, loadNextWithCheck);
}
const resNextElement = doc.querySelector('link[rel=next]');
if (resNextElement && resNextElement.href) {
nextElement.href = resNextElement.href;
} else {
nextElement.remove();
if (buttonElement) {
buttonElement.remove();
}
}
} catch (e) {
nextElement.remove();
throw e;
}
};
const loadNextWithCheck = async function () {
if (target.getBoundingClientRect().top <= window.innerHeight && document.querySelector('link[rel=next]')) {
await loadNextPage();
}
}
const callback = async function (entries) {
if (loading) return;
loading = true;
if (entries[0].isIntersecting) {
// keep loading next page until target is out of the viewport or we've loaded the last page
if (!isMasonry) {
while (target.getBoundingClientRect().top <= window.innerHeight && document.querySelector('link[rel=next]')) {
await loadNextPage();
}
} else {
await loadNextPage();
}
}
loading = false;
if (!document.querySelector('link[rel=next]')) {
observer.disconnect();
}
};
const observer = new IntersectionObserver(callback);
if (isInfinite) {
observer.observe(target);
} else {
buttonElement.addEventListener('click', loadNextPage);
}
}