From 65993488783052f57c1a20fc0d0057920fe3ee73 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 11 Nov 2025 19:41:17 +0000 Subject: [PATCH] Images: Miniatures avec modal d'agrandissement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les images dans les notes sont maintenant des miniatures qui s'agrandissent dans un modal en plein écran au clic. CSS - Miniatures: - .note-card-image: 140px hauteur (cartes pliées) - .note-image: 200px max-height (notes expandues, réduit de 300px) - Cursor pointer + hover effect (scale 1.02, opacity 0.9) - Indication visuelle qu'on peut cliquer Modal Image: - Fond noir semi-transparent (rgba(0,0,0,0.9)) - Image centrée, max 90vw x 90vh - Bouton fermeture (top-right, backdrop-filter) - z-index 400 (au-dessus de tout) - Animation fadeIn 0.2s Interactions: - Clic sur miniature → Modal avec image en taille réelle - Clic sur fond noir → Ferme le modal - Bouton X → Ferme le modal - Touche Escape → Ferme le modal - Délégation d'événements pour gérer les images après re-render - Désactive scroll pendant que modal ouvert JavaScript: - openImageModal(src): Ouvre modal + désactive scroll - closeImageModal(): Ferme modal + réactive scroll - Event listeners: click, escape, backdrop Bénéfices utilisateur: ✓ Notes plus compactes (images miniatures) ✓ Images consultables en haute qualité (modal) ✓ Navigation intuitive (clic pour agrandir) ✓ Fermeture rapide (X, Escape, backdrop) ✓ Pas de scroll accidentel pendant consultation Files: - public/css/components.css: Miniatures + hover effects - public/css/skeleton.css: Styles modal image - public/index.html: HTML modal image - public/js/complete-app.js: Gestion modal + event listeners --- public/css/components.css | 16 +++++++++- public/css/skeleton.css | 65 +++++++++++++++++++++++++++++++++++++++ public/index.html | 13 ++++++++ public/js/complete-app.js | 58 ++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 1 deletion(-) diff --git a/public/css/components.css b/public/css/components.css index 9931e4d..c9c26aa 100644 --- a/public/css/components.css +++ b/public/css/components.css @@ -84,6 +84,13 @@ object-fit: cover; border-radius: var(--radius-md); margin-bottom: var(--spacing-md); + cursor: pointer; + transition: all var(--transition-fast); +} + +.note-card-image:hover { + opacity: 0.9; + transform: scale(1.02); } .note-todos-preview { @@ -840,9 +847,16 @@ .note-image { width: 100%; - max-height: 300px; + max-height: 200px; object-fit: cover; border-radius: var(--radius-lg); + cursor: pointer; + transition: all var(--transition-fast); +} + +.note-image:hover { + opacity: 0.9; + transform: scale(1.02); } .btn-remove-image { diff --git a/public/css/skeleton.css b/public/css/skeleton.css index 3ca81a1..048282d 100644 --- a/public/css/skeleton.css +++ b/public/css/skeleton.css @@ -293,3 +293,68 @@ transform: translateX(400px); } } + +/* Modal pour agrandir les images */ +.image-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.9); + z-index: 400; + display: none; + align-items: center; + justify-content: center; + padding: 40px; + cursor: pointer; + animation: fadeIn 0.2s ease-in; +} + +.image-modal.active { + display: flex; +} + +.image-modal-content { + position: relative; + max-width: 90vw; + max-height: 90vh; + cursor: default; +} + +.image-modal-img { + max-width: 100%; + max-height: 90vh; + object-fit: contain; + border-radius: var(--radius-md); + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); +} + +.image-modal-close { + position: fixed; + top: 20px; + right: 20px; + width: 48px; + height: 48px; + border: none; + background: rgba(255, 255, 255, 0.1); + color: white; + font-size: 32px; + cursor: pointer; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: all var(--transition-fast); + backdrop-filter: blur(10px); +} + +.image-modal-close:hover { + background: rgba(255, 255, 255, 0.2); + transform: scale(1.1); +} + +.image-modal-close svg { + width: 24px; + height: 24px; +} diff --git a/public/index.html b/public/index.html index 805c915..d4376aa 100644 --- a/public/index.html +++ b/public/index.html @@ -305,6 +305,19 @@
+ +
+
+ +
+ +
+ diff --git a/public/js/complete-app.js b/public/js/complete-app.js index fef8fd1..fe06f6c 100644 --- a/public/js/complete-app.js +++ b/public/js/complete-app.js @@ -534,6 +534,27 @@ function closeNotification(notification) { }, 300); } +// ==================== MODAL IMAGE ==================== +function openImageModal(imageSrc) { + const modal = document.getElementById('imageModal'); + const img = document.getElementById('imageModalImg'); + + if (modal && img) { + img.src = imageSrc; + modal.classList.add('active'); + document.body.style.overflow = 'hidden'; // Désactiver le scroll + } +} + +function closeImageModal() { + const modal = document.getElementById('imageModal'); + + if (modal) { + modal.classList.remove('active'); + document.body.style.overflow = ''; // Réactiver le scroll + } +} + // ==================== INLINE NOTE EXPANSION ==================== function expandNote(noteId) { state.expandedNoteId = noteId; @@ -2263,6 +2284,43 @@ async function init() { if (saveOpenRouterBtn) { saveOpenRouterBtn.addEventListener('click', saveOpenRouterSettings); } + + // ==================== MODAL IMAGE ==================== + // Fermer le modal avec le bouton X + const imageModalClose = document.getElementById('imageModalClose'); + if (imageModalClose) { + imageModalClose.addEventListener('click', closeImageModal); + } + + // Fermer le modal en cliquant sur le fond + const imageModal = document.getElementById('imageModal'); + if (imageModal) { + imageModal.addEventListener('click', (e) => { + if (e.target === imageModal) { + closeImageModal(); + } + }); + } + + // Fermer le modal avec la touche Escape + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + closeImageModal(); + } + }); + + // Délégation d'événements pour les clics sur les images + // Cela permettra de gérer les images même après un re-render + document.addEventListener('click', (e) => { + const target = e.target; + + // Si on clique sur une image de note (miniature) + if (target.classList.contains('note-card-image') || target.classList.contains('note-image')) { + e.preventDefault(); + e.stopPropagation(); + openImageModal(target.src); + } + }); } // Démarrer l'application