更新包
-- [CST 2026-08-04 Tuesday 16:05:05]
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
function randomPost(trigger) {
|
||||
const source = trigger instanceof Element
|
||||
? trigger
|
||||
: document.activeElement?.closest?.('.nav-random, [onclick*="randomPost"]');
|
||||
const overlay = document.createElement('div');
|
||||
const reduceMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
overlay.className = 'random-post-transition';
|
||||
overlay.setAttribute('role', 'status');
|
||||
overlay.setAttribute('aria-live', 'polite');
|
||||
overlay.innerHTML = `
|
||||
<div class="random-post-flight" aria-hidden="true"></div>
|
||||
<div class="random-post-transition-card">
|
||||
<i class="fa-solid fa-shuffle" aria-hidden="true"></i>
|
||||
<span>\u6b63\u5728\u62bd\u53d6\u4e00\u7bc7\u6587\u7ae0</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
source?.classList.add('is-randomizing');
|
||||
source?.setAttribute('aria-busy', 'true');
|
||||
document.body.appendChild(overlay);
|
||||
requestAnimationFrame(() => overlay.classList.add('is-visible'));
|
||||
|
||||
const finish = href => {
|
||||
const delay = reduceMotion ? 80 : 1250;
|
||||
window.setTimeout(() => {
|
||||
location.href = href;
|
||||
}, delay);
|
||||
};
|
||||
|
||||
const startCardFlight = posts => {
|
||||
if (reduceMotion) return;
|
||||
|
||||
const flight = overlay.querySelector('.random-post-flight');
|
||||
if (!flight) return;
|
||||
|
||||
const candidates = posts
|
||||
.filter(post => post && typeof post.href === 'string' && post.href.startsWith('/posts/'))
|
||||
.map(post => ({
|
||||
title: typeof post.title === 'string' && post.title.trim() ? post.title.trim() : '\u672a\u547d\u540d\u6587\u7ae0',
|
||||
meta: typeof post.category === 'string' && post.category.trim() ? post.category.trim() : '\u968f\u673a\u6587\u7ae0',
|
||||
}));
|
||||
|
||||
const pool = candidates.length ? candidates : [{ title: '\u968f\u673a\u6587\u7ae0', meta: '\u6b63\u5728\u62bd\u53d6' }];
|
||||
const count = Math.min(9, Math.max(5, pool.length));
|
||||
|
||||
for (let index = 0; index < count; index += 1) {
|
||||
const post = pool[Math.floor(Math.random() * pool.length)];
|
||||
const card = document.createElement('div');
|
||||
card.className = 'random-post-flying-card';
|
||||
card.style.setProperty('--flight-delay', `${index * 0.11}s`);
|
||||
card.style.setProperty('--flight-y', `${-42 + Math.random() * 84}px`);
|
||||
card.style.setProperty('--flight-rotate', `${-8 + Math.random() * 16}deg`);
|
||||
const meta = document.createElement('small');
|
||||
const title = document.createElement('strong');
|
||||
meta.textContent = post.meta;
|
||||
title.textContent = post.title;
|
||||
card.append(meta, title);
|
||||
flight.appendChild(card);
|
||||
}
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
source?.classList.remove('is-randomizing');
|
||||
source?.removeAttribute('aria-busy');
|
||||
overlay.classList.remove('is-visible');
|
||||
window.setTimeout(() => overlay.remove(), reduceMotion ? 0 : 180);
|
||||
};
|
||||
|
||||
fetch('/api/posts.json')
|
||||
.then(res => {
|
||||
if (!res.ok) throw new Error(`Failed to load posts: ${res.status}`);
|
||||
return res.json();
|
||||
})
|
||||
.then(posts => {
|
||||
const postLinks = posts
|
||||
.map(post => post && post.href)
|
||||
.filter(href => typeof href === 'string' && href.startsWith('/posts/'));
|
||||
|
||||
if (postLinks.length === 0) {
|
||||
console.warn('No posts available for random navigation.');
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
startCardFlight(posts);
|
||||
finish(postLinks[Math.floor(Math.random() * postLinks.length)]);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Random post navigation failed:', error);
|
||||
reset();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user