forked from akai/readest
fix: clamp fitted library cover sizing
This commit is contained in:
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user