112 lines
4.6 KiB
JavaScript
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();
|
|
})();
|