fix: constrain thumbnail strip to right pane and handle non-previewable formats

The thumbnail strip expanded beyond the right pane because the flex
section lacked min-w-0, causing a page-level horizontal scrollbar.
Added min-w-0 to both mobile and desktop image area sections.

For non-previewable formats (DDS, TIFF, EXR, PSD, RAW, etc.), show a
file info card with format and size instead of passing the blob URL to
an img tag that fails and shows an infinite "Loading preview..." spinner.
Also changed the ImageViewer error state from a misleading spinner to a
static "Preview not available" message.
This commit is contained in:
SnapOtter
2026-05-11 17:10:42 +08:00
parent aec1e91c5a
commit aa614cb53d
2 changed files with 31 additions and 9 deletions
@@ -1,4 +1,4 @@
import { Loader2, Maximize, Minimize2, ZoomIn, ZoomOut } from "lucide-react";
import { FileImage, Maximize, Minimize2, ZoomIn, ZoomOut } from "lucide-react";
import { useCallback, useEffect, useRef, useState } from "react";
import { formatFileSize } from "@/lib/download";
@@ -184,8 +184,8 @@ export function ImageViewer({
>
{loadError ? (
<div className="flex flex-col items-center justify-center gap-3 text-center">
<Loader2 className="h-8 w-8 text-muted-foreground animate-spin" />
<p className="text-sm text-muted-foreground">Loading preview...</p>
<FileImage className="h-8 w-8 text-muted-foreground" />
<p className="text-sm text-muted-foreground">Preview not available</p>
<p className="text-xs text-muted-foreground/60">{filename}</p>
</div>
) : bgPreview?.backgroundSrc || bgPreview?.containerBackground ? (
+28 -6
View File
@@ -586,11 +586,33 @@ export function ToolPage() {
}
if (hasFile && originalBlobUrl) {
const fname = selectedFileName ?? files[0].name;
const fsize = selectedFileSize ?? files[0].size;
if (!canBrowserPreview(originalBlobUrl, fname)) {
const ext = fname.split(".").pop()?.toUpperCase() ?? "";
return (
<div className="flex flex-col items-center justify-center h-full gap-4 text-center p-8">
<div className="w-16 h-16 rounded-full bg-muted flex items-center justify-center">
<FileImage className="h-8 w-8 text-muted-foreground" />
</div>
<div>
<p className="text-sm font-medium truncate max-w-xs">{fname}</p>
<p className="text-xs text-muted-foreground mt-1">
{ext} · {formatFileSize(fsize)}
</p>
</div>
<p className="text-xs text-muted-foreground max-w-xs">
{ext} files cannot be previewed in the browser. The tool will still process this file
normally.
</p>
</div>
);
}
return (
<ImageViewer
src={originalBlobUrl}
filename={selectedFileName ?? files[0].name}
fileSize={selectedFileSize ?? files[0].size}
filename={fname}
fileSize={fsize}
{...(isLivePreview && previewTransform
? {
cssRotate: previewTransform.rotate,
@@ -722,11 +744,11 @@ export function ToolPage() {
{/* Main area: image viewer */}
<section
aria-label="Image area"
className="flex-1 flex flex-col min-h-0"
className="flex-1 flex flex-col min-h-0 min-w-0"
onKeyDown={hasMultiple ? handleImageKeyDown : undefined}
tabIndex={hasMultiple ? 0 : undefined}
>
<div className="flex-1 relative flex items-center justify-center p-4 min-h-0">
<div className="flex-1 relative flex items-center justify-center p-4 min-h-0 min-w-0">
{renderNavArrows()}
{renderImageArea()}
</div>
@@ -762,11 +784,11 @@ export function ToolPage() {
{/* Main area: image viewer */}
<section
aria-label="Image area"
className="flex-1 flex flex-col min-h-0"
className="flex-1 flex flex-col min-h-0 min-w-0"
onKeyDown={hasMultiple ? handleImageKeyDown : undefined}
tabIndex={hasMultiple ? 0 : undefined}
>
<div className="flex-1 relative flex items-center justify-center p-6 min-h-0">
<div className="flex-1 relative flex items-center justify-center p-6 min-h-0 min-w-0">
{renderNavArrows()}
{renderImageArea()}
</div>