fix: clamp fitted library cover sizing
Android E2E (CDP) / android-e2e (pull_request) Waiting to run
CodeQL Advanced / Analyze (actions) (pull_request) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (pull_request) Waiting to run
CodeQL Advanced / Analyze (rust) (pull_request) Waiting to run
PR checks / rust_lint (pull_request) Waiting to run
PR checks / build_web_app (pull_request) Waiting to run
PR checks / test_web_app (1) (pull_request) Waiting to run
PR checks / test_web_app (2) (pull_request) Waiting to run
PR checks / test_extensions (pull_request) Waiting to run
PR checks / build_tauri_app (pull_request) Waiting to run

This commit is contained in:
akai
2026-07-09 20:02:39 +08:00
parent 75293bd1a4
commit 4993053d03
@@ -33,6 +33,10 @@ interface BookItemProps {
showBookDetailsModal: (book: Book) => void;
}
const CELL_ASPECT_RATIO = 28 / 41;
const MIN_FIT_COVER_WIDTH_RATIO = 0.72;
const MIN_FIT_COVER_HEIGHT_RATIO = 0.78;
const BookItem: React.FC<BookItemProps> = ({
book,
mode,
@@ -56,17 +60,66 @@ const BookItem: React.FC<BookItemProps> = ({
setCoverAspect(null);
}, [book.hash, book.metadata?.coverImageUrl, book.coverImageUrl]);
const CELL_ASPECT_RATIO = 28 / 41;
const measuredCoverAspect = coverAspect ?? CELL_ASPECT_RATIO;
const fitCoverInGrid = mode === 'grid' && coverFit === 'fit' && coverAspect !== null;
const shouldShrinkWidth = fitCoverInGrid && coverAspect! < CELL_ASPECT_RATIO;
const fitCoverBaseWidthRatio =
fitCoverInGrid && measuredCoverAspect < CELL_ASPECT_RATIO
? measuredCoverAspect / CELL_ASPECT_RATIO
: 1;
const fitCoverBaseHeightRatio =
fitCoverInGrid && measuredCoverAspect > CELL_ASPECT_RATIO
? CELL_ASPECT_RATIO / measuredCoverAspect
: 1;
const fitCoverWidthRatio = fitCoverInGrid
? Math.max(MIN_FIT_COVER_WIDTH_RATIO, fitCoverBaseWidthRatio)
: 1;
const fitCoverHeightRatio = fitCoverInGrid
? Math.max(MIN_FIT_COVER_HEIGHT_RATIO, fitCoverBaseHeightRatio)
: 1;
const fitCoverIsZoomed =
fitCoverInGrid &&
(fitCoverWidthRatio > fitCoverBaseWidthRatio || fitCoverHeightRatio > fitCoverBaseHeightRatio);
const bookitemMainStyle = fitCoverInGrid
? {
aspectRatio: coverAspect!,
...(shouldShrinkWidth ? { width: `${(coverAspect! / CELL_ASPECT_RATIO) * 100}%` } : {}),
width: `${fitCoverWidthRatio * 100}%`,
height: `${fitCoverHeightRatio * 100}%`,
}
: undefined;
const seriesText = formatSeries(book.metadata?.series, book.metadata?.seriesIndex);
const coverNode = (
<div
className={clsx(
'bookitem-main relative flex justify-center overflow-hidden rounded',
mode === 'grid' && 'items-end',
mode === 'grid' && !fitCoverInGrid && 'h-full w-full',
mode === 'list' && 'aspect-[28/41] min-w-20 items-center',
coverFit === 'crop' && 'shadow-md',
)}
style={bookitemMainStyle}
>
<BookCover
mode={mode}
book={book}
coverFit={fitCoverIsZoomed ? 'crop' : coverFit}
showSpine={false}
imageClassName='rounded shadow-md'
onAspectRatioChange={setCoverAspect}
/>
{bookSelected && (
<div className='absolute inset-0 bg-black opacity-30 transition-opacity duration-300'></div>
)}
{isSelectMode && (
<div className='absolute bottom-1 right-1'>
{bookSelected ? (
<MdCheckCircle className='fill-blue-500' />
) : (
<MdCheckCircleOutline className='fill-gray-300 drop-shadow-sm' />
)}
</div>
)}
</div>
);
return (
<div
@@ -80,37 +133,11 @@ const BookItem: React.FC<BookItemProps> = ({
)}
onClick={(e) => e.stopPropagation()}
>
<div
className={clsx(
'bookitem-main relative flex justify-center overflow-hidden rounded',
!fitCoverInGrid && 'aspect-[28/41]',
coverFit === 'crop' && 'shadow-md',
mode === 'grid' && 'items-end',
mode === 'list' && 'min-w-20 items-center',
)}
style={bookitemMainStyle}
>
<BookCover
mode={mode}
book={book}
coverFit={coverFit}
showSpine={false}
imageClassName='rounded shadow-md'
onAspectRatioChange={setCoverAspect}
/>
{bookSelected && (
<div className='absolute inset-0 bg-black opacity-30 transition-opacity duration-300'></div>
)}
{isSelectMode && (
<div className='absolute bottom-1 right-1'>
{bookSelected ? (
<MdCheckCircle className='fill-blue-500' />
) : (
<MdCheckCircleOutline className='fill-gray-300 drop-shadow-sm' />
)}
</div>
)}
</div>
{mode === 'grid' ? (
<div className='flex aspect-[28/41] w-full items-end justify-center'>{coverNode}</div>
) : (
coverNode
)}
<div
className={clsx(
'flex w-full flex-col p-0',