Files
suwayomi-material-you-webui/src/components/MangaCard.tsx
T

264 lines
10 KiB
TypeScript
Raw Normal View History

/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
2021-01-26 23:32:12 +03:30
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
2021-01-26 23:32:12 +03:30
2021-09-09 17:51:22 +04:30
import Card from '@mui/material/Card';
import CardActionArea from '@mui/material/CardActionArea';
import Typography from '@mui/material/Typography';
2021-01-19 20:20:28 +03:30
import { Link } from 'react-router-dom';
2023-06-17 16:50:17 +02:00
import { Avatar, Box, CardContent, styled } from '@mui/material';
2023-03-23 13:59:32 +01:00
import { useTranslation } from 'react-i18next';
2023-08-15 13:54:29 +02:00
import requestManager from '@/lib/requests/RequestManager.ts';
2023-06-05 01:42:39 +02:00
import { GridLayout, useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext';
import SpinnerImage from '@/components/util/SpinnerImage';
2023-09-06 21:47:13 +02:00
import { MangaType } from '@/lib/graphql/generated/graphql.ts';
2020-12-25 17:42:22 +01:00
2021-10-31 21:02:45 +03:30
const BottomGradient = styled('div')({
position: 'absolute',
bottom: 0,
width: '100%',
height: '30%',
background: 'linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 100%)',
});
2021-05-28 19:37:26 +04:30
2021-10-31 21:02:45 +03:30
const BottomGradientDoubledDown = styled('div')({
position: 'absolute',
bottom: 0,
width: '100%',
height: '20%',
background: 'linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 100%)',
});
const MangaTitle = styled(Typography)({
2023-06-17 16:50:17 +02:00
lineHeight: '1.5rem',
maxHeight: '3rem',
display: '-webkit-box',
WebkitLineClamp: '2',
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
textOverflow: 'ellipsis',
});
const GridMangaTitle = styled(MangaTitle)({
width: '100%',
2021-10-31 21:02:45 +03:30
position: 'absolute',
bottom: 0,
2023-06-17 16:50:17 +02:00
margin: '0.5em 0',
padding: '0 0.5em',
2021-10-31 21:02:45 +03:30
fontSize: '1.05rem',
});
const BadgeContainer = styled('div')({
display: 'flex',
height: 'fit-content',
2021-10-31 21:02:45 +03:30
borderRadius: '5px',
overflow: 'hidden',
'& p': {
color: 'white',
padding: '0.1em',
paddingInline: '0.2em',
fontSize: '1.05rem',
},
});
2020-12-25 17:42:22 +01:00
interface IProps {
2023-09-06 21:47:13 +02:00
manga: MangaType;
2023-02-06 10:06:33 +01:00
gridLayout?: GridLayout;
inLibraryIndicator?: boolean;
2020-12-25 17:42:22 +01:00
}
2023-02-06 10:06:33 +01:00
2023-06-17 16:50:17 +02:00
const MangaCard = (props: IProps) => {
2023-03-23 13:59:32 +01:00
const { t } = useTranslation();
2020-12-25 17:42:22 +01:00
const {
2023-09-06 21:47:13 +02:00
manga: { id, title, thumbnailUrl: tmpThumbnailUrl, downloadCount, unreadCount: unread, inLibrary },
2022-03-06 16:45:25 +00:00
gridLayout,
2022-11-24 21:04:30 +01:00
inLibraryIndicator,
2020-12-25 17:42:22 +01:00
} = props;
2023-09-06 21:47:13 +02:00
const thumbnailUrl = tmpThumbnailUrl ?? 'nonExistingMangaUrl';
2023-02-06 10:06:33 +01:00
const {
options: { showUnreadBadge, showDownloadBadge },
} = useLibraryOptionsContext();
2021-10-31 21:02:45 +03:30
2023-06-08 14:25:24 +02:00
const mangaLinkTo = `/manga/${id}/`;
2022-11-21 01:33:45 +01:00
if (gridLayout !== GridLayout.List) {
2022-03-06 21:03:15 +00:00
return (
2023-06-17 16:50:17 +02:00
<Link to={mangaLinkTo} style={gridLayout === GridLayout.Comfortable ? { textDecoration: 'none' } : {}}>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
}}
>
<Card
2021-10-31 21:02:45 +03:30
sx={{
2023-06-17 16:50:17 +02:00
// force standard aspect ratio of manga covers
aspectRatio: '225/350',
2022-03-06 16:45:25 +00:00
display: 'flex',
2021-10-31 21:02:45 +03:30
}}
>
2023-06-17 16:50:17 +02:00
<CardActionArea
2022-03-06 16:45:25 +00:00
sx={{
2023-06-17 16:50:17 +02:00
position: 'relative',
height: '100%',
2021-10-31 21:02:45 +03:30
}}
2022-03-06 16:45:25 +00:00
>
2023-06-17 16:50:17 +02:00
<BadgeContainer
2022-03-06 21:03:15 +00:00
sx={{
2023-06-17 16:50:17 +02:00
position: 'absolute',
top: 5,
left: 5,
2022-03-06 16:45:25 +00:00
}}
2022-03-06 21:03:15 +00:00
>
2023-06-17 16:50:17 +02:00
{inLibraryIndicator && inLibrary && (
<Typography sx={{ backgroundColor: 'primary.dark', zIndex: '1' }}>
{t('manga.button.in_library')}
</Typography>
2022-03-06 21:03:15 +00:00
)}
2023-06-17 16:50:17 +02:00
{showUnreadBadge && unread! > 0 && (
<Typography sx={{ backgroundColor: 'primary.dark' }}>{unread}</Typography>
)}
{showDownloadBadge && downloadCount! > 0 && (
<Typography
sx={{
backgroundColor: 'success.dark',
}}
>
{downloadCount}
</Typography>
)}
</BadgeContainer>
<SpinnerImage
alt={title}
src={requestManager.getValidImgUrlFor(thumbnailUrl)}
imgStyle={
inLibraryIndicator && inLibrary
? {
height: '100%',
width: '100%',
objectFit: 'cover',
filter: 'brightness(0.4)',
}
: {
height: '100%',
width: '100%',
objectFit: 'cover',
}
}
spinnerStyle={{
display: 'grid',
placeItems: 'center',
2022-03-06 16:45:25 +00:00
}}
2023-06-17 16:50:17 +02:00
/>
{gridLayout !== GridLayout.Comfortable && (
<>
<BottomGradient />
<BottomGradientDoubledDown />
<GridMangaTitle
sx={{
color: 'white',
textShadow: '0px 0px 3px #000000',
}}
title={title}
>
{title}
</GridMangaTitle>
</>
)}
</CardActionArea>
</Card>
{gridLayout === GridLayout.Comfortable && (
<GridMangaTitle
sx={{
position: 'relative',
color: 'text.primary',
height: '3rem',
}}
title={title}
>
{title}
</GridMangaTitle>
)}
</Box>
</Link>
2022-03-06 21:03:15 +00:00
);
}
2022-03-06 21:03:15 +00:00
return (
2023-06-17 16:50:17 +02:00
<Card>
<CardActionArea component={Link} to={mangaLinkTo}>
<CardContent
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: 2,
position: 'relative',
}}
>
<Avatar
variant="rounded"
sx={
inLibraryIndicator && inLibrary
? {
width: 56,
height: 56,
flex: '0 0 auto',
marginRight: 2,
imageRendering: 'pixelated',
filter: 'brightness(0.4)',
}
: {
width: 56,
height: 56,
flex: '0 0 auto',
marginRight: 2,
imageRendering: 'pixelated',
}
}
src={requestManager.getValidImgUrlFor(thumbnailUrl)}
/>
<Box
2022-03-06 21:03:15 +00:00
sx={{
display: 'flex',
2023-06-17 16:50:17 +02:00
flexDirection: 'row',
flexGrow: 1,
width: 'min-content',
2022-03-06 21:03:15 +00:00
}}
>
2023-06-17 16:50:17 +02:00
<MangaTitle variant="h5" title={title}>
{title}
</MangaTitle>
</Box>
<BadgeContainer>
{inLibraryIndicator && inLibrary && (
<Typography sx={{ backgroundColor: 'primary.dark' }}>
{t('manga.button.in_library')}
2022-03-06 21:03:15 +00:00
</Typography>
2023-06-17 16:50:17 +02:00
)}
{showUnreadBadge && unread! > 0 && (
<Typography sx={{ backgroundColor: 'primary.dark' }}>{unread}</Typography>
)}
{showDownloadBadge && downloadCount! > 0 && (
<Typography
sx={{
backgroundColor: 'success.dark',
}}
>
{downloadCount}
</Typography>
)}
</BadgeContainer>
</CardContent>
</CardActionArea>
</Card>
2020-12-25 17:42:22 +01:00
);
2023-06-17 16:50:17 +02:00
};
2021-01-22 21:11:00 +03:30
export default MangaCard;