feat: Implement infinite scroll for the tags page by adding a paginated API endpoint and client-side loading logic.
This commit is contained in:
@@ -2,33 +2,109 @@
|
||||
<div id="main">
|
||||
<div class="container">
|
||||
<h3 style="text-align: center;">☯</h3>
|
||||
<div class="tags-grid">
|
||||
<div class="tags-grid" id="tags-container">
|
||||
@if(session)
|
||||
@each(toptags_regged as toptag)
|
||||
<a href="/tag/{!! toptag.tag !!}" class="tag-card">
|
||||
<a href="/tag/{{ toptag.tag }}" class="tag-card">
|
||||
<div class="tag-card-image">
|
||||
<img src="/tag_image/{!! toptag.tag !!}" loading="lazy" alt="{!! toptag.tag !!}">
|
||||
<img src="/tag_image/{{ toptag.tag }}" loading="lazy" alt="{{ toptag.tag }}">
|
||||
</div>
|
||||
<div class="tag-card-content">
|
||||
<span class="tag-name">#{!! toptag.tag !!}</span>
|
||||
<span class="tag-name">#{{ toptag.tag }}</span>
|
||||
<span class="tag-count">{{ toptag.total_items }} posts</span>
|
||||
</div>
|
||||
</a>
|
||||
@endeach
|
||||
@else
|
||||
@each(toptags as toptag)
|
||||
<a href="/tag/{!! toptag.tag !!}" class="tag-card">
|
||||
<a href="/tag/{{ toptag.tag }}" class="tag-card">
|
||||
<div class="tag-card-image">
|
||||
<img src="/tag_image/{!! toptag.tag !!}" loading="lazy" alt="{!! toptag.tag !!}">
|
||||
<img src="/tag_image/{{ toptag.tag }}" loading="lazy" alt="{{ toptag.tag }}">
|
||||
</div>
|
||||
<div class="tag-card-content">
|
||||
<span class="tag-name">#{!! toptag.tag !!}</span>
|
||||
<span class="tag-name">#{{ toptag.tag }}</span>
|
||||
<span class="tag-count">{{ toptag.total_items }} posts</span>
|
||||
</div>
|
||||
</a>
|
||||
@endeach
|
||||
@endif
|
||||
</div>
|
||||
<div id="tags-loader" style="text-align: center; padding: 20px; display: none;">
|
||||
<span style="color: #888;">Loading more tags...</span>
|
||||
</div>
|
||||
<div id="tags-end" style="text-align: center; padding: 20px; display: none;">
|
||||
<span style="color: #666;">No more tags</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
let page = 1;
|
||||
let loading = false;
|
||||
let hasMore = true;
|
||||
const container = document.getElementById('tags-container');
|
||||
const loader = document.getElementById('tags-loader');
|
||||
const endMsg = document.getElementById('tags-end');
|
||||
|
||||
const escapeHtml = (str) => {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = str;
|
||||
return div.innerHTML;
|
||||
};
|
||||
|
||||
const loadMore = async () => {
|
||||
if (loading || !hasMore) return;
|
||||
loading = true;
|
||||
loader.style.display = 'block';
|
||||
page++;
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/tags?page=${page}`);
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.tags || data.tags.length === 0) {
|
||||
hasMore = false;
|
||||
loader.style.display = 'none';
|
||||
endMsg.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
hasMore = data.hasMore;
|
||||
|
||||
data.tags.forEach(tag => {
|
||||
const escapedTag = escapeHtml(tag.tag);
|
||||
const html = `
|
||||
<a href="/tag/${encodeURIComponent(tag.tag)}" class="tag-card">
|
||||
<div class="tag-card-image">
|
||||
<img src="/tag_image/${encodeURIComponent(tag.tag)}" loading="lazy" alt="${escapedTag}">
|
||||
</div>
|
||||
<div class="tag-card-content">
|
||||
<span class="tag-name">#${escapedTag}</span>
|
||||
<span class="tag-count">${tag.total_items} posts</span>
|
||||
</div>
|
||||
</a>
|
||||
`;
|
||||
container.insertAdjacentHTML('beforeend', html);
|
||||
});
|
||||
|
||||
if (!hasMore) {
|
||||
endMsg.style.display = 'block';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load tags:', e);
|
||||
} finally {
|
||||
loading = false;
|
||||
loader.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
// Infinite scroll
|
||||
window.addEventListener('scroll', () => {
|
||||
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 500) {
|
||||
loadMore();
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@include(snippets/footer)
|
||||
Reference in New Issue
Block a user