Expanded UI
This commit is contained in:
232
js/enhanced-main.js
Normal file
232
js/enhanced-main.js
Normal file
@@ -0,0 +1,232 @@
|
||||
import { showToast, updateImageInfo } from './utils.js';
|
||||
import SwipeCard from '../components/swipe-card.js';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Track total images and processed count for progress bar
|
||||
const progressState = {
|
||||
totalImages: 0,
|
||||
processedImages: 0
|
||||
};
|
||||
|
||||
// Global state
|
||||
const state = {
|
||||
currentImageInfo: null,
|
||||
currentOrientation: 'all',
|
||||
isLoading: false
|
||||
};
|
||||
|
||||
// DOM elements
|
||||
const lastActionText = document.getElementById('last-action');
|
||||
const orientationFilters = document.querySelector('.orientation-filters');
|
||||
const modal = document.getElementById('fullscreen-modal');
|
||||
const fullscreenImage = document.getElementById('fullscreen-image');
|
||||
const closeModal = document.querySelector('.close-modal');
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
|
||||
// Initialize the enhanced swipe card
|
||||
const swipeCard = new SwipeCard({
|
||||
container: document.querySelector('.swipe-container'),
|
||||
onSwipe: performSwipe,
|
||||
threshold: 100
|
||||
});
|
||||
|
||||
// Make state available to window for debugging and other components
|
||||
window.state = state;
|
||||
window.performSwipe = performSwipe;
|
||||
|
||||
function performSwipe(direction) {
|
||||
if (!state.currentImageInfo) return;
|
||||
|
||||
// Update last action text with the action name instead of direction
|
||||
const actionMap = {
|
||||
left: 'Discarded',
|
||||
right: 'Kept',
|
||||
up: 'Favorited',
|
||||
down: 'Marked for review'
|
||||
};
|
||||
lastActionText.textContent = `Last action: ${actionMap[direction] || 'Unknown'}`;
|
||||
|
||||
// Show toast notification
|
||||
const toastMap = {
|
||||
left: 'Discarded',
|
||||
right: 'Kept',
|
||||
up: 'Favorited',
|
||||
down: 'Marked for review'
|
||||
};
|
||||
showToast(toastMap[direction] || 'Action');
|
||||
|
||||
// Record the selection
|
||||
recordSelection(state.currentImageInfo, direction);
|
||||
|
||||
// Update progress
|
||||
progressState.processedImages++;
|
||||
updateProgressBar();
|
||||
|
||||
// Load new image after animation completes
|
||||
setTimeout(() => {
|
||||
loadNewImage();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function updateProgressBar() {
|
||||
if (progressState.totalImages > 0) {
|
||||
const percentage = (progressState.processedImages / progressState.totalImages) * 100;
|
||||
progressBar.style.width = `${Math.min(percentage, 100)}%`;
|
||||
}
|
||||
}
|
||||
|
||||
function recordSelection(imageInfo, action) {
|
||||
fetch('/selection', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
image_path: imageInfo.path,
|
||||
resolution: imageInfo.resolution,
|
||||
action,
|
||||
}),
|
||||
}).catch(error => console.error('Error recording selection:', error));
|
||||
}
|
||||
|
||||
function loadNewImage() {
|
||||
if (state.isLoading) return;
|
||||
state.isLoading = true;
|
||||
swipeCard.showLoading();
|
||||
|
||||
// First, get the total count if we don't have it yet
|
||||
if (progressState.totalImages === 0) {
|
||||
fetch('/image-count')
|
||||
.then(response => response.json())
|
||||
.catch(() => ({ count: 100 })) // Fallback if endpoint doesn't exist
|
||||
.then(data => {
|
||||
progressState.totalImages = data.count || 100;
|
||||
updateProgressBar();
|
||||
});
|
||||
}
|
||||
|
||||
fetch(`/random-image?orientation=${state.currentOrientation}&t=${new Date().getTime()}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
state.isLoading = false;
|
||||
swipeCard.hideLoading();
|
||||
|
||||
if (data && data.path) {
|
||||
state.currentImageInfo = data;
|
||||
swipeCard.setImage(data);
|
||||
updateImageInfo(data);
|
||||
adjustContainerToImage(data.orientation);
|
||||
} else {
|
||||
swipeCard.card.innerHTML = `<div class="no-images-message">${data.message || 'No more images.'}</div>`;
|
||||
state.currentImageInfo = null;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching image:', error);
|
||||
state.isLoading = false;
|
||||
swipeCard.hideLoading();
|
||||
swipeCard.card.innerHTML = '<div class="no-images-message">Error loading image.</div>';
|
||||
});
|
||||
}
|
||||
|
||||
function adjustContainerToImage(orientation) {
|
||||
const container = document.querySelector('.swipe-container');
|
||||
if (window.innerWidth < 992) { // Only on desktop
|
||||
container.style.transition = 'all 0.5s ease-in-out';
|
||||
if (orientation === 'landscape') {
|
||||
container.style.flex = '4';
|
||||
} else {
|
||||
container.style.flex = '2';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Button event listeners
|
||||
document.getElementById('btn-left').addEventListener('click', () => performSwipe('left'));
|
||||
document.getElementById('btn-right').addEventListener('click', () => performSwipe('right'));
|
||||
document.getElementById('btn-up').addEventListener('click', () => performSwipe('up'));
|
||||
document.getElementById('btn-down').addEventListener('click', () => performSwipe('down'));
|
||||
|
||||
// Orientation filter event listeners
|
||||
orientationFilters.addEventListener('click', (e) => {
|
||||
if (e.target.tagName === 'BUTTON' && !e.target.classList.contains('active')) {
|
||||
orientationFilters.querySelector('.active').classList.remove('active');
|
||||
e.target.classList.add('active');
|
||||
state.currentOrientation = e.target.dataset.orientation;
|
||||
loadNewImage();
|
||||
}
|
||||
});
|
||||
|
||||
// Modal event listeners
|
||||
swipeCard.card.addEventListener('click', () => {
|
||||
if (!swipeCard.state.hasMoved && state.currentImageInfo) {
|
||||
fullscreenImage.src = state.currentImageInfo.path;
|
||||
document.getElementById('modal-resolution').textContent = `Resolution: ${state.currentImageInfo.resolution}`;
|
||||
document.getElementById('modal-filename').textContent = `Filename: ${state.currentImageInfo.filename || 'N/A'}`;
|
||||
document.getElementById('modal-creation-date').textContent = `Creation Date: ${state.currentImageInfo.creation_date || 'N/A'}`;
|
||||
modal.style.display = 'flex';
|
||||
|
||||
// Add animation classes
|
||||
setTimeout(() => {
|
||||
modal.classList.add('show');
|
||||
}, 10);
|
||||
}
|
||||
});
|
||||
|
||||
closeModal.addEventListener('click', () => {
|
||||
modal.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
modal.style.display = 'none';
|
||||
}, 400);
|
||||
});
|
||||
|
||||
modal.addEventListener('click', (e) => {
|
||||
if (e.target === modal) {
|
||||
modal.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
modal.style.display = 'none';
|
||||
}, 400);
|
||||
}
|
||||
});
|
||||
|
||||
// Keyboard event listeners
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (modal.style.display === 'flex' && e.key === 'Escape') {
|
||||
modal.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
modal.style.display = 'none';
|
||||
}, 400);
|
||||
return;
|
||||
}
|
||||
|
||||
if (modal.style.display !== 'flex') {
|
||||
switch (e.key) {
|
||||
case 'ArrowLeft': performSwipe('left'); break;
|
||||
case 'ArrowRight': performSwipe('right'); break;
|
||||
case 'ArrowUp': performSwipe('up'); break;
|
||||
case 'ArrowDown': performSwipe('down'); break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add ripple effect to action buttons
|
||||
document.querySelectorAll('.action-btn').forEach(button => {
|
||||
button.addEventListener('click', function(e) {
|
||||
const ripple = document.createElement('span');
|
||||
ripple.classList.add('ripple');
|
||||
this.appendChild(ripple);
|
||||
|
||||
const rect = button.getBoundingClientRect();
|
||||
const size = Math.max(rect.width, rect.height);
|
||||
|
||||
ripple.style.width = ripple.style.height = `${size}px`;
|
||||
ripple.style.left = `${e.clientX - rect.left - size/2}px`;
|
||||
ripple.style.top = `${e.clientY - rect.top - size/2}px`;
|
||||
|
||||
setTimeout(() => {
|
||||
ripple.remove();
|
||||
}, 600);
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize by loading the first image
|
||||
loadNewImage();
|
||||
});
|
||||
Reference in New Issue
Block a user