Add pagination with 'Näytä lisää' button (24 posts per page)
Shows 24 posts initially, loads 24 more each click. Resets on filter/search change. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,7 @@
|
|||||||
<section class="controls" id="posts">
|
<section class="controls" id="posts">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="search-row">
|
<div class="search-row">
|
||||||
<input type="text" id="search" data-i18n-ph="search_ph" oninput="filterPosts()" />
|
<input type="text" id="search" data-i18n-ph="search_ph" oninput="visibleCount=POSTS_PER_PAGE;filterPosts()" />
|
||||||
<button class="likes-filter-btn" id="likesFilterBtn" onclick="toggleLikesFilter()">❤️ Tykkäämäni</button>
|
<button class="likes-filter-btn" id="likesFilterBtn" onclick="toggleLikesFilter()">❤️ Tykkäämäni</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="filters" id="categoryFilters"></div>
|
<div class="filters" id="categoryFilters"></div>
|
||||||
@@ -44,6 +44,9 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="recipe-grid" id="postGrid"></div>
|
<div class="recipe-grid" id="postGrid"></div>
|
||||||
<p class="no-results" id="noResults" style="display:none;" data-i18n="no_results"></p>
|
<p class="no-results" id="noResults" style="display:none;" data-i18n="no_results"></p>
|
||||||
|
<div id="loadMoreWrap" style="text-align:center;margin:24px 0;display:none">
|
||||||
|
<button id="loadMoreBtn" onclick="loadMore()" style="padding:10px 32px;font-size:1rem;border:2px solid #c4956a;background:#fff;color:#8b5e3c;border-radius:24px;cursor:pointer;font-weight:600">Näytä lisää</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
30
script.js
30
script.js
@@ -225,11 +225,15 @@ function shuffleArray(arr) {
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const POSTS_PER_PAGE = 24;
|
||||||
|
let visibleCount = POSTS_PER_PAGE;
|
||||||
|
|
||||||
function renderCards() {
|
function renderCards() {
|
||||||
const grid = document.getElementById('postGrid');
|
const grid = document.getElementById('postGrid');
|
||||||
if (!grid) return;
|
if (!grid) return;
|
||||||
|
|
||||||
shuffleArray(APP.posts);
|
shuffleArray(APP.posts);
|
||||||
|
visibleCount = POSTS_PER_PAGE;
|
||||||
grid.innerHTML = APP.posts.map(p => {
|
grid.innerHTML = APP.posts.map(p => {
|
||||||
const liked = APP.userLikes.includes(p.id);
|
const liked = APP.userLikes.includes(p.id);
|
||||||
const likeCount = APP.likes[p.id] || 0;
|
const likeCount = APP.likes[p.id] || 0;
|
||||||
@@ -269,6 +273,7 @@ let currentSubFilter = 'all';
|
|||||||
function setFilter(category, btn) {
|
function setFilter(category, btn) {
|
||||||
currentFilter = category;
|
currentFilter = category;
|
||||||
currentSubFilter = 'all';
|
currentSubFilter = 'all';
|
||||||
|
visibleCount = POSTS_PER_PAGE;
|
||||||
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
|
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
|
||||||
btn.classList.add('active');
|
btn.classList.add('active');
|
||||||
renderSubFilters();
|
renderSubFilters();
|
||||||
@@ -277,6 +282,7 @@ function setFilter(category, btn) {
|
|||||||
|
|
||||||
function setSubFilter(sub, btn) {
|
function setSubFilter(sub, btn) {
|
||||||
currentSubFilter = sub;
|
currentSubFilter = sub;
|
||||||
|
visibleCount = POSTS_PER_PAGE;
|
||||||
document.querySelectorAll('.sub-filter-btn').forEach(b => b.classList.remove('active'));
|
document.querySelectorAll('.sub-filter-btn').forEach(b => b.classList.remove('active'));
|
||||||
btn.classList.add('active');
|
btn.classList.add('active');
|
||||||
filterPosts();
|
filterPosts();
|
||||||
@@ -297,7 +303,8 @@ function renderSubFilters() {
|
|||||||
function filterPosts() {
|
function filterPosts() {
|
||||||
const query = (document.getElementById('search')?.value || '').toLowerCase();
|
const query = (document.getElementById('search')?.value || '').toLowerCase();
|
||||||
const cards = document.querySelectorAll('.recipe-card');
|
const cards = document.querySelectorAll('.recipe-card');
|
||||||
let visible = 0;
|
let matched = 0;
|
||||||
|
let shown = 0;
|
||||||
cards.forEach(card => {
|
cards.forEach(card => {
|
||||||
const matchesCat = currentFilter === 'all' || card.dataset.category === currentFilter;
|
const matchesCat = currentFilter === 'all' || card.dataset.category === currentFilter;
|
||||||
const postSubs = (card.dataset.subcategory || '').split(',').filter(Boolean);
|
const postSubs = (card.dataset.subcategory || '').split(',').filter(Boolean);
|
||||||
@@ -309,12 +316,24 @@ function filterPosts() {
|
|||||||
const matchesSearch = !query || title.includes(query) || desc.includes(query) || subLbl.includes(query) || author.includes(query);
|
const matchesSearch = !query || title.includes(query) || desc.includes(query) || subLbl.includes(query) || author.includes(query);
|
||||||
const postId = card.querySelector('[data-like-id]')?.dataset.likeId || '';
|
const postId = card.querySelector('[data-like-id]')?.dataset.likeId || '';
|
||||||
const matchesLikes = !APP.showOnlyLiked || APP.userLikes.includes(postId);
|
const matchesLikes = !APP.showOnlyLiked || APP.userLikes.includes(postId);
|
||||||
const show = matchesCat && matchesSub && matchesSearch && matchesLikes;
|
const matchesFilter = matchesCat && matchesSub && matchesSearch && matchesLikes;
|
||||||
card.style.display = show ? '' : 'none';
|
if (matchesFilter) {
|
||||||
if (show) visible++;
|
matched++;
|
||||||
|
card.style.display = matched <= visibleCount ? '' : 'none';
|
||||||
|
if (matched <= visibleCount) shown++;
|
||||||
|
} else {
|
||||||
|
card.style.display = 'none';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
const noRes = document.getElementById('noResults');
|
const noRes = document.getElementById('noResults');
|
||||||
if (noRes) noRes.style.display = visible === 0 ? 'block' : 'none';
|
if (noRes) noRes.style.display = matched === 0 ? 'block' : 'none';
|
||||||
|
const wrap = document.getElementById('loadMoreWrap');
|
||||||
|
if (wrap) wrap.style.display = matched > shown ? '' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadMore() {
|
||||||
|
visibleCount += POSTS_PER_PAGE;
|
||||||
|
filterPosts();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===========================
|
// ===========================
|
||||||
@@ -930,6 +949,7 @@ async function init() {
|
|||||||
renderCategoryFilters();
|
renderCategoryFilters();
|
||||||
renderSubFilters();
|
renderSubFilters();
|
||||||
renderCards();
|
renderCards();
|
||||||
|
filterPosts();
|
||||||
|
|
||||||
// Open post from URL hash (e.g. #resepti/pinaattiletut)
|
// Open post from URL hash (e.g. #resepti/pinaattiletut)
|
||||||
const hash = window.location.hash;
|
const hash = window.location.hash;
|
||||||
|
|||||||
Reference in New Issue
Block a user