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

283 lines
11 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-29 14:25:18 +03:30
import React from 'react';
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';
import { Avatar, CardContent, Grid } from '@mui/material';
import useLocalStorage from 'util/useLocalStorage';
2021-10-30 16:10:34 +03:30
import SpinnerImage from 'components/util/SpinnerImage';
import { Box, styled } from '@mui/system';
2022-03-03 18:19:01 +05:30
import { useLibraryOptionsContext } from 'components/context/LibraryOptionsContext';
import { BACK } from 'util/useBackTo';
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%)',
});
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%)',
});
2021-05-28 19:37:26 +04:30
2021-10-31 21:02:45 +03:30
const MangaTitle = styled(Typography)({
position: 'absolute',
bottom: 0,
padding: '0.5em',
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
2021-08-29 21:46:20 +04:30
const truncateText = (str: string, maxLength: number) => {
const ending = '...';
// trim the string to the maximum length
const trimmedString = str.substr(0, maxLength - ending.length);
if (trimmedString.length < str.length) {
return trimmedString + ending;
}
return str;
};
2020-12-25 17:42:22 +01:00
interface IProps {
manga: IMangaCard
gridLayout: number | undefined
dimensions: number
inLibraryIndicator?: boolean
2020-12-25 17:42:22 +01:00
}
const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref) => {
2020-12-25 17:42:22 +01:00
const {
manga: {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
id, title, thumbnailUrl, downloadCount, unreadCount: unread, inLibrary,
2021-01-29 14:25:18 +03:30
},
gridLayout,
dimensions,
inLibraryIndicator,
2020-12-25 17:42:22 +01:00
} = props;
2022-03-03 18:19:01 +05:30
const { options: { showUnreadBadge, showDownloadBadge } } = useLibraryOptionsContext();
2021-10-31 21:02:45 +03:30
2021-03-07 22:35:27 +03:30
const [serverAddress] = useLocalStorage<String>('serverBaseURL', '');
2021-09-18 20:59:23 +04:30
const [useCache] = useLocalStorage<boolean>('useCache', true);
const [ItemWidth] = useLocalStorage<number>('ItemWidth', 300);
2020-12-25 17:42:22 +01:00
const mangaLinkTo = { pathname: `/manga/${id}/`, state: { backLink: BACK } };
if (gridLayout !== 2) {
const cols = Math.ceil(dimensions / ItemWidth);
return (
<Grid item columns={cols} xs={1}>
<Link to={mangaLinkTo} style={(gridLayout === 1) ? { textDecoration: 'none' } : {}}>
<Box
2021-10-31 21:02:45 +03:30
sx={{
display: 'flex',
flexDirection: 'column',
2021-10-31 21:02:45 +03:30
}}
>
<Card
sx={{
// force standard aspect ratio of manga covers
aspectRatio: '225/350',
display: 'flex',
}}
ref={ref}
>
<CardActionArea
sx={{
position: 'relative',
height: '100%',
}}
>
<BadgeContainer
sx={{
position: 'absolute',
top: 5,
left: 5,
}}
>
{inLibraryIndicator && inLibrary && (
<Typography
sx={{ backgroundColor: 'primary.dark', zIndex: '1' }}
>
In library
</Typography>
)}
{ 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={`${serverAddress}${thumbnailUrl}?useCache=${useCache}`}
imgStyle={inLibraryIndicator && inLibrary
? {
height: '100%',
width: '100%',
objectFit: 'cover',
filter: 'brightness(0.4)',
}
: {
height: '100%',
width: '100%',
objectFit: 'cover',
}}
spinnerStyle={{
display: 'grid',
placeItems: 'center',
}}
/>
{(gridLayout === 1) ? (<></>) : (
<>
<BottomGradient />
<BottomGradientDoubledDown />
</>
)}
{(gridLayout === 1) ? (
<></>
) : (
<MangaTitle
sx={{
color: 'white',
textShadow: '0px 0px 3px #000000',
}}
>
{truncateText(title, 61)}
</MangaTitle>
)}
</CardActionArea>
</Card>
{(gridLayout === 1) ? (
<MangaTitle
sx={{
position: 'relative',
color: 'text.primary',
}}
>
{truncateText(title, 61)}
</MangaTitle>
) : (<></>)}
</Box>
</Link>
</Grid>
);
}
return (
<Grid item xs={12}>
<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={`${serverAddress}${thumbnailUrl}?useCache=${useCache}`}
/>
<Box
sx={{
display: 'flex',
flexDirection: 'row',
flexGrow: 1,
width: 'min-content',
}}
>
<Typography variant="h5" component="h2">
{truncateText(title, 61)}
</Typography>
</Box>
<BadgeContainer>
{inLibraryIndicator && inLibrary && (
<Typography
sx={{ backgroundColor: 'primary.dark' }}
>
In library
</Typography>
)}
{ showUnreadBadge && unread! > 0 && (
<Typography
sx={{ backgroundColor: 'primary.dark' }}
>
{unread}
</Typography>
)}
{ showDownloadBadge && downloadCount! > 0 && (
<Typography sx={{
backgroundColor: 'success.dark',
}}
>
{downloadCount}
</Typography>
)}
</BadgeContainer>
</CardContent>
</CardActionArea>
</Card>
2021-01-23 01:58:18 +03:30
</Grid>
2020-12-25 17:42:22 +01:00
);
2021-01-22 21:11:00 +03:30
});
export default MangaCard;