improved Modal with zoom and pagination. also implementing thumbnail generation
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
{% if images.pages > 1 %}
|
||||
<div class="pagination-container">
|
||||
{% set total_pages = images.pages %}
|
||||
{% set current_page = images.page %}
|
||||
{% set window_size = 7 %}
|
||||
{% set endpoint = request.endpoint %}
|
||||
|
||||
{% if total_pages <= window_size %}
|
||||
{% set start_page = 1 %}
|
||||
{% set end_page = total_pages %}
|
||||
{% elif current_page <= 4 %}
|
||||
{% set start_page = 1 %}
|
||||
{% set end_page = window_size %}
|
||||
{% elif current_page > total_pages - 4 %}
|
||||
{% set start_page = total_pages - window_size + 1 %}
|
||||
{% set end_page = total_pages %}
|
||||
{% else %}
|
||||
{% set start_page = current_page - 3 %}
|
||||
{% set end_page = current_page + 3 %}
|
||||
{% endif %}
|
||||
|
||||
{# First and Prev #}
|
||||
{% if images.has_prev %}
|
||||
{% if current_page > 1 %}
|
||||
<a class="pagination-link" href="{{ url_for(endpoint, page=1, **request.view_args) }}">« First</a>
|
||||
{% endif %}
|
||||
<a class="pagination-link" href="{{ url_for(endpoint, page=images.prev_num, **request.view_args) }}">← Previous</a>
|
||||
{% endif %}
|
||||
|
||||
{# Left ellipsis #}
|
||||
{% if start_page > 1 %}
|
||||
<a class="pagination-link" href="{{ url_for(endpoint, page=1, **request.view_args) }}">1</a>
|
||||
{% if start_page > 2 %}
|
||||
<span class="pagination-ellipsis">…</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# Page numbers #}
|
||||
{% for p in range(start_page, end_page + 1) %}
|
||||
<a class="pagination-link {% if p == current_page %}active{% endif %}" href="{{ url_for(endpoint, page=p, **request.view_args) }}">{{ p }}</a>
|
||||
{% endfor %}
|
||||
|
||||
{# Right ellipsis #}
|
||||
{% if end_page < total_pages %}
|
||||
{% if end_page < total_pages - 1 %}
|
||||
<span class="pagination-ellipsis">…</span>
|
||||
{% endif %}
|
||||
<a class="pagination-link" href="{{ url_for(endpoint, page=total_pages, **request.view_args) }}">{{ total_pages }}</a>
|
||||
{% endif %}
|
||||
|
||||
{# Next and Last #}
|
||||
{% if images.has_next %}
|
||||
<a class="pagination-link" href="{{ url_for(endpoint, page=images.next_num, **request.view_args) }}">Next →</a>
|
||||
{% if current_page < total_pages %}
|
||||
<a class="pagination-link" href="{{ url_for(endpoint, page=total_pages, **request.view_args) }}">Last »</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -1,54 +1,29 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}{{ artist }}'s Gallery{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 style="text-align:center; margin-top: 1rem;">{{ artist }}</h1>
|
||||
|
||||
<!-- Pagination Controls -->
|
||||
<div class="pagination-container">
|
||||
{% if images.has_prev %}
|
||||
<a class="pagination-link" href="{{ url_for('main.artist_gallery', artist_name=artist, page=images.prev_num) }}">← Previous</a>
|
||||
{% endif %}
|
||||
{% include '_pagination.html' %}
|
||||
|
||||
{% for p in range(1, images.pages + 1) %}
|
||||
<a class="pagination-link {% if p == images.page %}active{% endif %}" href="{{ url_for('main.artist_gallery', artist_name=artist, page=p) }}">{{ p }}</a>
|
||||
{% endfor %}
|
||||
|
||||
{% if images.has_next %}
|
||||
<a class="pagination-link" href="{{ url_for('main.artist_gallery', artist_name=artist, page=images.next_num) }}">Next →</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Gallery Grid -->
|
||||
<div class="gallery-grid">
|
||||
{% for image in images.items %}
|
||||
{% for image in images %}
|
||||
<div class="gallery-item">
|
||||
<div class="gallery-thumb img-clickable"
|
||||
data-full="{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '')) }}"
|
||||
style="background-image: url('{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '')) }}');"
|
||||
data-filename="{{ image.filename }}">
|
||||
data-full="{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '') ) }}"
|
||||
style="background-image: url('{{ url_for('main.serve_image', filename=(image.thumb_path or image.filepath) | replace('/images/', '') ) }}');"
|
||||
data-filename="{{ image.filename }}">
|
||||
</div>
|
||||
<a href="{{ url_for('main.artist_gallery', artist_name=image.artist) }}">{{ image.artist }}</a>
|
||||
<span class="image-date">
|
||||
{{ (image.taken_at or image.imported_at) | datetimeformat }}
|
||||
{{ image.taken_at or image.imported_at | datetimeformat }}
|
||||
</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Pagination Controls -->
|
||||
<div class="pagination-container">
|
||||
{% if images.has_prev %}
|
||||
<a class="pagination-link" href="{{ url_for('main.artist_gallery', artist_name=artist, page=images.prev_num) }}">← Previous</a>
|
||||
{% endif %}
|
||||
{% include '_pagination.html' %}
|
||||
|
||||
{% for p in range(1, images.pages + 1) %}
|
||||
<a class="pagination-link {% if p == images.page %}active{% endif %}" href="{{ url_for('main.artist_gallery', artist_name=artist, page=p) }}">{{ p }}</a>
|
||||
{% endfor %}
|
||||
|
||||
{% if images.has_next %}
|
||||
<a class="pagination-link" href="{{ url_for('main.artist_gallery', artist_name=artist, page=images.next_num) }}">Next →</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
{% block title %}Artists{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 style="text-align:center; margin-top: 1rem;">Artists</h1>
|
||||
|
||||
<h1>Artists</h1>
|
||||
<div class="artist-grid">
|
||||
{% for artist in artist_data %}
|
||||
<a href="{{ url_for('main.artist_gallery', artist_name=artist.name) }}" class="artist-card-link">
|
||||
@@ -12,7 +11,7 @@
|
||||
<div class="artist-preview">
|
||||
{% for image in artist.images %}
|
||||
<div class="artist-thumb"
|
||||
style="background-image: url('{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '')) }}');">
|
||||
style="background-image: url('{{ url_for('main.serve_image', filename=(image.thumb_path or image.filepath) | replace('/images/', '') ) }}');">
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}Gallery{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Gallery Thumbnail Grid -->
|
||||
<h1 style="text-align:center; margin-top: 1rem;">Gallery</h1>
|
||||
|
||||
<!-- Pagination Controls (Top) -->
|
||||
{% include '_pagination.html' %}
|
||||
|
||||
<!-- Gallery Grid -->
|
||||
<div class="gallery-grid">
|
||||
{% for image in images %}
|
||||
{% for image in images.items %}
|
||||
<div class="gallery-item">
|
||||
<div class="gallery-thumb img-clickable"
|
||||
data-full="{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '')) }}"
|
||||
style="background-image: url('{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '')) }}');"
|
||||
data-full="{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '') ) }}"
|
||||
style="background-image: url('{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '') ) }}');"
|
||||
data-filename="{{ image.filename }}">
|
||||
</div>
|
||||
<a href="{{ url_for('main.artist_gallery', artist_name=image.artist) }}">{{ image.artist }}</a>
|
||||
<span class="image-date">
|
||||
{{ (image.taken_at or image.imported_at) | datetimeformat }}
|
||||
{{ image.taken_at or image.imported_at | datetimeformat }}
|
||||
</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Pagination Controls (Bottom) -->
|
||||
{% include '_pagination.html' %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
+24
-80
@@ -31,15 +31,15 @@
|
||||
|
||||
|
||||
<!-- FLASH MESSAGES -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div class="flash-container">
|
||||
{% for category, message in messages %}
|
||||
<div class="flash {{ category }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
<div class="flash flash-{{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -49,86 +49,30 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if request.endpoint == 'main.gallery' or request.endpoint == 'main.artist_gallery' %}
|
||||
<input type="hidden" id="hasNextPage" value="{{ has_next|lower }}">
|
||||
<input type="hidden" id="nextPageUrl" value="{{ next_page_url }}">
|
||||
<input type="hidden" id="hasPrevPage" value="{{ has_prev|lower }}">
|
||||
<input type="hidden" id="prevPageUrl" value="{{ prev_page_url }}">
|
||||
{% endif %}
|
||||
|
||||
|
||||
<!-- Modal -->
|
||||
<div id="imageModal" class="modal">
|
||||
<div class="modal-dialog modal-xl modal-dialog-centered">
|
||||
<div class="modal-content bg-transparent border-0">
|
||||
<button id="modalClose" class="modal-button modal-close">✕</button>
|
||||
<button id="modalPrev" class="modal-button modal-prev">←</button>
|
||||
<button id="modalNext" class="modal-button modal-next">→</button>
|
||||
<div class="modal-body">
|
||||
<h5 id="modalFilename" class="modal-filename"></h5>
|
||||
<img id="modalImage" src="" class="img-fluid">
|
||||
<div class="modal-content">
|
||||
<!-- Navigation buttons -->
|
||||
<button id="modalPrev" class="modal-button modal-prev">←</button>
|
||||
<button id="modalNext" class="modal-button modal-next">→</button>
|
||||
|
||||
<div class="modal-body">
|
||||
<div id="modalImageWrapper" class="modal-image-wrapper">
|
||||
<img id="modalImage" src="" alt="Full View">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const modal = document.getElementById('imageModal');
|
||||
const modalImage = document.getElementById('modalImage');
|
||||
const modalClose = document.getElementById('modalClose');
|
||||
const modalPrev = document.getElementById('modalPrev');
|
||||
const modalNext = document.getElementById('modalNext');
|
||||
const modalFilename = document.getElementById('modalFilename');
|
||||
const images = Array.from(document.querySelectorAll('.img-clickable'));
|
||||
|
||||
let currentIndex = -1;
|
||||
|
||||
function openModal(index) {
|
||||
currentIndex = index;
|
||||
const img = images[currentIndex];
|
||||
modalImage.src = img.dataset.full;
|
||||
modalFilename.textContent = img.dataset.filename || '';
|
||||
modal.classList.add('active');
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
modal.classList.remove('active');
|
||||
modalImage.src = '';
|
||||
modalFilename.textContent = '';
|
||||
currentIndex = -1;
|
||||
}
|
||||
|
||||
function showNext() {
|
||||
if (images.length === 0) return;
|
||||
currentIndex = (currentIndex + 1) % images.length;
|
||||
const img = images[currentIndex];
|
||||
modalImage.src = img.dataset.full;
|
||||
modalFilename.textContent = img.dataset.filename || '';
|
||||
}
|
||||
|
||||
function showPrev() {
|
||||
if (images.length === 0) return;
|
||||
currentIndex = (currentIndex - 1 + images.length) % images.length;
|
||||
const img = images[currentIndex];
|
||||
modalImage.src = img.dataset.full;
|
||||
modalFilename.textContent = img.dataset.filename || '';
|
||||
}
|
||||
|
||||
images.forEach((img, index) => {
|
||||
img.addEventListener('click', () => openModal(index));
|
||||
});
|
||||
|
||||
modalClose.addEventListener('click', closeModal);
|
||||
modalNext.addEventListener('click', showNext);
|
||||
modalPrev.addEventListener('click', showPrev);
|
||||
|
||||
modal.addEventListener('click', (e) => {
|
||||
if (e.target === modal) closeModal();
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (!modal.classList.contains('active')) return;
|
||||
if (e.key === 'ArrowRight') showNext();
|
||||
else if (e.key === 'ArrowLeft') showPrev();
|
||||
else if (e.key === 'Escape') closeModal();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/modal-pagination.js') }}"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -12,9 +12,15 @@
|
||||
<button type="submit" class="btn primary-btn">Trigger Image Import</button>
|
||||
</form>
|
||||
|
||||
<form action="{{ url_for('main.trigger_thumbnail_generation') }}" method="post" onsubmit="return confirm('Are you sure you want to regenerate all thumbnails?');">
|
||||
<button type="submit" class="btn warning-btn">Regenerate Thumbnails</button>
|
||||
</form>
|
||||
|
||||
|
||||
<form action="{{ url_for('main.reset_db') }}" method="post" onsubmit="return confirm('Are you sure you want to delete all image records? This action cannot be undone.');">
|
||||
<button type="submit" class="btn danger-btn">Reset Image Database</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user