2021-03-26 04:17:02 +04:30
|
|
|
/*
|
|
|
|
|
* 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-09-09 17:51:22 +04:30
|
|
|
import FavoriteIcon from '@mui/icons-material/Favorite';
|
|
|
|
|
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
|
|
|
|
|
import PublicIcon from '@mui/icons-material/Public';
|
2022-11-09 18:09:15 +01:00
|
|
|
import { Typography } from '@mui/material';
|
|
|
|
|
import IconButton from '@mui/material/IconButton';
|
|
|
|
|
import { Theme } from '@mui/material/styles';
|
|
|
|
|
import makeStyles from '@mui/styles/makeStyles';
|
2023-05-01 23:31:14 +02:00
|
|
|
import React, { useEffect } from 'react';
|
2023-03-23 13:59:32 +01:00
|
|
|
import { useTranslation } from 'react-i18next';
|
2022-11-09 18:09:15 +01:00
|
|
|
import { mutate } from 'swr';
|
2021-05-27 05:13:01 +04:30
|
|
|
import client from 'util/client';
|
|
|
|
|
import useLocalStorage from 'util/useLocalStorage';
|
2023-02-24 16:40:37 +01:00
|
|
|
import { IManga, ISource } from 'typings';
|
2023-05-01 23:31:14 +02:00
|
|
|
import { t as translate } from 'i18next';
|
|
|
|
|
import makeToast from 'components/util/Toast';
|
2021-02-21 04:27:41 +03:30
|
|
|
|
2023-02-06 10:06:33 +01:00
|
|
|
const useStyles = (inLibrary: boolean) =>
|
|
|
|
|
makeStyles((theme: Theme) => ({
|
|
|
|
|
root: {
|
|
|
|
|
width: '100%',
|
|
|
|
|
[theme.breakpoints.up('md')]: {
|
|
|
|
|
position: 'sticky',
|
|
|
|
|
top: '64px',
|
|
|
|
|
left: '0px',
|
|
|
|
|
width: '50vw',
|
|
|
|
|
height: 'calc(100vh - 64px)',
|
|
|
|
|
alignSelf: 'flex-start',
|
|
|
|
|
overflowY: 'auto',
|
|
|
|
|
},
|
2021-03-19 14:52:20 +03:30
|
|
|
},
|
2023-02-06 10:06:33 +01:00
|
|
|
top: {
|
|
|
|
|
padding: '10px',
|
|
|
|
|
// [theme.breakpoints.up('md')]: {
|
|
|
|
|
// minWidth: '50%',
|
|
|
|
|
// },
|
2021-03-17 19:17:03 +03:30
|
|
|
},
|
2023-02-06 10:06:33 +01:00
|
|
|
leftRight: {
|
|
|
|
|
display: 'flex',
|
2021-03-17 19:17:03 +03:30
|
|
|
},
|
2023-02-06 10:06:33 +01:00
|
|
|
leftSide: {
|
|
|
|
|
'& img': {
|
|
|
|
|
borderRadius: 4,
|
|
|
|
|
maxWidth: '100%',
|
|
|
|
|
minWidth: '100%',
|
|
|
|
|
height: 'auto',
|
|
|
|
|
},
|
|
|
|
|
maxWidth: '50%',
|
|
|
|
|
// [theme.breakpoints.up('md')]: {
|
|
|
|
|
// minWidth: '100px',
|
|
|
|
|
// },
|
2021-03-17 19:17:03 +03:30
|
|
|
},
|
2023-02-06 10:06:33 +01:00
|
|
|
rightSide: {
|
|
|
|
|
marginLeft: 15,
|
|
|
|
|
maxWidth: '100%',
|
|
|
|
|
'& span': {
|
|
|
|
|
fontWeight: '400',
|
|
|
|
|
},
|
|
|
|
|
[theme.breakpoints.up('lg')]: {
|
|
|
|
|
fontSize: '1.3em',
|
|
|
|
|
},
|
2021-03-17 19:17:03 +03:30
|
|
|
},
|
2023-02-06 10:06:33 +01:00
|
|
|
buttons: {
|
|
|
|
|
display: 'flex',
|
|
|
|
|
justifyContent: 'space-around',
|
2021-03-17 19:17:03 +03:30
|
|
|
'& button': {
|
2023-02-06 10:06:33 +01:00
|
|
|
color: inLibrary ? '#2196f3' : 'inherit',
|
|
|
|
|
},
|
|
|
|
|
'& a': {
|
|
|
|
|
textDecoration: 'none',
|
|
|
|
|
color: '#858585',
|
|
|
|
|
'& button': {
|
|
|
|
|
color: 'inherit',
|
|
|
|
|
},
|
2021-03-17 19:17:03 +03:30
|
|
|
},
|
|
|
|
|
},
|
2023-02-06 10:06:33 +01:00
|
|
|
bottom: {
|
|
|
|
|
paddingLeft: '10px',
|
|
|
|
|
paddingRight: '10px',
|
|
|
|
|
[theme.breakpoints.up('md')]: {
|
|
|
|
|
fontSize: '1.2em',
|
|
|
|
|
// maxWidth: '50%',
|
|
|
|
|
},
|
|
|
|
|
[theme.breakpoints.up('lg')]: {
|
|
|
|
|
fontSize: '1.3em',
|
|
|
|
|
},
|
2021-03-17 19:17:03 +03:30
|
|
|
},
|
2023-02-06 10:06:33 +01:00
|
|
|
description: {
|
|
|
|
|
'& h4': {
|
|
|
|
|
marginTop: '1em',
|
|
|
|
|
marginBottom: 0,
|
|
|
|
|
},
|
|
|
|
|
'& p': {
|
|
|
|
|
textAlign: 'justify',
|
|
|
|
|
textJustify: 'inter-word',
|
|
|
|
|
},
|
2021-03-17 19:17:03 +03:30
|
|
|
},
|
2023-02-06 10:06:33 +01:00
|
|
|
genre: {
|
|
|
|
|
display: 'flex',
|
|
|
|
|
flexWrap: 'wrap',
|
|
|
|
|
'& h5': {
|
|
|
|
|
border: '2px solid #2196f3',
|
|
|
|
|
borderRadius: '1.13em',
|
|
|
|
|
marginRight: '1em',
|
|
|
|
|
marginTop: 0,
|
|
|
|
|
marginBottom: '10px',
|
|
|
|
|
padding: '0.3em',
|
|
|
|
|
color: '#2196f3',
|
|
|
|
|
},
|
2021-02-21 04:27:41 +03:30
|
|
|
},
|
2023-02-06 10:06:33 +01:00
|
|
|
}));
|
2021-01-19 20:20:28 +03:30
|
|
|
|
2023-02-06 10:06:33 +01:00
|
|
|
interface IProps {
|
|
|
|
|
manga: IManga;
|
2021-03-14 23:57:33 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getSourceName(source: ISource) {
|
2023-05-01 23:31:14 +02:00
|
|
|
if (!source) {
|
|
|
|
|
return translate('global.label.unknown');
|
2021-03-17 19:17:03 +03:30
|
|
|
}
|
2023-05-01 23:31:14 +02:00
|
|
|
|
|
|
|
|
return source.displayName ?? source.id;
|
2021-01-19 20:20:28 +03:30
|
|
|
}
|
|
|
|
|
|
2021-03-17 19:17:03 +03:30
|
|
|
function getValueOrUnknown(val: string) {
|
|
|
|
|
return val || 'UNKNOWN';
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 18:09:15 +01:00
|
|
|
const MangaDetails: React.FC<IProps> = ({ manga }) => {
|
2023-03-23 13:59:32 +01:00
|
|
|
const { t } = useTranslation();
|
|
|
|
|
|
2021-03-17 19:17:03 +03:30
|
|
|
const [serverAddress] = useLocalStorage<String>('serverBaseURL', '');
|
2021-09-18 20:59:23 +04:30
|
|
|
const [useCache] = useLocalStorage<boolean>('useCache', true);
|
2021-03-17 19:17:03 +03:30
|
|
|
|
2022-11-09 18:09:15 +01:00
|
|
|
const classes = useStyles(manga.inLibrary)();
|
2021-02-13 21:12:18 +03:30
|
|
|
|
2023-05-02 00:35:56 +02:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (!manga.source) {
|
|
|
|
|
makeToast(translate('source.error.label.source_not_found'), 'error');
|
|
|
|
|
}
|
|
|
|
|
}, [manga.source]);
|
2023-05-01 23:31:14 +02:00
|
|
|
|
2022-11-09 18:09:15 +01:00
|
|
|
const addToLibrary = () => {
|
2023-02-08 18:19:26 +01:00
|
|
|
mutate(`/api/v1/manga/${manga.id}/?onlineFetch=false`, { ...manga, inLibrary: true }, { revalidate: false });
|
2023-02-06 10:06:33 +01:00
|
|
|
client
|
|
|
|
|
.get(`/api/v1/manga/${manga.id}/library/`)
|
2022-11-09 18:09:15 +01:00
|
|
|
.then(() => mutate(`/api/v1/manga/${manga.id}/?onlineFetch=false`));
|
|
|
|
|
};
|
2021-02-13 21:12:18 +03:30
|
|
|
|
2022-11-09 18:09:15 +01:00
|
|
|
const removeFromLibrary = () => {
|
2023-02-08 18:19:26 +01:00
|
|
|
mutate(`/api/v1/manga/${manga.id}/?onlineFetch=false`, { ...manga, inLibrary: false }, { revalidate: false });
|
2023-02-06 10:06:33 +01:00
|
|
|
client
|
|
|
|
|
.delete(`/api/v1/manga/${manga.id}/library/`)
|
2022-11-09 18:09:15 +01:00
|
|
|
.then(() => mutate(`/api/v1/manga/${manga.id}/?onlineFetch=false`));
|
|
|
|
|
};
|
2021-01-19 20:20:28 +03:30
|
|
|
|
|
|
|
|
return (
|
2021-03-17 19:17:03 +03:30
|
|
|
<div className={classes.root}>
|
|
|
|
|
<div className={classes.top}>
|
|
|
|
|
<div className={classes.leftRight}>
|
|
|
|
|
<div className={classes.leftSide}>
|
2023-02-08 18:19:26 +01:00
|
|
|
<img src={`${serverAddress}${manga.thumbnailUrl}?useCache=${useCache}`} alt="Manga Thumbnail" />
|
2021-03-17 19:17:03 +03:30
|
|
|
</div>
|
|
|
|
|
<div className={classes.rightSide}>
|
2023-02-06 10:06:33 +01:00
|
|
|
<h1>{manga.title}</h1>
|
2021-03-17 19:17:03 +03:30
|
|
|
<h3>
|
2023-03-23 13:59:32 +01:00
|
|
|
{`${t('manga.label.author')}: `}
|
2021-03-17 19:17:03 +03:30
|
|
|
<span>{getValueOrUnknown(manga.author)}</span>
|
|
|
|
|
</h3>
|
|
|
|
|
<h3>
|
2023-03-23 13:59:32 +01:00
|
|
|
{`${t('manga.label.artist')}: `}
|
2021-03-17 19:17:03 +03:30
|
|
|
<span>{getValueOrUnknown(manga.artist)}</span>
|
|
|
|
|
</h3>
|
2023-03-23 13:59:32 +01:00
|
|
|
<h3>{`${t('manga.label.status')}: ${manga.status}`}</h3>
|
|
|
|
|
<h3>{`${t('source.title')}: ${getSourceName(manga.source)}`}</h3>
|
2021-03-17 19:17:03 +03:30
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={classes.buttons}>
|
|
|
|
|
<div>
|
2023-02-08 18:19:26 +01:00
|
|
|
<IconButton onClick={manga.inLibrary ? removeFromLibrary : addToLibrary} size="large">
|
|
|
|
|
{manga.inLibrary ? <FavoriteIcon sx={{ mr: 1 }} /> : <FavoriteBorderIcon sx={{ mr: 1 }} />}
|
2022-11-09 18:09:15 +01:00
|
|
|
<Typography sx={{ fontSize: { xs: '0.75em', sm: '0.85em' } }}>
|
2023-03-23 13:59:32 +01:00
|
|
|
{manga.inLibrary ? t('manga.button.in_library') : t('manga.button.add_to_library')}
|
2022-11-09 18:09:15 +01:00
|
|
|
</Typography>
|
2021-03-17 19:17:03 +03:30
|
|
|
</IconButton>
|
|
|
|
|
</div>
|
2022-11-09 18:09:15 +01:00
|
|
|
<a href={manga.realUrl} target="_blank" rel="noreferrer">
|
2021-09-09 17:51:22 +04:30
|
|
|
<IconButton size="large">
|
2022-11-09 18:09:15 +01:00
|
|
|
<PublicIcon sx={{ mr: 1 }} />
|
2023-03-23 13:59:32 +01:00
|
|
|
<Typography sx={{ fontSize: { xs: '0.75em', sm: '0.85em' } }}>
|
|
|
|
|
{t('global.button.open_site')}
|
|
|
|
|
</Typography>
|
2021-03-17 19:17:03 +03:30
|
|
|
</IconButton>
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={classes.bottom}>
|
|
|
|
|
<div className={classes.description}>
|
2023-03-23 13:59:32 +01:00
|
|
|
<h4>{t('settings.about.title')}</h4>
|
2021-03-17 19:17:03 +03:30
|
|
|
<p>{manga.description}</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={classes.genre}>
|
2023-02-06 10:06:33 +01:00
|
|
|
{manga.genre.map((g) => (
|
|
|
|
|
<h5 key={g}>{g}</h5>
|
|
|
|
|
))}
|
2021-03-17 19:17:03 +03:30
|
|
|
</div>
|
2021-02-13 21:12:18 +03:30
|
|
|
</div>
|
2021-02-21 04:27:41 +03:30
|
|
|
</div>
|
2021-01-19 20:20:28 +03:30
|
|
|
);
|
2022-11-09 18:09:15 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default MangaDetails;
|