diff --git a/frontend/src/components/input/editor/TipTap.vue b/frontend/src/components/input/editor/TipTap.vue index 69ebc0a7e..c37553488 100644 --- a/frontend/src/components/input/editor/TipTap.vue +++ b/frontend/src/components/input/editor/TipTap.vue @@ -110,7 +110,8 @@ @@ -677,25 +678,37 @@ function focusIfEditing() { } const lightboxBlobUrl = ref(null) +const lightboxAlt = ref('') + +function getLightboxImage(target: EventTarget | null): HTMLImageElement | null { + if ( + target instanceof HTMLImageElement + && target.dataset.src !== undefined + && target.src.startsWith('blob:') + ) { + return target + } + + return null +} function handleContentClick(event: MouseEvent) { focusIfEditing() if (isEditing.value) { return } - // Preview mode: open content images in the lightbox. Their blob URL is - // resolved lazily by CustomImage (src stays '#' until it loads). Mention - // and user avatars are too, so skip those. - const target = event.target - if ( - target instanceof HTMLImageElement - && !target.src.endsWith('#') - && !target.closest('.mention-user, .avatar-wrapper') - ) { - lightboxBlobUrl.value = target.src + + const image = getLightboxImage(event.target) + if (image !== null) { + lightboxBlobUrl.value = image.src + lightboxAlt.value = image.alt } } +function closeLightbox() { + lightboxBlobUrl.value = null +} + function handleEscapeKey(event: KeyboardEvent) { // Only intercept Escape when discard shortcut is enabled if (event.key !== 'Escape' || !props.enableDiscardShortcut) {