add filter and badge for downloadCount (#62)
* Added the Download filter and download badge * Update src/components/library/LibraryMangaGrid.tsx Co-authored-by: Sascha Hahne <ntbm@users.noreply.github.com> * - corrected some spelling mistakes Co-authored-by: Sascha Hahne <ntbm@users.noreply.github.com>
This commit is contained in:
@@ -40,17 +40,21 @@ const MangaTitle = styled(Typography)({
|
|||||||
textShadow: '0px 0px 3px #000000',
|
textShadow: '0px 0px 3px #000000',
|
||||||
});
|
});
|
||||||
|
|
||||||
const UnreadBadge = styled(Typography)(({ theme }) => ({
|
const BadgeContainer = styled('div')({
|
||||||
|
display: 'flex',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 2,
|
top: 5,
|
||||||
left: 2,
|
left: 5,
|
||||||
backgroundColor: theme.palette.primary.dark,
|
height: 'fit-content',
|
||||||
borderRadius: '5px',
|
borderRadius: '5px',
|
||||||
color: 'white',
|
overflow: 'hidden',
|
||||||
padding: '0.1em',
|
'& p': {
|
||||||
paddingInline: '0.3em',
|
color: 'white',
|
||||||
fontSize: '1.05rem',
|
padding: '0.1em',
|
||||||
}));
|
paddingInline: '0.2em',
|
||||||
|
fontSize: '1.05rem',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const truncateText = (str: string, maxLength: number) => {
|
const truncateText = (str: string, maxLength: number) => {
|
||||||
const ending = '...';
|
const ending = '...';
|
||||||
@@ -69,7 +73,7 @@ interface IProps {
|
|||||||
const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref) => {
|
const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref) => {
|
||||||
const {
|
const {
|
||||||
manga: {
|
manga: {
|
||||||
id, title, thumbnailUrl, unreadCount: unread,
|
id, title, thumbnailUrl, downloadCount, unreadCount: unread,
|
||||||
},
|
},
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
@@ -93,12 +97,24 @@ const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref)
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{unread! > 0
|
|
||||||
&& (
|
<BadgeContainer>
|
||||||
<UnreadBadge>
|
{unread! > 0 && (
|
||||||
|
<Typography
|
||||||
|
sx={{ backgroundColor: 'primary.dark' }}
|
||||||
|
>
|
||||||
{unread}
|
{unread}
|
||||||
</UnreadBadge>
|
</Typography>
|
||||||
) }
|
)}
|
||||||
|
{downloadCount! > 0 && (
|
||||||
|
<Typography sx={{
|
||||||
|
backgroundColor: 'success.dark',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{downloadCount}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</BadgeContainer>
|
||||||
<SpinnerImage
|
<SpinnerImage
|
||||||
alt={title}
|
alt={title}
|
||||||
src={`${serverAddress}${thumbnailUrl}?useCache=${useCache}`}
|
src={`${serverAddress}${thumbnailUrl}?useCache=${useCache}`}
|
||||||
@@ -107,7 +123,6 @@ const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref)
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
spinnerStyle={{
|
spinnerStyle={{
|
||||||
minHeight: '400px',
|
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
placeItems: 'center',
|
placeItems: 'center',
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -23,15 +23,29 @@ function unreadFilter(unread: NullAndUndefined<boolean>, { unreadCount }: IManga
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function downloadedFilter(downloaded: NullAndUndefined<boolean>,
|
||||||
|
{ downloadCount }: IMangaCard): boolean {
|
||||||
|
switch (downloaded) {
|
||||||
|
case true:
|
||||||
|
return !!downloadCount && downloadCount >= 1;
|
||||||
|
case false:
|
||||||
|
return downloadCount === 0;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function queryFilter(query: NullAndUndefined<string>, { title }: IMangaCard): boolean {
|
function queryFilter(query: NullAndUndefined<string>, { title }: IMangaCard): boolean {
|
||||||
if (!query) return true;
|
if (!query) return true;
|
||||||
return title.toLowerCase().includes(query.toLowerCase());
|
return title.toLowerCase().includes(query.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterManga(mangas: IMangaCard[]): IMangaCard[] {
|
function filterManga(mangas: IMangaCard[]): IMangaCard[] {
|
||||||
const { unread, query } = useLibraryOptions();
|
const { downloaded, unread, query } = useLibraryOptions();
|
||||||
return mangas
|
return mangas
|
||||||
.filter((manga) => unreadFilter(unread, manga) && queryFilter(query, manga));
|
.filter((manga) => downloadedFilter(downloaded, manga)
|
||||||
|
&& unreadFilter(unread, manga)
|
||||||
|
&& queryFilter(query, manga));
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function LibraryMangaGrid(props: IMangaGridProps) {
|
export default function LibraryMangaGrid(props: IMangaGridProps) {
|
||||||
|
|||||||
@@ -13,10 +13,13 @@ import useLibraryOptions from 'util/useLibraryOptions';
|
|||||||
import ThreeStateCheckbox from 'components/util/ThreeStateCheckbox';
|
import ThreeStateCheckbox from 'components/util/ThreeStateCheckbox';
|
||||||
|
|
||||||
function Options() {
|
function Options() {
|
||||||
const { unread, setUnread } = useLibraryOptions();
|
const {
|
||||||
|
downloaded, setDownloaded, unread, setUnread,
|
||||||
|
} = useLibraryOptions();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
<FormControlLabel control={<ThreeStateCheckbox name="Unread" checked={unread} onChange={setUnread} />} label="Unread" />
|
<FormControlLabel control={<ThreeStateCheckbox name="Unread" checked={unread} onChange={setUnread} />} label="Unread" />
|
||||||
|
<FormControlLabel control={<ThreeStateCheckbox name="Downloaded" checked={downloaded} onChange={setDownloaded} />} label="Downloaded" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
2
src/typings.d.ts
vendored
2
src/typings.d.ts
vendored
@@ -35,6 +35,7 @@ interface IMangaCard {
|
|||||||
title: string
|
title: string
|
||||||
thumbnailUrl: string
|
thumbnailUrl: string
|
||||||
unreadCount?: number
|
unreadCount?: number
|
||||||
|
downloadCount?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IManga {
|
interface IManga {
|
||||||
@@ -58,6 +59,7 @@ interface IManga {
|
|||||||
|
|
||||||
freshData: boolean
|
freshData: boolean
|
||||||
unreadCount?: number
|
unreadCount?: number
|
||||||
|
downloadCount?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IChapter {
|
interface IChapter {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import { BooleanParam, useQueryParams, StringParam } from 'use-query-params';
|
|||||||
export type NullAndUndefined<T> = T | null | undefined;
|
export type NullAndUndefined<T> = T | null | undefined;
|
||||||
|
|
||||||
interface IUseLibraryOptions {
|
interface IUseLibraryOptions {
|
||||||
|
downloaded: NullAndUndefined<boolean>
|
||||||
|
setDownloaded: (downloaded: NullAndUndefined<boolean>)=>void
|
||||||
unread: NullAndUndefined<boolean>
|
unread: NullAndUndefined<boolean>
|
||||||
setUnread: (unread: NullAndUndefined<boolean>) => void
|
setUnread: (unread: NullAndUndefined<boolean>) => void
|
||||||
query: NullAndUndefined<string>
|
query: NullAndUndefined<string>
|
||||||
@@ -20,10 +22,14 @@ interface IUseLibraryOptions {
|
|||||||
|
|
||||||
export default function useLibraryOptions(): IUseLibraryOptions {
|
export default function useLibraryOptions(): IUseLibraryOptions {
|
||||||
const [searchQuery, setSearchQuery] = useQueryParams({
|
const [searchQuery, setSearchQuery] = useQueryParams({
|
||||||
|
downloaded: BooleanParam,
|
||||||
unread: BooleanParam,
|
unread: BooleanParam,
|
||||||
query: StringParam,
|
query: StringParam,
|
||||||
});
|
});
|
||||||
const { unread, query } = searchQuery;
|
const { downloaded, unread, query } = searchQuery;
|
||||||
|
const setDownloaded = (newDownloaded: NullAndUndefined<boolean>) => {
|
||||||
|
setSearchQuery(Object.assign(searchQuery, { downloaded: newDownloaded }), 'replace');
|
||||||
|
};
|
||||||
const setUnread = (newUnread: NullAndUndefined<boolean>) => {
|
const setUnread = (newUnread: NullAndUndefined<boolean>) => {
|
||||||
setSearchQuery(Object.assign(searchQuery, { unread: newUnread }), 'replace');
|
setSearchQuery(Object.assign(searchQuery, { unread: newUnread }), 'replace');
|
||||||
};
|
};
|
||||||
@@ -31,8 +37,8 @@ export default function useLibraryOptions(): IUseLibraryOptions {
|
|||||||
setSearchQuery(Object.assign(searchQuery, { query: newQuery }), 'replace');
|
setSearchQuery(Object.assign(searchQuery, { query: newQuery }), 'replace');
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line eqeqeq
|
// eslint-disable-next-line eqeqeq
|
||||||
const active = !(unread == undefined);
|
const active = !(unread == undefined) || !(downloaded == undefined);
|
||||||
return {
|
return {
|
||||||
unread, setUnread, active, query, setQuery,
|
downloaded, setDownloaded, unread, setUnread, active, query, setQuery,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user