diff --git a/data/db.sqlite3 b/data/db.sqlite3 index 3230a49..5e07870 100644 Binary files a/data/db.sqlite3 and b/data/db.sqlite3 differ diff --git a/links/templates/links/collection_detail.html b/links/templates/links/collection_detail.html index 360cb16..24a2bae 100644 --- a/links/templates/links/collection_detail.html +++ b/links/templates/links/collection_detail.html @@ -166,8 +166,10 @@ const dropzone = new Dropzone("#uploadForm", { }, paramName: "file", acceptedFiles: 'image/*', - parallelUploads: 4, + parallelUploads: 5, maxFilesize: 10, + uploadMultiple: false, // Process one file at a time + autoProcessQueue: true, dictDefaultMessage: `
@@ -180,18 +182,41 @@ const dropzone = new Dropzone("#uploadForm", {
`, init: function() { - this.on("success", function(file, response) { - console.log("Upload successful:", response); + let totalFiles = 0; + let completedFiles = 0; + + this.on("addedfile", function(file) { + totalFiles++; + console.log(`Added file: ${file.name}. Total files: ${totalFiles}`); }); + + this.on("success", function(file, response) { + completedFiles++; + console.log(`Upload successful: ${file.name}. Completed: ${completedFiles}/${totalFiles}`); + file.previewElement.classList.add('dz-success'); + }); + this.on("error", function(file, errorMessage) { - console.error("Upload error:", errorMessage); + console.error(`Upload error for ${file.name}:`, errorMessage); + completedFiles++; + file.previewElement.classList.add('dz-error'); alert(typeof errorMessage === 'string' ? errorMessage : errorMessage.error || 'Upload failed'); }); + this.on("queuecomplete", function() { - console.log("All uploads completed"); - setTimeout(() => { - location.reload(); - }, 1000); + console.log("Queue complete. All files processed."); + if (completedFiles === totalFiles) { + console.log("All files uploaded successfully. Reloading page..."); + setTimeout(() => { + location.reload(); + }, 1000); + } + }); + + // Reset counters when queue is cleared + this.on("reset", function() { + totalFiles = 0; + completedFiles = 0; }); } }); diff --git a/links/templates/links/collection_slideshow.html b/links/templates/links/collection_slideshow.html index 20ce6dd..b405af3 100644 --- a/links/templates/links/collection_slideshow.html +++ b/links/templates/links/collection_slideshow.html @@ -68,20 +68,43 @@ .control-button:hover { background: rgba(255,255,255,0.2); } - .progress-bar { + .progress-circle { position: fixed; - top: 0; - left: 0; - height: 2px; - background: #3b82f6; - transition: width 0.1s linear; + bottom: 2rem; + right: 2rem; + width: 32px; + height: 32px; + z-index: 50; + opacity: 0.8; + } + .progress-circle-bg { + fill: none; + stroke: rgba(255, 255, 255, 0.2); + stroke-width: 2.5; + } + .progress-circle-path { + fill: none; + stroke: #3b82f6; + stroke-width: 2.5; + stroke-linecap: round; + transform: rotate(-90deg); + transform-origin: center; } {% endblock %} {% block content %}
-
+
+ + + + +
{% for image in collection.images.all %}
@@ -124,10 +147,11 @@ let currentSlide = 0; const slides = document.querySelectorAll('.slide'); const totalSlides = slides.length; let slideInterval = null; +let progressInterval = null; let isPlaying = true; const INTERVAL_TIME = 5000; // 5 seconds -let progressWidth = 0; -let progressInterval = null; +let startTime = null; +let animationFrame = null; function showSlide(index) { slides.forEach(slide => slide.classList.remove('active')); @@ -162,40 +186,55 @@ function togglePlayPause() { function startSlideshow() { stopSlideshow(); + startTime = Date.now(); slideInterval = setInterval(nextSlide, INTERVAL_TIME); - startProgress(); + updateProgress(); } function stopSlideshow() { clearInterval(slideInterval); - clearInterval(progressInterval); - progressWidth = 0; - updateProgressBar(); + if (animationFrame) { + cancelAnimationFrame(animationFrame); + animationFrame = null; + } + startTime = null; } function exitSlideshow() { window.location.href = '{% url "collection-detail" collection.pk %}'; } -function startProgress() { - progressWidth = 0; - const progressStep = 100 / (INTERVAL_TIME / 10); // Update every 10ms - progressInterval = setInterval(() => { - progressWidth = Math.min(100, progressWidth + progressStep); - updateProgressBar(); - }, 10); +function updateProgress() { + if (!startTime || !isPlaying) return; + + const elapsed = Date.now() - startTime; + const progress = Math.min(100, (elapsed / INTERVAL_TIME) * 100); + + const circle = document.querySelector('.progress-circle-path'); + + // Calculate the circumference of the circle + const radius = 16; + const circumference = 2 * Math.PI * radius; + + // Calculate the dash offset based on progress + const dashOffset = circumference * (1 - progress / 100); + + // Update the circle + circle.style.strokeDasharray = `${circumference} ${circumference}`; + circle.style.strokeDashoffset = dashOffset; + + // Request next frame + animationFrame = requestAnimationFrame(updateProgress); } function resetProgress() { - progressWidth = 0; - updateProgressBar(); + startTime = Date.now(); + if (animationFrame) { + cancelAnimationFrame(animationFrame); + } if (isPlaying) { - startProgress(); + updateProgress(); } -} - -function updateProgressBar() { - document.getElementById('progressBar').style.width = `${progressWidth}%`; } // Keyboard controls @@ -216,7 +255,9 @@ document.addEventListener('keydown', (e) => { } }); -// Start slideshow -startSlideshow(); +// Start slideshow when page loads +document.addEventListener('DOMContentLoaded', () => { + startSlideshow(); +}); {% endblock %}