fix: preserve result thumbnail aspect ratios

This commit is contained in:
2026-05-19 20:35:16 +08:00
parent ece4db338e
commit 6c3f5eda0a
2 changed files with 23 additions and 5 deletions

View File

@@ -11,7 +11,9 @@ type PreviewState = {
function parseRatio(aspectRatio?: string) {
if (!aspectRatio || aspectRatio === 'long') return aspectRatio === 'long' ? 1 / 3 : 1;
const [w, h] = aspectRatio.split(':').map(Number);
const [w, h] = aspectRatio.includes('/')
? aspectRatio.split('/').map(part => Number(part.trim()))
: aspectRatio.split(':').map(Number);
return w && h ? w / h : 1;
}
@@ -42,11 +44,13 @@ export function HoverImagePreview({
alt,
imageClassName,
aspectRatio,
onImageLoad,
}: {
src: string;
alt: string;
imageClassName?: string;
aspectRatio?: string;
onImageLoad?: (image: HTMLImageElement) => void;
}) {
const [preview, setPreview] = useState<PreviewState | null>(null);
@@ -61,6 +65,7 @@ export function HoverImagePreview({
setPreview(nextPreviewState(event, aspectRatio));
}}
onPointerLeave={() => setPreview(null)}
onLoad={event => onImageLoad?.(event.currentTarget)}
/>
{preview && (
<div

View File

@@ -1,6 +1,6 @@
'use client';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import type { GenImage } from '@/lib/types';
import { HoverImagePreview } from './HoverImagePreview';
@@ -10,6 +10,8 @@ export type ResultGridProps = {
};
export default function ResultGrid({ images, onAction }: ResultGridProps) {
const [ratios, setRatios] = useState<Record<string, string>>({});
useEffect(() => {
function handler(e: KeyboardEvent) {
const target = e.target as HTMLElement;
@@ -27,7 +29,7 @@ export default function ResultGrid({ images, onAction }: ResultGridProps) {
return () => window.removeEventListener('keydown', handler);
}, [images, onAction]);
const cols = images.length <= 4 ? 'grid-cols-2' : images.length <= 9 ? 'grid-cols-3' : 'grid-cols-4';
const cols = images.length === 1 ? 'grid-cols-[minmax(220px,520px)]' : images.length <= 4 ? 'grid-cols-2' : images.length <= 9 ? 'grid-cols-3' : 'grid-cols-4';
const selectedCount = images.filter(i => i.status === 'selected').length;
return (
@@ -51,13 +53,24 @@ export default function ResultGrid({ images, onAction }: ResultGridProps) {
</div>
</div>
<div className={`grid ${cols} gap-3`}>
<div className={`grid ${cols} items-start gap-3`}>
{images.map((img, i) => (
<div
key={img.id}
className={`tile group ${img.status === 'selected' ? 'tile-selected' : ''} ${img.status === 'rejected' ? 'tile-rejected' : ''}`}
style={{ aspectRatio: ratios[img.id] ?? '1 / 1' }}
>
<HoverImagePreview src={img.url} alt={`gen ${i + 1}`} imageClassName="w-full h-full object-contain bg-white" />
<HoverImagePreview
src={img.url}
alt={`gen ${i + 1}`}
aspectRatio={ratios[img.id]}
imageClassName="w-full h-full object-contain bg-white"
onImageLoad={image => {
if (!image.naturalWidth || !image.naturalHeight) return;
const next = `${image.naturalWidth} / ${image.naturalHeight}`;
setRatios(prev => prev[img.id] === next ? prev : { ...prev, [img.id]: next });
}}
/>
<div className="tile-keynum">{i + 1}</div>
{img.status === 'selected' && (