Update templates/index.html
Browse files- templates/index.html +94 -30
templates/index.html
CHANGED
@@ -192,7 +192,7 @@
|
|
192 |
object-fit: cover;
|
193 |
}
|
194 |
.preview-item .pdf-icon {
|
195 |
-
font-size: 3rem;
|
196 |
color: var(--danger-color);
|
197 |
}
|
198 |
.preview-item span {
|
@@ -203,7 +203,6 @@
|
|
203 |
text-align: center;
|
204 |
}
|
205 |
|
206 |
-
|
207 |
.button {
|
208 |
width: 100%;
|
209 |
padding: var(--spacing-unit);
|
@@ -230,13 +229,12 @@
|
|
230 |
|
231 |
.clear-button {
|
232 |
background-color: var(--danger-color);
|
233 |
-
margin-top: 0;
|
234 |
}
|
235 |
.clear-button:hover:not(:disabled) {
|
236 |
background-color: var(--danger-hover);
|
237 |
}
|
238 |
|
239 |
-
|
240 |
.copy-button {
|
241 |
background-color: var(--secondary-color);
|
242 |
}
|
@@ -245,6 +243,23 @@
|
|
245 |
background-color: var(--secondary-hover);
|
246 |
}
|
247 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
#solving-container {
|
249 |
display: none;
|
250 |
background-color: #f9f9f9;
|
@@ -383,6 +398,10 @@
|
|
383 |
</div>
|
384 |
</div>
|
385 |
|
|
|
|
|
|
|
|
|
386 |
<div id="upload-section" class="upload-section">
|
387 |
<div class="upload-icon">📤</div>
|
388 |
<p>Cliquez ou glissez-déposez vos images et/ou 1 fichier PDF ici</p>
|
@@ -422,13 +441,66 @@
|
|
422 |
const copyButton = document.getElementById('copy-button');
|
423 |
const statusElement = document.getElementById('status');
|
424 |
const loadingText = document.getElementById('loading-text');
|
|
|
|
|
425 |
|
426 |
-
let selectedFiles = [];
|
|
|
|
|
|
|
|
|
|
|
427 |
|
428 |
window.selectStyle = function(style) {
|
429 |
document.getElementById(`style-${style}`).checked = true;
|
430 |
};
|
431 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
432 |
uploadSection.addEventListener('click', () => fileInput.click());
|
433 |
|
434 |
uploadSection.addEventListener('dragover', (e) => {
|
@@ -464,15 +536,14 @@
|
|
464 |
|
465 |
newFiles.forEach(file => {
|
466 |
if (file.type.startsWith('image/')) {
|
467 |
-
if (!selectedFiles.some(sf => sf.name === file.name && sf.size === file.size)) {
|
468 |
selectedFiles.push(file);
|
469 |
}
|
470 |
} else if (file.type === 'application/pdf') {
|
471 |
if (!pdfAlreadySelected) {
|
472 |
-
// Supprimer tout PDF existant avant d'ajouter le nouveau
|
473 |
selectedFiles = selectedFiles.filter(f => f.type !== 'application/pdf');
|
474 |
selectedFiles.push(file);
|
475 |
-
pdfAlreadySelected = true;
|
476 |
} else {
|
477 |
alert('Vous ne pouvez sélectionner qu\'un seul fichier PDF.');
|
478 |
}
|
@@ -489,7 +560,7 @@
|
|
489 |
}
|
490 |
|
491 |
function updateFilePreviews() {
|
492 |
-
filePreviewArea.innerHTML = '';
|
493 |
|
494 |
if (selectedFiles.length === 0) {
|
495 |
filePreviewArea.style.display = 'none';
|
@@ -504,7 +575,6 @@
|
|
504 |
const fileNameSpan = document.createElement('span');
|
505 |
fileNameSpan.textContent = file.name.length > 15 ? file.name.substring(0,12) + "..." : file.name;
|
506 |
|
507 |
-
|
508 |
if (file.type.startsWith('image/')) {
|
509 |
const img = document.createElement('img');
|
510 |
const reader = new FileReader();
|
@@ -516,7 +586,7 @@
|
|
516 |
} else if (file.type === 'application/pdf') {
|
517 |
const pdfIcon = document.createElement('div');
|
518 |
pdfIcon.classList.add('pdf-icon');
|
519 |
-
pdfIcon.textContent = '📄';
|
520 |
previewItem.appendChild(pdfIcon);
|
521 |
}
|
522 |
previewItem.appendChild(fileNameSpan);
|
@@ -525,10 +595,14 @@
|
|
525 |
}
|
526 |
|
527 |
function updateButtonsState() {
|
528 |
-
if (selectedFiles.length > 0) {
|
529 |
solveButton.disabled = false;
|
530 |
solveButton.textContent = `🔍 Résoudre (${selectedFiles.length} fichier(s))`;
|
531 |
clearFilesButton.style.display = 'block';
|
|
|
|
|
|
|
|
|
532 |
} else {
|
533 |
solveButton.disabled = true;
|
534 |
solveButton.textContent = '🔍 Résoudre';
|
@@ -538,7 +612,7 @@
|
|
538 |
|
539 |
clearFilesButton.addEventListener('click', () => {
|
540 |
selectedFiles = [];
|
541 |
-
fileInput.value = '';
|
542 |
updateFilePreviews();
|
543 |
updateButtonsState();
|
544 |
solvingContainer.style.display = 'none';
|
@@ -546,10 +620,13 @@
|
|
546 |
});
|
547 |
|
548 |
solveButton.addEventListener('click', () => {
|
549 |
-
if (selectedFiles.length === 0) return;
|
550 |
|
551 |
const selectedStyle = document.querySelector('input[name="resolution-style"]:checked').value;
|
552 |
|
|
|
|
|
|
|
553 |
solveButton.disabled = true;
|
554 |
solveButton.textContent = '⏳ Traitement...';
|
555 |
solvingContainer.style.display = 'block';
|
@@ -561,14 +638,9 @@
|
|
561 |
|
562 |
const formData = new FormData();
|
563 |
selectedFiles.forEach(file => {
|
564 |
-
formData.append('user_files', file);
|
565 |
});
|
566 |
formData.append('style', selectedStyle);
|
567 |
-
|
568 |
-
// Pour le débogage : afficher le contenu de FormData
|
569 |
-
// for (let [key, value] of formData.entries()) {
|
570 |
-
// console.log(`${key}: ${value.name || value}`);
|
571 |
-
// }
|
572 |
|
573 |
fetch('/solve', {
|
574 |
method: 'POST',
|
@@ -595,7 +667,7 @@
|
|
595 |
|
596 |
if (data.error) {
|
597 |
handleError(data.error);
|
598 |
-
eventSource.close();
|
599 |
return;
|
600 |
}
|
601 |
|
@@ -633,8 +705,7 @@
|
|
633 |
case 'completed':
|
634 |
statusElement.className = 'status completed';
|
635 |
statusElement.textContent = 'Traitement terminé avec succès ! 🎉';
|
636 |
-
responseDiv.innerHTML =
|
637 |
-
renderMathInElement(responseDiv);
|
638 |
showResponse();
|
639 |
break;
|
640 |
case 'error':
|
@@ -646,14 +717,9 @@
|
|
646 |
function showResponse() {
|
647 |
responseContainer.style.display = 'block';
|
648 |
loadingText.style.display = 'none';
|
649 |
-
// Ne pas réactiver le bouton ici si on veut attendre que l'utilisateur efface les fichiers
|
650 |
-
// solveButton.disabled = false;
|
651 |
-
// solveButton.textContent = `🔍 Résoudre (${selectedFiles.length} fichier(s))`;
|
652 |
-
// Laisser le bouton "Effacer les fichiers" comme principal moyen de recommencer
|
653 |
}
|
654 |
|
655 |
function handleEventSourceError(taskId) {
|
656 |
-
// Essayer de récupérer l'état final de la tâche
|
657 |
fetch('/task/' + taskId)
|
658 |
.then(response => {
|
659 |
if (!response.ok) {
|
@@ -670,7 +736,6 @@
|
|
670 |
} else if (taskData.status === 'error' || taskData.error) {
|
671 |
handleError(taskData.error || 'Une erreur est survenue lors du traitement de la tâche.');
|
672 |
} else {
|
673 |
-
// Si la tâche n'est pas terminée ou en erreur, mais que le flux est perdu.
|
674 |
handleError('La connexion au flux a été perdue. Vérifiez Telegram ou réessayez plus tard.');
|
675 |
}
|
676 |
})
|
@@ -690,7 +755,6 @@
|
|
690 |
}, 2000);
|
691 |
})
|
692 |
.catch(() => {
|
693 |
-
// Fallback pour les anciens navigateurs
|
694 |
const range = document.createRange();
|
695 |
range.selectNode(responseDiv);
|
696 |
window.getSelection().removeAllRanges();
|
|
|
192 |
object-fit: cover;
|
193 |
}
|
194 |
.preview-item .pdf-icon {
|
195 |
+
font-size: 3rem;
|
196 |
color: var(--danger-color);
|
197 |
}
|
198 |
.preview-item span {
|
|
|
203 |
text-align: center;
|
204 |
}
|
205 |
|
|
|
206 |
.button {
|
207 |
width: 100%;
|
208 |
padding: var(--spacing-unit);
|
|
|
229 |
|
230 |
.clear-button {
|
231 |
background-color: var(--danger-color);
|
232 |
+
margin-top: 0;
|
233 |
}
|
234 |
.clear-button:hover:not(:disabled) {
|
235 |
background-color: var(--danger-hover);
|
236 |
}
|
237 |
|
|
|
238 |
.copy-button {
|
239 |
background-color: var(--secondary-color);
|
240 |
}
|
|
|
243 |
background-color: var(--secondary-hover);
|
244 |
}
|
245 |
|
246 |
+
.cooldown-notice {
|
247 |
+
background-color: #fff3cd;
|
248 |
+
border: 1px solid #ffeaa7;
|
249 |
+
border-radius: 0.5rem;
|
250 |
+
padding: var(--spacing-unit);
|
251 |
+
margin: var(--spacing-unit) 0;
|
252 |
+
text-align: center;
|
253 |
+
color: #856404;
|
254 |
+
font-weight: 500;
|
255 |
+
}
|
256 |
+
|
257 |
+
.cooldown-timer {
|
258 |
+
font-size: 1.2rem;
|
259 |
+
color: #d63031;
|
260 |
+
font-weight: bold;
|
261 |
+
}
|
262 |
+
|
263 |
#solving-container {
|
264 |
display: none;
|
265 |
background-color: #f9f9f9;
|
|
|
398 |
</div>
|
399 |
</div>
|
400 |
|
401 |
+
<div id="cooldown-notice" class="cooldown-notice" style="display: none;">
|
402 |
+
⏰ Veuillez attendre <span id="cooldown-timer" class="cooldown-timer">2:00</span> avant de pouvoir soumettre à nouveau.
|
403 |
+
</div>
|
404 |
+
|
405 |
<div id="upload-section" class="upload-section">
|
406 |
<div class="upload-icon">📤</div>
|
407 |
<p>Cliquez ou glissez-déposez vos images et/ou 1 fichier PDF ici</p>
|
|
|
441 |
const copyButton = document.getElementById('copy-button');
|
442 |
const statusElement = document.getElementById('status');
|
443 |
const loadingText = document.getElementById('loading-text');
|
444 |
+
const cooldownNotice = document.getElementById('cooldown-notice');
|
445 |
+
const cooldownTimer = document.getElementById('cooldown-timer');
|
446 |
|
447 |
+
let selectedFiles = [];
|
448 |
+
let cooldownEndTime = 0;
|
449 |
+
let cooldownInterval = null;
|
450 |
+
|
451 |
+
// Vérifier le cooldown au chargement de la page
|
452 |
+
checkCooldownOnLoad();
|
453 |
|
454 |
window.selectStyle = function(style) {
|
455 |
document.getElementById(`style-${style}`).checked = true;
|
456 |
};
|
457 |
|
458 |
+
function checkCooldownOnLoad() {
|
459 |
+
const savedCooldownEndTime = localStorage.getItem('mariamCooldownEndTime');
|
460 |
+
if (savedCooldownEndTime) {
|
461 |
+
const endTime = parseInt(savedCooldownEndTime);
|
462 |
+
const now = Date.now();
|
463 |
+
if (now < endTime) {
|
464 |
+
cooldownEndTime = endTime;
|
465 |
+
startCooldownTimer();
|
466 |
+
} else {
|
467 |
+
localStorage.removeItem('mariamCooldownEndTime');
|
468 |
+
}
|
469 |
+
}
|
470 |
+
}
|
471 |
+
|
472 |
+
function startCooldown() {
|
473 |
+
cooldownEndTime = Date.now() + (2 * 60 * 1000); // 2 minutes
|
474 |
+
localStorage.setItem('mariamCooldownEndTime', cooldownEndTime.toString());
|
475 |
+
startCooldownTimer();
|
476 |
+
}
|
477 |
+
|
478 |
+
function startCooldownTimer() {
|
479 |
+
cooldownNotice.style.display = 'block';
|
480 |
+
solveButton.disabled = true;
|
481 |
+
|
482 |
+
cooldownInterval = setInterval(() => {
|
483 |
+
const now = Date.now();
|
484 |
+
const remainingTime = Math.max(0, cooldownEndTime - now);
|
485 |
+
|
486 |
+
if (remainingTime <= 0) {
|
487 |
+
clearInterval(cooldownInterval);
|
488 |
+
cooldownNotice.style.display = 'none';
|
489 |
+
localStorage.removeItem('mariamCooldownEndTime');
|
490 |
+
updateButtonsState(); // Réactiver le bouton si des fichiers sont sélectionnés
|
491 |
+
return;
|
492 |
+
}
|
493 |
+
|
494 |
+
const minutes = Math.floor(remainingTime / 60000);
|
495 |
+
const seconds = Math.floor((remainingTime % 60000) / 1000);
|
496 |
+
cooldownTimer.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
|
497 |
+
}, 1000);
|
498 |
+
}
|
499 |
+
|
500 |
+
function isCooldownActive() {
|
501 |
+
return Date.now() < cooldownEndTime;
|
502 |
+
}
|
503 |
+
|
504 |
uploadSection.addEventListener('click', () => fileInput.click());
|
505 |
|
506 |
uploadSection.addEventListener('dragover', (e) => {
|
|
|
536 |
|
537 |
newFiles.forEach(file => {
|
538 |
if (file.type.startsWith('image/')) {
|
539 |
+
if (!selectedFiles.some(sf => sf.name === file.name && sf.size === file.size)) {
|
540 |
selectedFiles.push(file);
|
541 |
}
|
542 |
} else if (file.type === 'application/pdf') {
|
543 |
if (!pdfAlreadySelected) {
|
|
|
544 |
selectedFiles = selectedFiles.filter(f => f.type !== 'application/pdf');
|
545 |
selectedFiles.push(file);
|
546 |
+
pdfAlreadySelected = true;
|
547 |
} else {
|
548 |
alert('Vous ne pouvez sélectionner qu\'un seul fichier PDF.');
|
549 |
}
|
|
|
560 |
}
|
561 |
|
562 |
function updateFilePreviews() {
|
563 |
+
filePreviewArea.innerHTML = '';
|
564 |
|
565 |
if (selectedFiles.length === 0) {
|
566 |
filePreviewArea.style.display = 'none';
|
|
|
575 |
const fileNameSpan = document.createElement('span');
|
576 |
fileNameSpan.textContent = file.name.length > 15 ? file.name.substring(0,12) + "..." : file.name;
|
577 |
|
|
|
578 |
if (file.type.startsWith('image/')) {
|
579 |
const img = document.createElement('img');
|
580 |
const reader = new FileReader();
|
|
|
586 |
} else if (file.type === 'application/pdf') {
|
587 |
const pdfIcon = document.createElement('div');
|
588 |
pdfIcon.classList.add('pdf-icon');
|
589 |
+
pdfIcon.textContent = '📄';
|
590 |
previewItem.appendChild(pdfIcon);
|
591 |
}
|
592 |
previewItem.appendChild(fileNameSpan);
|
|
|
595 |
}
|
596 |
|
597 |
function updateButtonsState() {
|
598 |
+
if (selectedFiles.length > 0 && !isCooldownActive()) {
|
599 |
solveButton.disabled = false;
|
600 |
solveButton.textContent = `🔍 Résoudre (${selectedFiles.length} fichier(s))`;
|
601 |
clearFilesButton.style.display = 'block';
|
602 |
+
} else if (selectedFiles.length > 0 && isCooldownActive()) {
|
603 |
+
solveButton.disabled = true;
|
604 |
+
solveButton.textContent = `🔍 Résoudre (${selectedFiles.length} fichier(s))`;
|
605 |
+
clearFilesButton.style.display = 'block';
|
606 |
} else {
|
607 |
solveButton.disabled = true;
|
608 |
solveButton.textContent = '🔍 Résoudre';
|
|
|
612 |
|
613 |
clearFilesButton.addEventListener('click', () => {
|
614 |
selectedFiles = [];
|
615 |
+
fileInput.value = '';
|
616 |
updateFilePreviews();
|
617 |
updateButtonsState();
|
618 |
solvingContainer.style.display = 'none';
|
|
|
620 |
});
|
621 |
|
622 |
solveButton.addEventListener('click', () => {
|
623 |
+
if (selectedFiles.length === 0 || isCooldownActive()) return;
|
624 |
|
625 |
const selectedStyle = document.querySelector('input[name="resolution-style"]:checked').value;
|
626 |
|
627 |
+
// Démarrer le cooldown immédiatement
|
628 |
+
startCooldown();
|
629 |
+
|
630 |
solveButton.disabled = true;
|
631 |
solveButton.textContent = '⏳ Traitement...';
|
632 |
solvingContainer.style.display = 'block';
|
|
|
638 |
|
639 |
const formData = new FormData();
|
640 |
selectedFiles.forEach(file => {
|
641 |
+
formData.append('user_files', file);
|
642 |
});
|
643 |
formData.append('style', selectedStyle);
|
|
|
|
|
|
|
|
|
|
|
644 |
|
645 |
fetch('/solve', {
|
646 |
method: 'POST',
|
|
|
667 |
|
668 |
if (data.error) {
|
669 |
handleError(data.error);
|
670 |
+
eventSource.close();
|
671 |
return;
|
672 |
}
|
673 |
|
|
|
705 |
case 'completed':
|
706 |
statusElement.className = 'status completed';
|
707 |
statusElement.textContent = 'Traitement terminé avec succès ! 🎉';
|
708 |
+
responseDiv.innerHTML = '<p style="color: #2ecc71; font-size: 1.2rem; text-align: center; font-weight: bold;">📄 Votre PDF est disponible sur Telegram</p>';
|
|
|
709 |
showResponse();
|
710 |
break;
|
711 |
case 'error':
|
|
|
717 |
function showResponse() {
|
718 |
responseContainer.style.display = 'block';
|
719 |
loadingText.style.display = 'none';
|
|
|
|
|
|
|
|
|
720 |
}
|
721 |
|
722 |
function handleEventSourceError(taskId) {
|
|
|
723 |
fetch('/task/' + taskId)
|
724 |
.then(response => {
|
725 |
if (!response.ok) {
|
|
|
736 |
} else if (taskData.status === 'error' || taskData.error) {
|
737 |
handleError(taskData.error || 'Une erreur est survenue lors du traitement de la tâche.');
|
738 |
} else {
|
|
|
739 |
handleError('La connexion au flux a été perdue. Vérifiez Telegram ou réessayez plus tard.');
|
740 |
}
|
741 |
})
|
|
|
755 |
}, 2000);
|
756 |
})
|
757 |
.catch(() => {
|
|
|
758 |
const range = document.createRange();
|
759 |
range.selectNode(responseDiv);
|
760 |
window.getSelection().removeAllRanges();
|