Files
web_huangguo2_h5/app/static/js/favorites.js
T
谢宇宁andClaude Opus 5.5 0fbdba5ccf Initial commit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 11:47:47 +07:00

112 lines
4.6 KiB
JavaScript

(() => {
const root = document.querySelector('[data-favorites]');
if (!root) return;
const cards = Array.from(root.querySelectorAll('[data-favorites-card]'));
const filters = Array.from(root.querySelectorAll('[data-favorites-filter]'));
const manage = root.querySelector('[data-favorites-manage]');
const manageLabel = manage ? manage.querySelector('span') : null;
const toolbar = root.querySelector('[data-favorites-toolbar]');
const grid = root.querySelector('[data-favorites-grid]');
const empty = root.querySelector('[data-favorites-empty]');
const filterEmpty = root.querySelector('[data-favorites-filter-empty]');
const recommendations = root.querySelector('[data-favorites-recommendations]');
const loadMore = root.querySelector('[data-favorites-more]');
const pagination = root.querySelector('[data-favorites-pagination]');
const pages = root.querySelector('[data-favorites-pages]');
const previous = root.querySelector('[data-favorites-prev]');
const next = root.querySelector('[data-favorites-next]');
const count = root.querySelector('[data-favorites-count]');
const mobile = window.matchMedia('(max-width: 768px)');
let activeFilter = 'all';
let currentPage = 1;
let mobileVisible = 9;
function matches(card) {
if (card.dataset.removed === 'true') return false;
if (activeFilter === 'following') return card.dataset.following === 'true';
if (activeFilter === 'complete') return card.dataset.complete === 'true';
return activeFilter === 'all' || card.dataset.kind === activeFilter;
}
function render() {
const hasSavedWorks = cards.some(card => card.dataset.removed !== 'true');
const collectionEmpty = !hasSavedWorks;
const filtered = cards.filter(matches);
const pageCount = Math.ceil(filtered.length / 12);
currentPage = Math.min(currentPage, Math.max(1, pageCount));
const start = mobile.matches ? 0 : (currentPage - 1) * 12;
const end = mobile.matches ? mobileVisible : start + 12;
cards.forEach(card => { card.hidden = true; });
filtered.slice(start, end).forEach(card => { card.hidden = false; });
root.classList.toggle('is-empty', collectionEmpty);
toolbar.hidden = collectionEmpty;
grid.hidden = collectionEmpty;
empty.hidden = !collectionEmpty;
if (recommendations) recommendations.hidden = !collectionEmpty;
filterEmpty.hidden = collectionEmpty || filtered.length !== 0;
if (collectionEmpty) {
document.body.classList.remove('is-managing');
if (manage) manage.setAttribute('aria-pressed', 'false');
if (manageLabel) manageLabel.textContent = '管理';
}
loadMore.hidden = filtered.length === 0 || mobileVisible >= filtered.length;
pagination.hidden = filtered.length === 0;
count.textContent = `共 ${filtered.length} 部`;
previous.disabled = currentPage <= 1;
next.disabled = currentPage >= pageCount;
pages.replaceChildren();
for (let page = 1; page <= pageCount; page++) {
const button = document.createElement('button');
button.className = `favorites-pagination__button${page === currentPage ? ' is-active' : ''}`;
button.type = 'button';
button.textContent = String(page);
button.dataset.favoritesPage = String(page);
if (page === currentPage) button.setAttribute('aria-current', 'page');
button.addEventListener('click', () => {
currentPage = page;
render();
});
pages.append(button);
}
}
filters.forEach(filter => filter.addEventListener('click', () => {
activeFilter = filter.dataset.favoritesFilter;
currentPage = 1;
mobileVisible = 9;
filters.forEach(option => {
const selected = option === filter;
option.classList.toggle('is-active', selected);
option.setAttribute('aria-pressed', String(selected));
});
render();
}));
if (manage) manage.addEventListener('click', () => {
const managing = document.body.classList.toggle('is-managing');
manage.setAttribute('aria-pressed', String(managing));
manageLabel.textContent = managing ? '完成' : '管理';
});
root.querySelectorAll('[data-favorites-remove]').forEach(button => button.addEventListener('click', () => {
button.closest('[data-favorites-card]').dataset.removed = 'true';
render();
}));
loadMore.addEventListener('click', () => {
mobileVisible += 9;
render();
});
previous.addEventListener('click', () => {
if (currentPage > 1) { currentPage--; render(); }
});
next.addEventListener('click', () => {
if (currentPage < Math.ceil(cards.filter(matches).length / 12)) { currentPage++; render(); }
});
mobile.addEventListener('change', render);
render();
})();