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: `
`,
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 %}