ui change to improve tag list load

This commit is contained in:
Bryan Van Deusen
2026-01-24 12:14:27 -05:00
parent 9ebeeed133
commit 5af1dcbd4f
5 changed files with 253 additions and 76 deletions
+34
View File
@@ -0,0 +1,34 @@
<!-- /app/templates/_tag_cards.html -->
{% for tag in tag_data %}
<div class="tag-card" data-tag-id="{{ tag.id }}" data-tag-name="{{ tag.tag }}" data-tag-kind="{{ tag.kind }}">
<a href="{{ url_for('main.gallery', tag=tag.tag) }}" class="tag-card-link">
<div class="tag-preview">
{% for image in tag.images %}
<img class="tag-thumb"
src="{{ url_for('main.serve_image', filename=(image.thumb_path or image.filepath) | replace('/images/', '') ) }}"
loading="lazy"
alt="">
{% endfor %}
{% if tag.images|length == 0 %}
<div class="tag-thumb tag-thumb-empty"></div>
{% endif %}
</div>
<div class="tag-card-info">
<span class="tag-icon">
{%- if tag.kind == 'artist' -%}🎨
{%- elif tag.kind == 'character' -%}👤
{%- elif tag.kind == 'series' -%}📺
{%- elif tag.kind == 'fandom' -%}🎭
{%- elif tag.kind == 'rating' -%}⚠️
{%- elif tag.kind == 'archive' -%}🗜️
{%- elif tag.kind == 'source' -%}🌐
{%- elif tag.kind == 'post' -%}📌
{%- else -%}#{%- endif -%}
</span>
<span class="tag-name" title="{{ tag.name }}">{{ tag.name }}</span>
<span class="tag-count">{{ tag.count }}</span>
</div>
</a>
<button class="tag-edit-btn" title="Edit tag" data-tag-id="{{ tag.id }}">✏️</button>
</div>
{% endfor %}
+106 -34
View File
@@ -70,41 +70,27 @@
</div>
{% if tag_data %}
<div class="tag-grid">
{% for tag in tag_data %}
<div class="tag-card" data-tag-id="{{ tag.id }}" data-tag-name="{{ tag.tag }}" data-tag-kind="{{ tag.kind }}">
<a href="{{ url_for('main.gallery', tag=tag.tag) }}" class="tag-card-link">
<div class="tag-preview">
{% for image in tag.images %}
<img class="tag-thumb"
src="{{ url_for('main.serve_image', filename=(image.thumb_path or image.filepath) | replace('/images/', '') ) }}"
loading="lazy"
alt="">
{% endfor %}
{% if tag.images|length == 0 %}
<div class="tag-thumb tag-thumb-empty"></div>
{% endif %}
</div>
<div class="tag-card-info">
<span class="tag-icon">
{%- if tag.kind == 'artist' -%}🎨
{%- elif tag.kind == 'character' -%}👤
{%- elif tag.kind == 'series' -%}📺
{%- elif tag.kind == 'fandom' -%}🎭
{%- elif tag.kind == 'rating' -%}⚠️
{%- elif tag.kind == 'archive' -%}🗜️
{%- elif tag.kind == 'source' -%}🌐
{%- elif tag.kind == 'post' -%}📌
{%- else -%}#{%- endif -%}
</span>
<span class="tag-name" title="{{ tag.name }}">{{ tag.name }}</span>
<span class="tag-count">{{ tag.count }}</span>
</div>
</a>
<button class="tag-edit-btn" title="Edit tag" data-tag-id="{{ tag.id }}">✏️</button>
</div>
{% endfor %}
<div class="tag-grid" id="tagGrid">
{% include '_tag_cards.html' %}
</div>
<!-- Infinite scroll sentinel and loading indicator -->
<div id="tagScrollSentinel" class="scroll-sentinel" {% if not has_more %}style="display: none;"{% endif %}></div>
<div id="tagLoadingIndicator" class="loading-indicator" style="display: none;">
<span class="spinner"></span> Loading more tags...
</div>
<!-- Infinite scroll state -->
<script>
window.tagListState = {
kind: {{ (active_kind | tojson) if active_kind else 'null' }},
offset: {{ tag_data | length }},
pageSize: {{ page_size }},
hasMore: {{ 'true' if has_more else 'false' }},
loading: false,
total: {{ total_count }}
};
</script>
{% else %}
<p class="empty-state">No tags found in this category.</p>
{% endif %}
@@ -146,4 +132,90 @@
</div>
<script src="{{ url_for('static', filename='js/tag-editor.js') }}"></script>
<script>
// Tag list infinite scroll
(function() {
const state = window.tagListState;
if (!state) return;
const grid = document.getElementById('tagGrid');
const sentinel = document.getElementById('tagScrollSentinel');
const loading = document.getElementById('tagLoadingIndicator');
if (!grid || !sentinel) return;
async function loadMoreTags() {
if (state.loading || !state.hasMore) return;
state.loading = true;
loading.style.display = 'flex';
try {
const params = new URLSearchParams({
offset: state.offset,
limit: state.pageSize
});
if (state.kind) {
params.set('kind', state.kind);
}
const response = await fetch(`/api/tags/list?${params}`);
const data = await response.json();
if (data.ok && data.html) {
// Append new cards to grid
grid.insertAdjacentHTML('beforeend', data.html);
// Update state
state.offset = data.offset;
state.hasMore = data.has_more;
// Re-attach edit button listeners for new cards
attachEditListeners();
// Hide sentinel if no more data
if (!state.hasMore) {
sentinel.style.display = 'none';
}
}
} catch (error) {
console.error('Failed to load more tags:', error);
} finally {
state.loading = false;
loading.style.display = 'none';
}
}
// Re-attach edit button event listeners after loading new cards
function attachEditListeners() {
// The tag-editor.js handles this via event delegation on document,
// so new buttons should work automatically
}
// Set up IntersectionObserver for infinite scroll
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting && state.hasMore && !state.loading) {
loadMoreTags();
}
},
{ rootMargin: '200px' }
);
observer.observe(sentinel);
} else {
// Fallback for older browsers: use scroll event
let scrollTimeout;
window.addEventListener('scroll', () => {
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => {
const scrollY = window.scrollY + window.innerHeight;
const docHeight = document.documentElement.scrollHeight;
if (scrollY >= docHeight - 500 && state.hasMore && !state.loading) {
loadMoreTags();
}
}, 100);
});
}
})();
</script>
{% endblock %}