tweaking series order tools

This commit is contained in:
Bryan Van Deusen
2026-01-22 23:19:06 -05:00
parent a05aee5a07
commit c620c2e041
3 changed files with 130 additions and 4 deletions
+74 -3
View File
@@ -7,7 +7,8 @@
const state = {
isSelectMode: false,
selectedIds: new Set()
selectedIds: new Set(),
selectionOrder: [] // Array to track order of selection
};
// DOM elements (populated on init)
@@ -28,6 +29,8 @@
dom.tagInput = document.getElementById('bulkTagInput');
dom.autocomplete = document.getElementById('bulkTagAutocomplete');
dom.commonTags = document.getElementById('commonTagsList');
dom.floatingPreview = document.getElementById('floatingPreview');
dom.floatingPreviewImage = document.getElementById('floatingPreviewImage');
if (!dom.selectBtn || !dom.panel) return;
@@ -63,6 +66,30 @@
}
}
});
// Preview on hover in select mode
document.addEventListener('mouseenter', handlePreviewShow, true);
document.addEventListener('mouseleave', handlePreviewHide, true);
}
function handlePreviewShow(e) {
if (!state.isSelectMode || !dom.floatingPreview) return;
const item = e.target.closest('.img-clickable');
if (!item) return;
const fullSrc = item.dataset.full;
if (fullSrc && dom.floatingPreviewImage) {
dom.floatingPreviewImage.src = fullSrc;
dom.floatingPreview.classList.add('active');
}
}
function handlePreviewHide(e) {
if (!dom.floatingPreview) return;
const item = e.target.closest('.img-clickable');
if (!item) return;
dom.floatingPreview.classList.remove('active');
}
function toggleSelectMode() {
@@ -104,12 +131,18 @@
if (state.selectedIds.has(id)) {
state.selectedIds.delete(id);
state.selectionOrder = state.selectionOrder.filter(x => x !== id);
item.classList.remove('selected');
removeOrderBadge(item);
} else {
state.selectedIds.add(id);
state.selectionOrder.push(id);
item.classList.add('selected');
addOrderBadge(item, state.selectionOrder.length);
}
// Update all badges to reflect current order
updateAllOrderBadges();
updateCount();
loadCommonTags();
dispatchSelectionChanged();
@@ -117,8 +150,10 @@
function clearSelection() {
state.selectedIds.clear();
state.selectionOrder = [];
document.querySelectorAll('.img-clickable.selected').forEach(el => {
el.classList.remove('selected');
removeOrderBadge(el);
});
updateCount();
updateCommonTagsDisplay();
@@ -133,7 +168,10 @@
function dispatchSelectionChanged() {
document.dispatchEvent(new CustomEvent('selectionChanged', {
detail: { count: state.selectedIds.size }
detail: {
count: state.selectedIds.size,
orderedIds: [...state.selectionOrder]
}
}));
}
@@ -165,11 +203,43 @@
}
function updateSelectionUI() {
// Re-apply selected class to any newly loaded images that are in selection
// Re-apply selected class and order badges to any newly loaded images that are in selection
document.querySelectorAll('.img-clickable').forEach(item => {
const id = parseInt(item.dataset.id);
if (state.selectedIds.has(id)) {
item.classList.add('selected');
const orderIndex = state.selectionOrder.indexOf(id);
if (orderIndex !== -1) {
addOrderBadge(item, orderIndex + 1);
}
}
});
}
// ---------------------------
// Order Badge Helpers
// ---------------------------
function addOrderBadge(item, orderNumber) {
removeOrderBadge(item); // Remove existing badge first
const badge = document.createElement('div');
badge.className = 'selection-order-badge';
badge.textContent = orderNumber;
item.appendChild(badge);
}
function removeOrderBadge(item) {
const existing = item.querySelector('.selection-order-badge');
if (existing) existing.remove();
}
function updateAllOrderBadges() {
document.querySelectorAll('.img-clickable').forEach(item => {
const id = parseInt(item.dataset.id);
const orderIndex = state.selectionOrder.indexOf(id);
if (orderIndex !== -1) {
addOrderBadge(item, orderIndex + 1);
} else {
removeOrderBadge(item);
}
});
}
@@ -474,6 +544,7 @@
// Expose global API for other scripts (like series editor)
window.selectedImages = state.selectedIds;
window.selectionOrder = state.selectionOrder; // Ordered array of selected IDs
window.clearSelection = clearSelection;
window.enableSelectMode = enableSelectMode;
window.disableSelectMode = disableSelectMode;
+49
View File
@@ -2036,6 +2036,55 @@ body.select-mode .gallery-infinite-container {
font-size: 0.85rem;
}
/* Floating preview overlay (for select mode hover) */
.floating-preview {
display: none;
position: fixed;
top: 80px;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
width: 600px;
height: 500px;
background: var(--panel);
border: 2px solid var(--accent);
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
padding: 4px;
pointer-events: none;
}
.floating-preview.active {
display: flex;
align-items: center;
justify-content: center;
}
.floating-preview img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
border-radius: 4px;
}
/* Selection order badge on gallery items */
.selection-order-badge {
position: absolute;
top: 4px;
left: 4px;
width: 24px;
height: 24px;
background: var(--accent);
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
font-weight: bold;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
z-index: 10;
pointer-events: none;
}
/* Mobile: full-width panel from bottom */
@media (max-width: 640px) {
.bulk-editor-panel {
+7 -1
View File
@@ -120,6 +120,11 @@
<!-- Modal -->
{% include '_gallery_modal.html' %}
<!-- Floating Preview (for select mode hover) -->
<div id="floatingPreview" class="floating-preview">
<img id="floatingPreviewImage" src="" alt="Preview">
</div>
<!-- Bulk Editor Panel -->
<aside id="bulkEditorPanel" class="bulk-editor-panel">
<div class="bulk-editor-header">
@@ -204,7 +209,8 @@ document.addEventListener('DOMContentLoaded', () => {
addToSeriesBtn.addEventListener('click', async () => {
if (!window.selectedImages || window.selectedImages.size === 0) return;
const imageIds = Array.from(window.selectedImages);
// Use selectionOrder (click order) for page ordering
const imageIds = window.selectionOrder ? [...window.selectionOrder] : Array.from(window.selectedImages);
const startPage = parseInt(startPageInput.value) || 1;
addToSeriesBtn.disabled = true;