Skip to content

Commit 2b1e0c6

Browse files
committed
fix: ImageLightbox renders full-resolution image without upscaling
The lightbox previously displayed the proxied thumbnail URL stretched to `w-[90vw] h-[85vh]`, which forced the browser to upscale the small preview on wide displays and made it look blurry. Switch to `max-w-[90vw] max-h-[85vh]` so the image never exceeds its natural size, and proxy `attachment.url` (the full-resolution original) inside the lightbox itself. The already-proxied thumbnail is passed as an optional placeholder and shown while the full image loads.
1 parent 3dd26d1 commit 2b1e0c6

2 files changed

Lines changed: 21 additions & 10 deletions

File tree

apps/fluux/src/components/FileAttachments.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ export const ImageAttachment = memo(function ImageAttachment({ attachment, onLoa
141141
</button>
142142
{lightboxOpen && (
143143
<ImageLightbox
144-
src={proxiedImageSrc}
144+
src={attachment.url}
145+
placeholderSrc={proxiedImageSrc ?? undefined}
145146
alt={attachment.name || 'Image attachment'}
146147
downloadUrl={attachment.url}
147148
filename={attachment.name}

apps/fluux/src/components/ImageLightbox.tsx

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,29 @@
44
*/
55
import { useEffect, useRef } from 'react'
66
import { createPortal } from 'react-dom'
7-
import { X, Download } from 'lucide-react'
7+
import { X, Download, Loader2 } from 'lucide-react'
88
import { useTranslation } from 'react-i18next'
9+
import { useProxiedUrl } from '@/hooks'
910

1011
interface ImageLightboxProps {
11-
/** Image source URL (proxied/cached) for display */
12+
/** Original full-resolution image URL (proxied internally for display) */
1213
src: string
1314
/** Alt text for the image */
1415
alt?: string
1516
/** Original URL for downloading */
1617
downloadUrl: string
1718
/** Original filename */
1819
filename?: string
20+
/** Optional preview URL (e.g. already-proxied thumbnail) shown while the full-size image loads */
21+
placeholderSrc?: string
1922
/** Close handler */
2023
onClose: () => void
2124
}
2225

23-
export function ImageLightbox({ src, alt, downloadUrl, filename, onClose }: ImageLightboxProps) {
26+
export function ImageLightbox({ src, alt, downloadUrl, filename, placeholderSrc, onClose }: ImageLightboxProps) {
2427
const { t } = useTranslation()
2528
const mouseDownTargetRef = useRef<EventTarget | null>(null)
29+
const { url: proxiedSrc, isLoading } = useProxiedUrl(src)
2630

2731
useEffect(() => {
2832
const handleKeyDown = (e: KeyboardEvent) => {
@@ -32,6 +36,8 @@ export function ImageLightbox({ src, alt, downloadUrl, filename, onClose }: Imag
3236
return () => document.removeEventListener('keydown', handleKeyDown)
3337
}, [onClose])
3438

39+
const displaySrc = proxiedSrc ?? placeholderSrc
40+
3541
return createPortal(
3642
<div
3743
className="fixed inset-0 bg-black/90 flex flex-col items-center justify-center z-50"
@@ -60,12 +66,16 @@ export function ImageLightbox({ src, alt, downloadUrl, filename, onClose }: Imag
6066
</div>
6167

6268
{/* Image */}
63-
<img
64-
src={src}
65-
alt={alt || 'Image'}
66-
className="w-[90vw] h-[85vh] object-contain rounded-lg select-none"
67-
draggable={false}
68-
/>
69+
{displaySrc ? (
70+
<img
71+
src={displaySrc}
72+
alt={alt || 'Image'}
73+
className="max-w-[90vw] max-h-[85vh] object-contain rounded-lg select-none"
74+
draggable={false}
75+
/>
76+
) : (
77+
isLoading && <Loader2 className="w-8 h-8 text-white/70 animate-spin" />
78+
)}
6979

7080
{/* Filename label */}
7181
{filename && (

0 commit comments

Comments
 (0)