mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-24 15:48:16 +02:00
Images: Miniatures avec modal d'agrandissement
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
This commit is contained in:
4 files changed
+151
-1
No files matched your search
@@ -84,6 +84,13 @@
|
|||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
margin-bottom: var(--spacing-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 {
|
.note-todos-preview {
|
||||||
@@ -840,9 +847,16 @@
|
|||||||
|
|
||||||
.note-image {
|
.note-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-height: 300px;
|
max-height: 200px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
border-radius: var(--radius-lg);
|
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 {
|
.btn-remove-image {
|
||||||
|
|||||||
Vendored
+65
@@ -293,3 +293,68 @@
|
|||||||
transform: translateX(400px);
|
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;
|
||||||
|
}
|
||||||
@@ -305,6 +305,19 @@
|
|||||||
<!-- Conteneur de notifications -->
|
<!-- Conteneur de notifications -->
|
||||||
<div class="notifications-container" id="notificationsContainer"></div>
|
<div class="notifications-container" id="notificationsContainer"></div>
|
||||||
|
|
||||||
|
<!-- Modal pour agrandir les images -->
|
||||||
|
<div class="image-modal" id="imageModal">
|
||||||
|
<div class="image-modal-content">
|
||||||
|
<img src="" alt="" class="image-modal-img" id="imageModalImg">
|
||||||
|
</div>
|
||||||
|
<button class="image-modal-close" id="imageModalClose">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||||
|
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- JavaScript -->
|
<!-- JavaScript -->
|
||||||
<script src="/js/complete-app.js"></script>
|
<script src="/js/complete-app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -534,6 +534,27 @@ function closeNotification(notification) {
|
|||||||
}, 300);
|
}, 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 ====================
|
// ==================== INLINE NOTE EXPANSION ====================
|
||||||
function expandNote(noteId) {
|
function expandNote(noteId) {
|
||||||
state.expandedNoteId = noteId;
|
state.expandedNoteId = noteId;
|
||||||
@@ -2263,6 +2284,43 @@ async function init() {
|
|||||||
if (saveOpenRouterBtn) {
|
if (saveOpenRouterBtn) {
|
||||||
saveOpenRouterBtn.addEventListener('click', saveOpenRouterSettings);
|
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
|
// Démarrer l'application
|
||||||
|
|||||||
Reference in new issue
Block a user