@@ -11,21 +11,30 @@ import { AppRoutes } from '@/base/AppRoute.constants.ts';
|
||||
import { Mangas } from '@/features/manga/services/Mangas.ts';
|
||||
import type { MangaIdInfo, MangaThumbnailInfo, MangaTitleInfo } from '@/features/manga/Manga.types.ts';
|
||||
import { ListCardAvatar } from '@/base/components/lists/cards/ListCardAvatar.tsx';
|
||||
import type { ComponentProps } from 'react';
|
||||
import merge from 'lodash/fp/merge';
|
||||
|
||||
export const ChapterCardThumbnail = ({
|
||||
mangaId,
|
||||
mangaTitle,
|
||||
thumbnailUrl,
|
||||
thumbnailUrlLastFetched,
|
||||
slots,
|
||||
}: MangaThumbnailInfo & {
|
||||
mangaId: MangaIdInfo['id'];
|
||||
mangaTitle: MangaTitleInfo['title'];
|
||||
slots?: {
|
||||
listCardAvatar?: Omit<ComponentProps<typeof ListCardAvatar>, 'alt' | 'iconUrl'>;
|
||||
};
|
||||
}) => (
|
||||
<Link to={AppRoutes.manga.path(mangaId)} style={{ textDecoration: 'none' }}>
|
||||
<ListCardAvatar
|
||||
iconUrl={Mangas.getThumbnailUrl({ thumbnailUrl, thumbnailUrlLastFetched })}
|
||||
alt={mangaTitle}
|
||||
slots={{ spinnerImageProps: { imgStyle: { imageRendering: 'pixelated' } } }}
|
||||
slots={merge(
|
||||
{ spinnerImageProps: { imgStyle: { imageRendering: 'pixelated' } } },
|
||||
slots?.listCardAvatar?.slots,
|
||||
)}
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ import Box from '@mui/material/Box';
|
||||
import CardActionArea from '@mui/material/CardActionArea';
|
||||
import Card from '@mui/material/Card';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { memo, useState } from 'react';
|
||||
import { DownloadStateIndicator } from '@/base/components/downloads/DownloadStateIndicator.tsx';
|
||||
import type { ChapterUpdateListFieldsFragment } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { AppRoutes } from '@/base/AppRoute.constants.ts';
|
||||
@@ -20,49 +20,31 @@ import { ChapterDownloadButton } from '@/features/chapter/components/buttons/Cha
|
||||
import { ChapterDownloadRetryButton } from '@/features/chapter/components/buttons/ChapterDownloadRetryButton.tsx';
|
||||
import { Chapters } from '@/features/chapter/services/Chapters.ts';
|
||||
import { ListCardContent } from '@/base/components/lists/cards/ListCardContent.tsx';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { plural } from '@lingui/core/macro';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Button from '@mui/material/Button';
|
||||
import { MUIUtil } from '@/lib/mui/MUI.util.ts';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
||||
import Collapse from '@mui/material/Collapse';
|
||||
import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
export const ChapterUpdateCard = memo(
|
||||
({
|
||||
chapter,
|
||||
otherChapters,
|
||||
otherChapters = STABLE_EMPTY_ARRAY,
|
||||
}: {
|
||||
chapter: ChapterUpdateListFieldsFragment;
|
||||
otherChapters: ChapterUpdateListFieldsFragment[];
|
||||
otherChapters?: ChapterUpdateListFieldsFragment[];
|
||||
}) => {
|
||||
const { manga } = chapter;
|
||||
|
||||
const { t } = useLingui();
|
||||
const theme = useTheme();
|
||||
|
||||
const uniqueOtherChapters = useMemo(
|
||||
() => Chapters.removeDuplicates(chapter, otherChapters),
|
||||
[chapter, otherChapters],
|
||||
);
|
||||
const otherChaptersCount = uniqueOtherChapters.length;
|
||||
const firstFewOtherChapters = uniqueOtherChapters.slice(-3);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const otherChaptersText = (() => {
|
||||
if (!otherChaptersCount) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const firstFewUpdatesString = firstFewOtherChapters
|
||||
.map((otherChapter) => `#${otherChapter.chapterNumber}`)
|
||||
.toReversed()
|
||||
.join(', ');
|
||||
|
||||
if (otherChaptersCount > firstFewOtherChapters.length) {
|
||||
const remainingUpdatesCount = otherChaptersCount - firstFewOtherChapters.length;
|
||||
|
||||
return t`Plus chapters ${firstFewUpdatesString} and ${remainingUpdatesCount} more`;
|
||||
}
|
||||
|
||||
return plural(firstFewOtherChapters.length, {
|
||||
one: `Plus chapter ${firstFewUpdatesString}`,
|
||||
other: `Plus chapters ${firstFewUpdatesString}`,
|
||||
});
|
||||
})();
|
||||
const isGroup = !!otherChapters.length;
|
||||
|
||||
return (
|
||||
<Card>
|
||||
@@ -71,7 +53,7 @@ export const ChapterUpdateCard = memo(
|
||||
to={AppRoutes.reader.path(chapter.manga.id, chapter.sourceOrder)}
|
||||
state={Chapters.getReaderOpenChapterLocationState(chapter)}
|
||||
sx={{
|
||||
color: (theme) => theme.palette.text[chapter.isRead ? 'disabled' : 'primary'],
|
||||
color: theme.palette.text[chapter.isRead ? 'disabled' : 'primary'],
|
||||
}}
|
||||
>
|
||||
<ListCardContent sx={{ justifyContent: 'space-between' }}>
|
||||
@@ -82,18 +64,66 @@ export const ChapterUpdateCard = memo(
|
||||
mangaTitle={manga.title}
|
||||
thumbnailUrl={manga.thumbnailUrl}
|
||||
thumbnailUrlLastFetched={manga.thumbnailUrlLastFetched}
|
||||
slots={
|
||||
isGroup
|
||||
? {
|
||||
listCardAvatar: {
|
||||
slots: {
|
||||
spinnerImageProps: {
|
||||
spinnerStyle: {
|
||||
height: 74,
|
||||
aspectRatio: '3 / 4',
|
||||
},
|
||||
imgStyle: {
|
||||
height: 74,
|
||||
aspectRatio: '3 / 4',
|
||||
},
|
||||
},
|
||||
avatarProps: {
|
||||
sx: {
|
||||
height: 74,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<ChapterCardMetadata
|
||||
title={manga.title}
|
||||
secondaryText={chapter.name}
|
||||
ternaryText={otherChaptersText}
|
||||
/>
|
||||
<Stack>
|
||||
<ChapterCardMetadata title={manga.title} secondaryText={chapter.name} />
|
||||
{isGroup && (
|
||||
<Button
|
||||
sx={{ width: 'fit-content', ...theme.typography.caption }}
|
||||
variant="text"
|
||||
size="small"
|
||||
endIcon={isExpanded ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
||||
{...MUIUtil.preventRippleProp()}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setIsExpanded(!isExpanded);
|
||||
}}
|
||||
>
|
||||
{plural(otherChapters.length, {
|
||||
one: 'Show # more chapter',
|
||||
other: 'Show # more chapters',
|
||||
})}
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
<DownloadStateIndicator chapterId={chapter.id} />
|
||||
<ChapterDownloadRetryButton chapterId={chapter.id} />
|
||||
<ChapterDownloadButton chapterId={chapter.id} isDownloaded={chapter.isDownloaded} />
|
||||
</ListCardContent>
|
||||
</CardActionArea>
|
||||
{isGroup && (
|
||||
<Collapse in={isExpanded} unmountOnExit>
|
||||
{otherChapters.map((otherChapter) => (
|
||||
<ChapterUpdateCard key={otherChapter.id} chapter={otherChapter} />
|
||||
))}
|
||||
</Collapse>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user