increase prettier line length to 120 (#233)

* [Prettier] Increase max line length to 120

100 is quite low, especially on modern monitors.
The length is also reached quite quickly with 4 spaces per tab depending on the indentation depth

* [Prettier] Increase max line length to 120 - Fix formatting
This commit is contained in:
Daniel
2023-02-08 18:19:26 +01:00
committed by GitHub
parent b958d74b92
commit 2c11708c92
54 changed files with 156 additions and 542 deletions

View File

@@ -1,7 +1,7 @@
{ {
"tabWidth": 4, "tabWidth": 4,
"singleQuote": true, "singleQuote": true,
"printWidth": 100, "printWidth": 120,
"semi": true, "semi": true,
"trailingComma": "all" "trailingComma": "all"
} }

View File

@@ -22,17 +22,7 @@ interface IProps {
export default function ExtensionCard(props: IProps) { export default function ExtensionCard(props: IProps) {
const { const {
extension: { extension: { name, lang, versionName, installed, hasUpdate, obsolete, pkgName, iconUrl, isNsfw },
name,
lang,
versionName,
installed,
hasUpdate,
obsolete,
pkgName,
iconUrl,
isNsfw,
},
notifyInstall, notifyInstall,
} = props; } = props;
const [installedState, setInstalledState] = useState<string>(() => { const [installedState, setInstalledState] = useState<string>(() => {
@@ -123,12 +113,7 @@ export default function ExtensionCard(props: IProps) {
<Typography variant="caption" display="block" gutterBottom> <Typography variant="caption" display="block" gutterBottom>
{langPress} {versionName} {langPress} {versionName}
{isNsfw && ( {isNsfw && (
<Typography <Typography variant="caption" display="inline" gutterBottom color="red">
variant="caption"
display="inline"
gutterBottom
color="red"
>
{' 18+'} {' 18+'}
</Typography> </Typography>
)} )}

View File

@@ -100,10 +100,7 @@ const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref)
const cols = Math.ceil(dimensions / ItemWidth); const cols = Math.ceil(dimensions / ItemWidth);
return ( return (
<Grid item columns={cols} xs={1}> <Grid item columns={cols} xs={1}>
<Link <Link to={mangaLinkTo} style={gridLayout === GridLayout.Comfortable ? { textDecoration: 'none' } : {}}>
to={mangaLinkTo}
style={gridLayout === GridLayout.Comfortable ? { textDecoration: 'none' } : {}}
>
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
@@ -132,16 +129,12 @@ const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref)
}} }}
> >
{inLibraryIndicator && inLibrary && ( {inLibraryIndicator && inLibrary && (
<Typography <Typography sx={{ backgroundColor: 'primary.dark', zIndex: '1' }}>
sx={{ backgroundColor: 'primary.dark', zIndex: '1' }}
>
In library In library
</Typography> </Typography>
)} )}
{showUnreadBadge && unread! > 0 && ( {showUnreadBadge && unread! > 0 && (
<Typography sx={{ backgroundColor: 'primary.dark' }}> <Typography sx={{ backgroundColor: 'primary.dark' }}>{unread}</Typography>
{unread}
</Typography>
)} )}
{showDownloadBadge && downloadCount! > 0 && ( {showDownloadBadge && downloadCount! > 0 && (
<Typography <Typography
@@ -266,14 +259,10 @@ const MangaCard = React.forwardRef<HTMLDivElement, IProps>((props: IProps, ref)
</Box> </Box>
<BadgeContainer> <BadgeContainer>
{inLibraryIndicator && inLibrary && ( {inLibraryIndicator && inLibrary && (
<Typography sx={{ backgroundColor: 'primary.dark' }}> <Typography sx={{ backgroundColor: 'primary.dark' }}>In library</Typography>
In library
</Typography>
)} )}
{showUnreadBadge && unread! > 0 && ( {showUnreadBadge && unread! > 0 && (
<Typography sx={{ backgroundColor: 'primary.dark' }}> <Typography sx={{ backgroundColor: 'primary.dark' }}>{unread}</Typography>
{unread}
</Typography>
)} )}
{showDownloadBadge && downloadCount! > 0 && ( {showDownloadBadge && downloadCount! > 0 && (
<Typography <Typography

View File

@@ -97,12 +97,7 @@ const SourceCard: React.FC<IProps> = (props: IProps) => {
<Typography variant="caption" display="block" gutterBottom> <Typography variant="caption" display="block" gutterBottom>
{langCodeToName(lang)} {langCodeToName(lang)}
{isNsfw && ( {isNsfw && (
<Typography <Typography variant="caption" display="inline" gutterBottom color="red">
variant="caption"
display="inline"
gutterBottom
color="red"
>
{' 18+'} {' 18+'}
</Typography> </Typography>
)} )}
@@ -113,29 +108,18 @@ const SourceCard: React.FC<IProps> = (props: IProps) => {
<> <>
<MobileWidthButtons> <MobileWidthButtons>
{supportsLatest && ( {supportsLatest && (
<Button <Button variant="outlined" onClick={(e) => redirectTo(e, `/sources/${id}/latest/`)}>
variant="outlined"
onClick={(e) => redirectTo(e, `/sources/${id}/latest/`)}
>
Latest Latest
</Button> </Button>
)} )}
</MobileWidthButtons> </MobileWidthButtons>
<WiderWidthButtons> <WiderWidthButtons>
{supportsLatest && ( {supportsLatest && (
<Button <Button component={Link} to={`/sources/${id}/latest/`} variant="outlined">
component={Link}
to={`/sources/${id}/latest/`}
variant="outlined"
>
Latest Latest
</Button> </Button>
)} )}
<Button <Button component={Link} to={`/sources/${id}/popular/`} variant="outlined">
component={Link}
to={`/sources/${id}/popular/`}
variant="outlined"
>
Browse Browse
</Button> </Button>
</WiderWidthButtons> </WiderWidthButtons>

View File

@@ -17,9 +17,7 @@ interface IProps extends RadioInputProps {
const SortRadioInput: React.FC<IProps> = ({ sortDescending, ...rest }) => ( const SortRadioInput: React.FC<IProps> = ({ sortDescending, ...rest }) => (
<RadioInput <RadioInput
checkedIcon={ checkedIcon={sortDescending ? <ArrowDownward color="primary" /> : <ArrowUpward color="primary" />}
sortDescending ? <ArrowDownward color="primary" /> : <ArrowUpward color="primary" />
}
{...rest} {...rest}
/> />
); );

View File

@@ -24,10 +24,7 @@ const unreadFilter = (unread: NullAndUndefined<boolean>, { unreadCount }: IManga
} }
}; };
const downloadedFilter = ( const downloadedFilter = (downloaded: NullAndUndefined<boolean>, { downloadCount }: IMangaCard): boolean => {
downloaded: NullAndUndefined<boolean>,
{ downloadCount }: IMangaCard,
): boolean => {
switch (downloaded) { switch (downloaded) {
case true: case true:
return !!downloadCount && downloadCount >= 1; return !!downloadCount && downloadCount >= 1;
@@ -117,9 +114,7 @@ const LibraryMangaGrid: React.FC<IMangaGridProps & { lastLibraryUpdate: number }
); );
const showFilteredOutMessage = const showFilteredOutMessage =
(unread != null || downloaded != null || query) && (unread != null || downloaded != null || query) && filteredManga.length === 0 && mangas.length > 0;
filteredManga.length === 0 &&
mangas.length > 0;
return ( return (
<MangaGrid <MangaGrid

View File

@@ -34,10 +34,7 @@ interface IProps {
const LibraryOptionsPanel: React.FC<IProps> = ({ open, onClose }) => { const LibraryOptionsPanel: React.FC<IProps> = ({ open, onClose }) => {
const { options, setOptions } = useLibraryOptionsContext(); const { options, setOptions } = useLibraryOptionsContext();
const handleFilterChange = <T extends keyof LibraryOptions>( const handleFilterChange = <T extends keyof LibraryOptions>(key: T, value: LibraryOptions[T]) => {
key: T,
value: LibraryOptions[T],
) => {
setOptions((v) => ({ ...v, [key]: value })); setOptions((v) => ({ ...v, [key]: value }));
}; };
@@ -85,17 +82,13 @@ const LibraryOptionsPanel: React.FC<IProps> = ({ open, onClose }) => {
<> <>
<FormLabel>Display mode</FormLabel> <FormLabel>Display mode</FormLabel>
<RadioGroup <RadioGroup
onChange={(e) => onChange={(e) => handleFilterChange('gridLayout', Number(e.target.value))}
handleFilterChange('gridLayout', Number(e.target.value))
}
value={gridLayout} value={gridLayout}
> >
<RadioInput <RadioInput
label="Compact grid" label="Compact grid"
value={GridLayout.Compact} value={GridLayout.Compact}
checked={ checked={gridLayout == null || gridLayout === GridLayout.Compact}
gridLayout == null || gridLayout === GridLayout.Compact
}
/> />
<RadioInput <RadioInput
label="Comfortable grid" label="Comfortable grid"
@@ -113,16 +106,12 @@ const LibraryOptionsPanel: React.FC<IProps> = ({ open, onClose }) => {
<CheckboxInput <CheckboxInput
label="Unread Badges" label="Unread Badges"
checked={showUnreadBadge === true} checked={showUnreadBadge === true}
onChange={() => onChange={() => handleFilterChange('showUnreadBadge', !showUnreadBadge)}
handleFilterChange('showUnreadBadge', !showUnreadBadge)
}
/> />
<CheckboxInput <CheckboxInput
label="Download Badges" label="Download Badges"
checked={showDownloadBadge === true} checked={showDownloadBadge === true}
onChange={() => onChange={() => handleFilterChange('showDownloadBadge', !showDownloadBadge)}
handleFilterChange('showDownloadBadge', !showDownloadBadge)
}
/> />
</> </>
); );

View File

@@ -5,9 +5,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import LibraryOptionsContext, { import LibraryOptionsContext, { DefaultLibraryOptions } from 'components/context/LibraryOptionsContext';
DefaultLibraryOptions,
} from 'components/context/LibraryOptionsContext';
import React from 'react'; import React from 'react';
import useLocalStorage from 'util/useLocalStorage'; import useLocalStorage from 'util/useLocalStorage';
@@ -16,16 +14,9 @@ interface IProps {
} }
const LibraryOptionsContextProvider: React.FC<IProps> = ({ children }) => { const LibraryOptionsContextProvider: React.FC<IProps> = ({ children }) => {
const [options, setOptions] = useLocalStorage<LibraryOptions>( const [options, setOptions] = useLocalStorage<LibraryOptions>('libraryOptions', DefaultLibraryOptions);
'libraryOptions',
DefaultLibraryOptions,
);
return ( return <LibraryOptionsContext.Provider value={{ options, setOptions }}>{children}</LibraryOptionsContext.Provider>;
<LibraryOptionsContext.Provider value={{ options, setOptions }}>
{children}
</LibraryOptionsContext.Provider>
);
}; };
export default LibraryOptionsContextProvider; export default LibraryOptionsContextProvider;

View File

@@ -22,10 +22,7 @@ function Progress({ progress }: IProgressProps) {
); );
} }
const baseWebsocketUrl = JSON.parse(window.localStorage.getItem('serverBaseURL')!).replace( const baseWebsocketUrl = JSON.parse(window.localStorage.getItem('serverBaseURL')!).replace('http', 'ws');
'http',
'ws',
);
interface IUpdateCheckerProps { interface IUpdateCheckerProps {
handleFinishedUpdate: (time: number) => void; handleFinishedUpdate: (time: number) => void;
@@ -58,8 +55,7 @@ function UpdateChecker({ handleFinishedUpdate }: IUpdateCheckerProps) {
const { running, statusMap } = JSON.parse(e.data) as IUpdateStatus; const { running, statusMap } = JSON.parse(e.data) as IUpdateStatus;
const { COMPLETE = [], RUNNING = [], PENDING = [] } = statusMap; const { COMPLETE = [], RUNNING = [], PENDING = [] } = statusMap;
const currentProgress = const currentProgress = 100 * (COMPLETE.length / (COMPLETE.length + RUNNING.length + PENDING.length));
100 * (COMPLETE.length / (COMPLETE.length + RUNNING.length + PENDING.length));
const isUpdateFinished = currentProgress === 100; const isUpdateFinished = currentProgress === 100;
const ignoreFaultyMessage = !updateStarted && !running && isUpdateFinished; const ignoreFaultyMessage = !updateStarted && !running && isUpdateFinished;

View File

@@ -1,9 +1,6 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
const baseWebsocketUrl = JSON.parse(window.localStorage.getItem('serverBaseURL')!).replace( const baseWebsocketUrl = JSON.parse(window.localStorage.getItem('serverBaseURL')!).replace('http', 'ws');
'http',
'ws',
);
const useSubscription = <T>(path: string, callback?: (newValue: T) => boolean | void) => { const useSubscription = <T>(path: string, callback?: (newValue: T) => boolean | void) => {
const [state, setState] = useState<T | undefined>(); const [state, setState] = useState<T | undefined>();

View File

@@ -42,14 +42,7 @@ interface IProps {
const ChapterCard: React.FC<IProps> = (props: IProps) => { const ChapterCard: React.FC<IProps> = (props: IProps) => {
const theme = useTheme(); const theme = useTheme();
const { const { chapter, triggerChaptersUpdate, downloadChapter: dc, showChapterNumber, onSelect, selected } = props;
chapter,
triggerChaptersUpdate,
downloadChapter: dc,
showChapterNumber,
onSelect,
selected,
} = props;
const isSelecting = selected !== null; const isSelecting = selected !== null;
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
@@ -85,9 +78,7 @@ const ChapterCard: React.FC<IProps> = (props: IProps) => {
}; };
const deleteChapter = () => { const deleteChapter = () => {
client client.delete(`/api/v1/manga/${chapter.mangaId}/chapter/${chapter.index}`).then(() => triggerChaptersUpdate());
.delete(`/api/v1/manga/${chapter.mangaId}/chapter/${chapter.index}`)
.then(() => triggerChaptersUpdate());
handleClose(); handleClose();
}; };
@@ -143,9 +134,7 @@ const ChapterCard: React.FC<IProps> = (props: IProps) => {
sx={{ mr: 0.5, position: 'relative', top: '0.15em' }} sx={{ mr: 0.5, position: 'relative', top: '0.15em' }}
/> />
)} )}
{showChapterNumber {showChapterNumber ? `Chapter ${chapter.chapterNumber}` : chapter.name}
? `Chapter ${chapter.chapterNumber}`
: chapter.name}
</Typography> </Typography>
<Typography variant="caption">{chapter.scanlator}</Typography> <Typography variant="caption">{chapter.scanlator}</Typography>
<Typography variant="caption"> <Typography variant="caption">
@@ -165,12 +154,7 @@ const ChapterCard: React.FC<IProps> = (props: IProps) => {
)} )}
</CardContent> </CardContent>
</CardActionArea> </CardActionArea>
<Menu <Menu anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleSelect}> <MenuItem onClick={handleSelect}>
<ListItemIcon> <ListItemIcon>
<CheckBoxOutlineBlank fontSize="small" /> <CheckBoxOutlineBlank fontSize="small" />

View File

@@ -140,10 +140,7 @@ const ChapterList: React.FC<IProps> = ({ mangaId }) => {
setSelection(null); setSelection(null);
}; };
const handleFabAction: ComponentProps<typeof SelectionFAB>['onAction'] = ( const handleFabAction: ComponentProps<typeof SelectionFAB>['onAction'] = (action, actionChapters) => {
action,
actionChapters,
) => {
if (actionChapters.length === 0) return; if (actionChapters.length === 0) return;
const chapterIds = actionChapters.map(({ chapter }) => chapter.id); const chapterIds = actionChapters.map(({ chapter }) => chapter.id);
@@ -164,16 +161,9 @@ const ChapterList: React.FC<IProps> = ({ mangaId }) => {
} }
actionPromise actionPromise
.then(() => .then(() => makeToast(interpolate(chapterIds.length, actionsStrings[action].success), 'success'))
makeToast(
interpolate(chapterIds.length, actionsStrings[action].success),
'success',
),
)
.then(() => mutate()) .then(() => mutate())
.catch(() => .catch(() => makeToast(interpolate(chapterIds.length, actionsStrings[action].error), 'error'));
makeToast(interpolate(chapterIds.length, actionsStrings[action].error), 'error'),
);
}; };
if (loading) { if (loading) {
@@ -206,9 +196,7 @@ const ChapterList: React.FC<IProps> = ({ mangaId }) => {
}); });
const selectedChapters = const selectedChapters =
selection === null selection === null ? null : chaptersWithMeta.filter(({ chapter }) => selection.includes(chapter.id));
? null
: chaptersWithMeta.filter(({ chapter }) => selection.includes(chapter.id));
return ( return (
<> <>
@@ -225,9 +213,7 @@ const ChapterList: React.FC<IProps> = ({ mangaId }) => {
}} }}
> >
<Typography variant="h5"> <Typography variant="h5">
{`${visibleChapters.length} Chapter${ {`${visibleChapters.length} Chapter${visibleChapters.length === 1 ? '' : 's'}`}
visibleChapters.length === 1 ? '' : 's'
}`}
</Typography> </Typography>
{selection === null ? ( {selection === null ? (

View File

@@ -134,22 +134,14 @@ const MangaDetails: React.FC<IProps> = ({ manga }) => {
const classes = useStyles(manga.inLibrary)(); const classes = useStyles(manga.inLibrary)();
const addToLibrary = () => { const addToLibrary = () => {
mutate( mutate(`/api/v1/manga/${manga.id}/?onlineFetch=false`, { ...manga, inLibrary: true }, { revalidate: false });
`/api/v1/manga/${manga.id}/?onlineFetch=false`,
{ ...manga, inLibrary: true },
{ revalidate: false },
);
client client
.get(`/api/v1/manga/${manga.id}/library/`) .get(`/api/v1/manga/${manga.id}/library/`)
.then(() => mutate(`/api/v1/manga/${manga.id}/?onlineFetch=false`)); .then(() => mutate(`/api/v1/manga/${manga.id}/?onlineFetch=false`));
}; };
const removeFromLibrary = () => { const removeFromLibrary = () => {
mutate( mutate(`/api/v1/manga/${manga.id}/?onlineFetch=false`, { ...manga, inLibrary: false }, { revalidate: false });
`/api/v1/manga/${manga.id}/?onlineFetch=false`,
{ ...manga, inLibrary: false },
{ revalidate: false },
);
client client
.delete(`/api/v1/manga/${manga.id}/library/`) .delete(`/api/v1/manga/${manga.id}/library/`)
.then(() => mutate(`/api/v1/manga/${manga.id}/?onlineFetch=false`)); .then(() => mutate(`/api/v1/manga/${manga.id}/?onlineFetch=false`));
@@ -160,10 +152,7 @@ const MangaDetails: React.FC<IProps> = ({ manga }) => {
<div className={classes.top}> <div className={classes.top}>
<div className={classes.leftRight}> <div className={classes.leftRight}>
<div className={classes.leftSide}> <div className={classes.leftSide}>
<img <img src={`${serverAddress}${manga.thumbnailUrl}?useCache=${useCache}`} alt="Manga Thumbnail" />
src={`${serverAddress}${manga.thumbnailUrl}?useCache=${useCache}`}
alt="Manga Thumbnail"
/>
</div> </div>
<div className={classes.rightSide}> <div className={classes.rightSide}>
<h1>{manga.title}</h1> <h1>{manga.title}</h1>
@@ -181,15 +170,8 @@ const MangaDetails: React.FC<IProps> = ({ manga }) => {
</div> </div>
<div className={classes.buttons}> <div className={classes.buttons}>
<div> <div>
<IconButton <IconButton onClick={manga.inLibrary ? removeFromLibrary : addToLibrary} size="large">
onClick={manga.inLibrary ? removeFromLibrary : addToLibrary} {manga.inLibrary ? <FavoriteIcon sx={{ mr: 1 }} /> : <FavoriteBorderIcon sx={{ mr: 1 }} />}
size="large"
>
{manga.inLibrary ? (
<FavoriteIcon sx={{ mr: 1 }} />
) : (
<FavoriteBorderIcon sx={{ mr: 1 }} />
)}
<Typography sx={{ fontSize: { xs: '0.75em', sm: '0.85em' } }}> <Typography sx={{ fontSize: { xs: '0.75em', sm: '0.85em' } }}>
{manga.inLibrary ? 'In Library' : 'Add To Library'} {manga.inLibrary ? 'In Library' : 'Add To Library'}
</Typography> </Typography>
@@ -198,9 +180,7 @@ const MangaDetails: React.FC<IProps> = ({ manga }) => {
<a href={manga.realUrl} target="_blank" rel="noreferrer"> <a href={manga.realUrl} target="_blank" rel="noreferrer">
<IconButton size="large"> <IconButton size="large">
<PublicIcon sx={{ mr: 1 }} /> <PublicIcon sx={{ mr: 1 }} />
<Typography sx={{ fontSize: { xs: '0.75em', sm: '0.85em' } }}> <Typography sx={{ fontSize: { xs: '0.75em', sm: '0.85em' } }}>Open Site</Typography>
Open Site
</Typography>
</IconButton> </IconButton>
</a> </a>
</div> </div>

View File

@@ -13,13 +13,7 @@ import React, { useRef, useState } from 'react';
import type { IChapterWithMeta } from 'components/manga/ChapterList'; import type { IChapterWithMeta } from 'components/manga/ChapterList';
import SelectionFABActionItem from 'components/manga/SelectionFABActionItem'; import SelectionFABActionItem from 'components/manga/SelectionFABActionItem';
export type SelectionAction = export type SelectionAction = 'download' | 'delete' | 'bookmark' | 'unbookmark' | 'mark_as_read' | 'mark_as_unread';
| 'download'
| 'delete'
| 'bookmark'
| 'unbookmark'
| 'mark_as_read'
| 'mark_as_unread';
interface SelectionFABProps { interface SelectionFABProps {
selectedChapters: IChapterWithMeta[]; selectedChapters: IChapterWithMeta[];
@@ -49,12 +43,7 @@ const SelectionFAB: React.FC<SelectionFABProps> = (props) => {
}} }}
ref={anchorEl} ref={anchorEl}
> >
<Fab <Fab variant="extended" color="primary" id="selectionMenuButton" onClick={() => setOpen(true)}>
variant="extended"
color="primary"
id="selectionMenuButton"
onClick={() => setOpen(true)}
>
{`${count} ${pluralize(count, 'chapter')}`} {`${count} ${pluralize(count, 'chapter')}`}
<MoreHoriz sx={{ ml: 1 }} /> <MoreHoriz sx={{ ml: 1 }} />
</Fab> </Fab>

View File

@@ -17,15 +17,11 @@ const defaultChapterOptions: ChapterListOptions = {
showChapterNumber: false, showChapterNumber: false,
}; };
function chapterOptionsReducer( function chapterOptionsReducer(state: ChapterListOptions, actions: ChapterOptionsReducerAction): ChapterListOptions {
state: ChapterListOptions,
actions: ChapterOptionsReducerAction,
): ChapterListOptions {
switch (actions.type) { switch (actions.type) {
case 'filter': case 'filter':
// eslint-disable-next-line no-case-declarations // eslint-disable-next-line no-case-declarations
const active = const active = state.unread !== false && state.downloaded !== false && state.bookmarked !== false;
state.unread !== false && state.downloaded !== false && state.bookmarked !== false;
return { return {
...state, ...state,
active, active,
@@ -53,10 +49,7 @@ export function unreadFilter(unread: NullAndUndefined<boolean>, { read: isChapte
} }
} }
function downloadFilter( function downloadFilter(downloaded: NullAndUndefined<boolean>, { downloaded: chapterDownload }: IChapter) {
downloaded: NullAndUndefined<boolean>,
{ downloaded: chapterDownload }: IChapter,
) {
switch (downloaded) { switch (downloaded) {
case true: case true:
return chapterDownload; return chapterDownload;
@@ -67,10 +60,7 @@ function downloadFilter(
} }
} }
function bookmarkedFilter( function bookmarkedFilter(bookmarked: NullAndUndefined<boolean>, { bookmarked: chapterBookmarked }: IChapter) {
bookmarked: NullAndUndefined<boolean>,
{ bookmarked: chapterBookmarked }: IChapter,
) {
switch (bookmarked) { switch (bookmarked) {
case true: case true:
return chapterBookmarked; return chapterBookmarked;
@@ -81,10 +71,7 @@ function bookmarkedFilter(
} }
} }
export function filterAndSortChapters( export function filterAndSortChapters(chapters: IChapter[], options: ChapterListOptions): IChapter[] {
chapters: IChapter[],
options: ChapterListOptions,
): IChapter[] {
const filtered = options.active const filtered = options.active
? chapters.filter( ? chapters.filter(
(chp) => (chp) =>
@@ -93,10 +80,7 @@ export function filterAndSortChapters(
bookmarkedFilter(options.bookmarked, chp), bookmarkedFilter(options.bookmarked, chp),
) )
: [...chapters]; : [...chapters];
const Sorted = const Sorted = options.sortBy === 'fetchedAt' ? filtered.sort((a, b) => a.fetchedAt - b.fetchedAt) : filtered;
options.sortBy === 'fetchedAt'
? filtered.sort((a, b) => a.fetchedAt - b.fetchedAt)
: filtered;
if (options.reverse) { if (options.reverse) {
Sorted.reverse(); Sorted.reverse();
} }

View File

@@ -24,9 +24,7 @@ const DownloadStateIndicator: React.FC<DownloadStateIndicatorProps> = ({ downloa
justifyContent: 'center', justifyContent: 'center',
}} }}
> >
{download.progress !== 0 && ( {download.progress !== 0 && <CircularProgress variant="determinate" value={download.progress * 100} />}
<CircularProgress variant="determinate" value={download.progress * 100} />
)}
<Box <Box
sx={{ sx={{
top: 0, top: 0,

View File

@@ -100,9 +100,7 @@ export default function DefaultNavBar() {
let navbar = <></>; let navbar = <></>;
if (isMobileWidth) { if (isMobileWidth) {
if (isMainRoute) { if (isMainRoute) {
navbar = ( navbar = <MobileBottomBar navBarItems={navbarItems.filter((it) => it.show !== 'desktop')} />;
<MobileBottomBar navBarItems={navbarItems.filter((it) => it.show !== 'desktop')} />
);
} }
} else { } else {
navbar = <DesktopSideBar navBarItems={navbarItems.filter((it) => it.show !== 'mobile')} />; navbar = <DesktopSideBar navBarItems={navbarItems.filter((it) => it.show !== 'mobile')} />;

View File

@@ -126,9 +126,7 @@ export default function ReaderNavBar(props: IProps) {
const [updateDrawerOnRender, setUpdateDrawerOnRender] = useState(true); const [updateDrawerOnRender, setUpdateDrawerOnRender] = useState(true);
const [hideOpenButton, setHideOpenButton] = useState(settings.staticNav || prevDrawerOpen); const [hideOpenButton, setHideOpenButton] = useState(settings.staticNav || prevDrawerOpen);
const [prevScrollPos, setPrevScrollPos] = useState(0); const [prevScrollPos, setPrevScrollPos] = useState(0);
const [settingsCollapseOpen, setSettingsCollapseOpen] = useState( const [settingsCollapseOpen, setSettingsCollapseOpen] = useState(prevSettingsCollapseOpen ?? true);
prevSettingsCollapseOpen ?? true,
);
const updateSettingValue = (key: keyof IReaderSettings, value: string | boolean) => { const updateSettingValue = (key: keyof IReaderSettings, value: string | boolean) => {
// prevent closing the navBar when updating the "staticNav" setting // prevent closing the navBar when updating the "staticNav" setting
@@ -181,14 +179,7 @@ export default function ReaderNavBar(props: IProps) {
return ( return (
<> <>
<Slide <Slide direction="right" in={drawerOpen} timeout={200} appear={false} mountOnEnter unmountOnExit>
direction="right"
in={drawerOpen}
timeout={200}
appear={false}
mountOnEnter
unmountOnExit
>
<Root <Root
sx={{ sx={{
position: settings.staticNav ? 'sticky' : 'fixed', position: settings.staticNav ? 'sticky' : 'fixed',
@@ -207,12 +198,7 @@ export default function ReaderNavBar(props: IProps) {
<KeyboardArrowLeftIcon /> <KeyboardArrowLeftIcon />
</IconButton> </IconButton>
)} )}
<Typography <Typography variant="h1" textOverflow="ellipsis" overflow="hidden" sx={{ py: 1 }}>
variant="h1"
textOverflow="ellipsis"
overflow="hidden"
sx={{ py: 1 }}
>
{chapter.name} {chapter.name}
</Typography> </Typography>
<IconButton <IconButton

View File

@@ -25,9 +25,7 @@ interface IProps {
export default function CategorySelect(props: IProps) { export default function CategorySelect(props: IProps) {
const { open, setOpen, mangaId } = props; const { open, setOpen, mangaId } = props;
const { data: mangaCategoriesData, mutate } = useQuery<ICategory[]>( const { data: mangaCategoriesData, mutate } = useQuery<ICategory[]>(`/api/v1/manga/${mangaId}/category`);
`/api/v1/manga/${mangaId}/category`,
);
const { data: categoriesData } = useQuery<ICategory[]>('/api/v1/category'); const { data: categoriesData } = useQuery<ICategory[]>('/api/v1/category');
const allCategories = useMemo(() => { const allCategories = useMemo(() => {

View File

@@ -40,9 +40,7 @@ interface IProps {
export default function LangSelect(props: IProps) { export default function LangSelect(props: IProps) {
const { shownLangs, setShownLangs, allLangs, forcedLangs } = props; const { shownLangs, setShownLangs, allLangs, forcedLangs } = props;
// hold a copy and only sate state on parent when OK pressed, improves performance // hold a copy and only sate state on parent when OK pressed, improves performance
const [mShownLangs, setMShownLangs] = useState( const [mShownLangs, setMShownLangs] = useState(removeAll(cloneObject(shownLangs), forcedLangs!));
removeAll(cloneObject(shownLangs), forcedLangs!),
);
const [open, setOpen] = useState<boolean>(false); const [open, setOpen] = useState<boolean>(false);
const handleCancel = () => { const handleCancel = () => {

View File

@@ -35,10 +35,7 @@ export default function DesktopSideBar({ navBarItems }: IProps) {
if (location.pathname === path) if (location.pathname === path)
return <SelectedIconComponent sx={{ color: 'primary.main' }} fontSize="large" />; return <SelectedIconComponent sx={{ color: 'primary.main' }} fontSize="large" />;
return ( return (
<IconComponent <IconComponent sx={{ color: theme.palette.mode === 'dark' ? 'grey.A400' : 'grey.600' }} fontSize="large" />
sx={{ color: theme.palette.mode === 'dark' ? 'grey.A400' : 'grey.600' }}
fontSize="large"
/>
); );
}; };
@@ -46,23 +43,17 @@ export default function DesktopSideBar({ navBarItems }: IProps) {
<SideNavBarContainer> <SideNavBarContainer>
{ {
// eslint-disable-next-line react/destructuring-assignment // eslint-disable-next-line react/destructuring-assignment
navBarItems.map( navBarItems.map(({ path, title, IconComponent, SelectedIconComponent }: NavbarItem) => (
({ path, title, IconComponent, SelectedIconComponent }: NavbarItem) => ( <Link to={path} style={{ color: 'inherit', textDecoration: 'none' }} key={path}>
<Link <ListItem disableRipple button key={title}>
to={path} <ListItemIcon sx={{ minWidth: '0' }}>
style={{ color: 'inherit', textDecoration: 'none' }} <Tooltip placement="right" title={title}>
key={path} {iconFor(path, IconComponent, SelectedIconComponent)}
> </Tooltip>
<ListItem disableRipple button key={title}> </ListItemIcon>
<ListItemIcon sx={{ minWidth: '0' }}> </ListItem>
<Tooltip placement="right" title={title}> </Link>
{iconFor(path, IconComponent, SelectedIconComponent)} ))
</Tooltip>
</ListItemIcon>
</ListItem>
</Link>
),
)
} }
</SideNavBarContainer> </SideNavBarContainer>
); );

View File

@@ -44,45 +44,35 @@ export default function MobileBottomBar({ navBarItems }: IProps) {
if (location.pathname === path) if (location.pathname === path)
return <SelectedIconComponent sx={{ color: 'primary.main' }} fontSize="medium" />; return <SelectedIconComponent sx={{ color: 'primary.main' }} fontSize="medium" />;
return ( return (
<IconComponent <IconComponent sx={{ color: theme.palette.mode === 'dark' ? 'grey.A400' : 'grey.600' }} fontSize="medium" />
sx={{ color: theme.palette.mode === 'dark' ? 'grey.A400' : 'grey.600' }}
fontSize="medium"
/>
); );
}; };
return ( return (
<BottomNavContainer> <BottomNavContainer>
{navBarItems.map( {navBarItems.map(({ path, title, IconComponent, SelectedIconComponent }: NavbarItem) => (
({ path, title, IconComponent, SelectedIconComponent }: NavbarItem) => ( <Link to={path} key={path}>
<Link to={path} key={path}> <ListItem disableRipple button sx={{ justifyContent: 'center', padding: '8px' }} key={title}>
<ListItem <Box display="flex" flexDirection="column" alignItems="center">
disableRipple {iconFor(path, IconComponent, SelectedIconComponent)}
button <Box
sx={{ justifyContent: 'center', padding: '8px' }} sx={{
key={title} fontSize: '0.65rem',
> color:
<Box display="flex" flexDirection="column" alignItems="center"> // eslint-disable-next-line no-nested-ternary
{iconFor(path, IconComponent, SelectedIconComponent)} location.pathname === path
<Box ? 'primary.main'
sx={{ : theme.palette.mode === 'dark'
fontSize: '0.65rem', ? 'grey.A400'
color: : 'grey.600',
// eslint-disable-next-line no-nested-ternary }}
location.pathname === path >
? 'primary.main' {title}
: theme.palette.mode === 'dark'
? 'grey.A400'
: 'grey.600',
}}
>
{title}
</Box>
</Box> </Box>
</ListItem> </Box>
</Link> </ListItem>
), </Link>
)} ))}
</BottomNavContainer> </BottomNavContainer>
); );
} }

View File

@@ -164,10 +164,8 @@ export default function HorizontalPager(props: IReaderProps) {
ref={selfRef} ref={selfRef}
sx={{ sx={{
display: 'flex', display: 'flex',
flexDirection: flexDirection: settings.readerType === 'ContinuesHorizontalLTR' ? 'row' : 'row-reverse',
settings.readerType === 'ContinuesHorizontalLTR' ? 'row' : 'row-reverse', justifyContent: settings.readerType === 'ContinuesHorizontalLTR' ? 'flex-start' : 'flex-end',
justifyContent:
settings.readerType === 'ContinuesHorizontalLTR' ? 'flex-start' : 'flex-end',
margin: '0 auto', margin: '0 auto',
width: 'auto', width: 'auto',
height: 'auto', height: 'auto',

View File

@@ -98,13 +98,7 @@ export default function PagedReader(props: IReaderProps) {
height: '100vh', height: '100vh',
}} }}
> >
<Page <Page key={curPage} index={curPage} onImageLoad={() => {}} src={pages[curPage].src} settings={settings} />
key={curPage}
index={curPage}
onImageLoad={() => {}}
src={pages[curPage].src}
settings={settings}
/>
</Box> </Box>
); );
} }

View File

@@ -85,9 +85,7 @@ export default function VerticalPager(props: IReaderProps) {
} }
window.scroll({ window.scroll({
top: top: window.scrollY + window.innerHeight * SCROLL_OFFSET * (direction === 'up' ? -1 : 1),
window.scrollY +
window.innerHeight * SCROLL_OFFSET * (direction === 'up' ? -1 : 1),
behavior: SCROLL_BEHAVIOR, behavior: SCROLL_BEHAVIOR,
}); });
}, },

View File

@@ -58,10 +58,7 @@ export default function SourceGridLayout() {
control={ control={
<Radio <Radio
name={GridLayout.Compact.toString()} name={GridLayout.Compact.toString()}
checked={ checked={SourcegridLayout === GridLayout.Compact || SourcegridLayout === undefined}
SourcegridLayout === GridLayout.Compact ||
SourcegridLayout === undefined
}
onChange={setGridContextOptions} onChange={setGridContextOptions}
/> />
} }

View File

@@ -16,16 +16,7 @@ function filterManga(mangas: IMangaCard[]): IMangaCard[] {
} }
export default function SourceMangaGrid(props: IMangaGridProps) { export default function SourceMangaGrid(props: IMangaGridProps) {
const { const { mangas, isLoading, hasNextPage, lastPageNum, setLastPageNum, message, messageExtra, gridLayout } = props;
mangas,
isLoading,
hasNextPage,
lastPageNum,
setLastPageNum,
message,
messageExtra,
gridLayout,
} = props;
const filteredManga = filterManga(mangas); const filteredManga = filterManga(mangas);
const showFilteredOutMessage = filteredManga.length === 0 && mangas.length > 0; const showFilteredOutMessage = filteredManga.length === 0 && mangas.length > 0;

View File

@@ -72,9 +72,7 @@ export function Options({ sourceFilter, group, updateFilterValue, update }: IFil
/> />
); );
case 'Header': case 'Header':
return ( return <HeaderFilter key={`filters ${e.filter.name}`} name={e.filter.name} />;
<HeaderFilter key={`filters ${e.filter.name}`} name={e.filter.name} />
);
case 'Select': case 'Select':
return ( return (
<SelectFilter <SelectFilter
@@ -90,12 +88,7 @@ export function Options({ sourceFilter, group, updateFilterValue, update }: IFil
/> />
); );
case 'Separator': case 'Separator':
return ( return <SeperatorFilter key={`filters ${e.filter.name}`} name={e.filter.name} />;
<SeperatorFilter
key={`filters ${e.filter.name}`}
name={e.filter.name}
/>
);
case 'Sort': case 'Sort':
return ( return (
<SortFilter <SortFilter

View File

@@ -24,8 +24,7 @@ const CheckBoxFilter: React.FC<Props> = (props: Props) => {
const handleChange = (event: { target: { name: any; checked: any } }) => { const handleChange = (event: { target: { name: any; checked: any } }) => {
setval(event.target.checked); setval(event.target.checked);
const upd = update.filter( const upd = update.filter(
(e: { position: number; group: number | undefined }) => (e: { position: number; group: number | undefined }) => !(position === e.position && group === e.group),
!(position === e.position && group === e.group),
); );
updateFilterValue([...upd, { position, state: event.target.checked.toString(), group }]); updateFilterValue([...upd, { position, state: event.target.checked.toString(), group }]);
}; };

View File

@@ -44,8 +44,7 @@ function hasSelect(
const vall = values.map((e) => e.displayname).indexOf(`${event.target.value}`); const vall = values.map((e) => e.displayname).indexOf(`${event.target.value}`);
setval(vall); setval(vall);
const upd = update.filter( const upd = update.filter(
(e: { position: number; group: number | undefined }) => (e: { position: number; group: number | undefined }) => !(position === e.position && group === e.group),
!(position === e.position && group === e.group),
); );
updateFilterValue([...upd, { position, state: vall.toString(), group }]); updateFilterValue([...upd, { position, state: vall.toString(), group }]);
}; };
@@ -58,12 +57,7 @@ function hasSelect(
return ( return (
<FormControl sx={{ my: 1 }} variant="standard"> <FormControl sx={{ my: 1 }} variant="standard">
<InputLabel>{name}</InputLabel> <InputLabel>{name}</InputLabel>
<Select <Select name={name} value={values[val].displayname} label={name} onChange={handleChange}>
name={name}
value={values[val].displayname}
label={name}
onChange={handleChange}
>
{rett} {rett}
</Select> </Select>
</FormControl> </FormControl>
@@ -88,8 +82,7 @@ function noSelect(
const vall = values.indexOf(`${event.target.value}`); const vall = values.indexOf(`${event.target.value}`);
setval(vall); setval(vall);
const upd = update.filter( const upd = update.filter(
(e: { position: number; group: number | undefined }) => (e: { position: number; group: number | undefined }) => !(position === e.position && group === e.group),
!(position === e.position && group === e.group),
); );
updateFilterValue([...upd, { position, state: vall.toString(), group }]); updateFilterValue([...upd, { position, state: vall.toString(), group }]);
}; };

View File

@@ -42,8 +42,7 @@ const SortFilter: React.FC<Props> = (props: Props) => {
tmp.index = index; tmp.index = index;
setval(tmp); setval(tmp);
const upd = update.filter( const upd = update.filter(
(e: { position: number; group: number | undefined }) => (e: { position: number; group: number | undefined }) => !(position === e.position && group === e.group),
!(position === e.position && group === e.group),
); );
updateFilterValue([...upd, { position, state: JSON.stringify(tmp), group }]); updateFilterValue([...upd, { position, state: JSON.stringify(tmp), group }]);
}; };

View File

@@ -25,8 +25,7 @@ const TextFilter: React.FC<Props> = (props) => {
function doneTyping(e: React.ChangeEvent<HTMLInputElement>) { function doneTyping(e: React.ChangeEvent<HTMLInputElement>) {
const upd = update.filter( const upd = update.filter(
(el: { position: number; group: number | undefined }) => (el: { position: number; group: number | undefined }) => !(position === el.position && group === el.group),
!(position === el.position && group === el.group),
); );
updateFilterValue([...upd, { position, state: e.target.value, group }]); updateFilterValue([...upd, { position, state: e.target.value, group }]);
} }

View File

@@ -26,8 +26,7 @@ const TriStateFilter: React.FC<Props> = (props) => {
const newState = checked === undefined ? 0 : checked ? 1 : 2; const newState = checked === undefined ? 0 : checked ? 1 : 2;
setval(newState); setval(newState);
const upd = update.filter( const upd = update.filter(
(e: { position: number; group: number | undefined }) => (e: { position: number; group: number | undefined }) => !(position === e.position && group === e.group),
!(position === e.position && group === e.group),
); );
updateFilterValue([ updateFilterValue([
...upd, ...upd,

View File

@@ -65,12 +65,7 @@ function ListDialog(props: IListDialogProps) {
<DialogContent dividers> <DialogContent dividers>
<RadioGroup ref={radioGroupRef} value={value} onChange={handleChange}> <RadioGroup ref={radioGroupRef} value={value} onChange={handleChange}>
{options.map((option) => ( {options.map((option) => (
<FormControlLabel <FormControlLabel value={option} key={option} control={<Radio />} label={option} />
value={option}
key={option}
control={<Radio />}
label={option}
/>
))} ))}
</RadioGroup> </RadioGroup>
</DialogContent> </DialogContent>

View File

@@ -64,11 +64,7 @@ function ListDialog(props: IListDialogProps) {
}; };
return ( return (
<Dialog <Dialog sx={{ '& .MuiDialog-paper': { width: '80%', maxHeight: 435 } }} maxWidth="xs" open={open}>
sx={{ '& .MuiDialog-paper': { width: '80%', maxHeight: 435 } }}
maxWidth="xs"
open={open}
>
<DialogTitle>{title}</DialogTitle> <DialogTitle>{title}</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<FormGroup> <FormGroup>
@@ -76,9 +72,7 @@ function ListDialog(props: IListDialogProps) {
<FormControlLabel <FormControlLabel
control={ control={
<Checkbox <Checkbox
checked={selectedValues.some( checked={selectedValues.some((selectedValue) => value === selectedValue)}
(selectedValue) => value === selectedValue,
)}
onChange={(e) => handleChange(e, value)} onChange={(e) => handleChange(e, value)}
color="default" color="default"
/> />

View File

@@ -61,20 +61,14 @@ export default function makeToast(message: string, severity: Severity) {
setTimeout(() => removeToast(container.id), 3500); setTimeout(() => removeToast(container.id), 3500);
} }
export function makeToaster([toasts, setToasts]: [ export function makeToaster([toasts, setToasts]: [React.ReactElement[], (arg0: React.ReactElement[]) => void]): [
React.ReactElement[], React.ReactElement[],
(arg0: React.ReactElement[]) => void, (message: string, severity: Severity) => void,
]): [React.ReactElement[], (message: string, severity: Severity) => void] { ] {
return [ return [
toasts, toasts,
(message: string, severity: Severity) => { (message: string, severity: Severity) => {
setToasts([ setToasts([<Toast key={Math.floor(Math.random() * 1000) + 1} message={message} severity={severity} />]);
<Toast
key={Math.floor(Math.random() * 1000) + 1}
message={message}
severity={severity}
/>,
]);
}, },
]; ];
} }

View File

@@ -97,9 +97,7 @@ const DownloadQueue: React.FC = () => {
> >
<Card <Card
sx={{ sx={{
backgroundColor: snapshot.isDragging backgroundColor: snapshot.isDragging ? 'custom.light' : undefined,
? 'custom.light'
: undefined,
}} }}
> >
<CardActionArea <CardActionArea
@@ -117,18 +115,9 @@ const DownloadQueue: React.FC = () => {
<IconButton sx={{ pointerEvents: 'none' }}> <IconButton sx={{ pointerEvents: 'none' }}>
<DragHandle /> <DragHandle />
</IconButton> </IconButton>
<Stack <Stack sx={{ flex: 1, ml: 1 }} direction="column">
sx={{ flex: 1, ml: 1 }} <Typography variant="h6">{item.manga.title}</Typography>
direction="column" <Typography variant="caption" display="block" gutterBottom>
>
<Typography variant="h6">
{item.manga.title}
</Typography>
<Typography
variant="caption"
display="block"
gutterBottom
>
{item.chapter.name} {item.chapter.name}
</Typography> </Typography>
</Stack> </Stack>

View File

@@ -67,10 +67,7 @@ function groupExtensions(extensions: IExtension[]) {
export default function MangaExtensions() { export default function MangaExtensions() {
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const { setTitle, setAction } = useContext(NavbarContext); const { setTitle, setAction } = useContext(NavbarContext);
const [shownLangs, setShownLangs] = useLocalStorage<string[]>( const [shownLangs, setShownLangs] = useLocalStorage<string[]>('shownExtensionLangs', extensionDefaultLangs());
'shownExtensionLangs',
extensionDefaultLangs(),
);
const [showNsfw] = useLocalStorage<boolean>('showNsfw', true); const [showNsfw] = useLocalStorage<boolean>('showNsfw', true);
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('sm')); const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
@@ -84,20 +81,12 @@ export default function MangaExtensions() {
<IconButton onClick={() => inputRef.current?.click()} size="large"> <IconButton onClick={() => inputRef.current?.click()} size="large">
<AddIcon /> <AddIcon />
</IconButton> </IconButton>
<LangSelect <LangSelect shownLangs={shownLangs} setShownLangs={setShownLangs} allLangs={allLangs} />
shownLangs={shownLangs}
setShownLangs={setShownLangs}
allLangs={allLangs}
/>
</>, </>,
); );
}, [shownLangs]); }, [shownLangs]);
const { const { data: allExtensions, mutate, loading } = useQuery<IExtension[]>('/api/v1/extension/list');
data: allExtensions,
mutate,
loading,
} = useQuery<IExtension[]>('/api/v1/extension/list');
const filteredExtensions = useMemo( const filteredExtensions = useMemo(
() => () =>
@@ -113,11 +102,7 @@ export default function MangaExtensions() {
() => () =>
groupExtensions(filteredExtensions) groupExtensions(filteredExtensions)
.filter((group) => group[EXTENSIONS].length > 0) .filter((group) => group[EXTENSIONS].length > 0)
.filter((group) => .filter((group) => ['installed', 'updates pending', 'all', ...shownLangs].includes(group[LANGUAGE])),
['installed', 'updates pending', 'all', ...shownLangs].includes(
group[LANGUAGE],
),
),
[shownLangs, filteredExtensions], [shownLangs, filteredExtensions],
); );

View File

@@ -60,12 +60,7 @@ export default function Library() {
}; };
if (tabsError != null) { if (tabsError != null) {
return ( return <EmptyView message="Could not load categories" messageExtra={tabsError?.message ?? tabsError} />;
<EmptyView
message="Could not load categories"
messageExtra={tabsError?.message ?? tabsError}
/>
);
} }
if (loading) { if (loading) {

View File

@@ -38,9 +38,7 @@ const Manga: React.FC = () => {
const [refresh, { loading: refreshing }] = useRefreshManga(id); const [refresh, { loading: refreshing }] = useRefreshManga(id);
useSetDefaultBackTo( useSetDefaultBackTo(
manga?.inLibrary === false && manga.sourceId != null manga?.inLibrary === false && manga.sourceId != null ? `/sources/${manga.sourceId}/popular` : '/library',
? `/sources/${manga.sourceId}/popular`
: '/library',
); );
useEffect(() => { useEffect(() => {
@@ -89,13 +87,7 @@ const Manga: React.FC = () => {
<CircularProgress size={16} /> <CircularProgress size={16} />
</IconButton> </IconButton>
)} )}
{manga && ( {manga && <MangaToolbarMenu manga={manga} onRefresh={refresh} refreshing={refreshing} />}
<MangaToolbarMenu
manga={manga}
onRefresh={refresh}
refreshing={refreshing}
/>
)}
</Stack> </Stack>
</NavbarToolbar> </NavbarToolbar>

View File

@@ -75,8 +75,7 @@ export default function Reader() {
const [curPage, setCurPage] = useState<number>(0); const [curPage, setCurPage] = useState<number>(0);
const { setOverride, setTitle } = useContext(NavbarContext); const { setOverride, setTitle } = useContext(NavbarContext);
const { settings: defaultSettings, loading: areDefaultSettingsLoading } = const { settings: defaultSettings, loading: areDefaultSettingsLoading } = useDefaultReaderSettings();
useDefaultReaderSettings();
const [settings, setSettings] = useState(getReaderSettingsFor(manga, defaultSettings)); const [settings, setSettings] = useState(getReaderSettingsFor(manga, defaultSettings));
const [isMangaLoading, setIsMangaLoading] = useState(true); const [isMangaLoading, setIsMangaLoading] = useState(true);
@@ -97,9 +96,7 @@ export default function Reader() {
useEffect(() => { useEffect(() => {
if (!areDefaultSettingsLoading && !isMangaLoading) { if (!areDefaultSettingsLoading && !isMangaLoading) {
checkAndHandleMissingStoredReaderSettings(manga, 'manga', defaultSettings).catch( checkAndHandleMissingStoredReaderSettings(manga, 'manga', defaultSettings).catch(() => {});
() => {},
);
setSettings(getReaderSettingsFor(manga, defaultSettings)); setSettings(getReaderSettingsFor(manga, defaultSettings));
} }
}, [areDefaultSettingsLoading, isMangaLoading]); }, [areDefaultSettingsLoading, isMangaLoading]);

View File

@@ -16,12 +16,7 @@ import React, { useContext, useEffect, useState } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { StringParam, useQueryParam } from 'use-query-params'; import { StringParam, useQueryParam } from 'use-query-params';
import client from 'util/client'; import client from 'util/client';
import { import { langCodeToName, langSortCmp, sourceDefualtLangs, sourceForcedDefaultLangs } from 'util/language';
langCodeToName,
langSortCmp,
sourceDefualtLangs,
sourceForcedDefaultLangs,
} from 'util/language';
import useLocalStorage from 'util/useLocalStorage'; import useLocalStorage from 'util/useLocalStorage';
function sourceToLangList(sources: ISource[]) { function sourceToLangList(sources: ISource[]) {
@@ -43,10 +38,7 @@ const SearchAll: React.FC = () => {
const [triggerUpdate, setTriggerUpdate] = useState<number>(2); const [triggerUpdate, setTriggerUpdate] = useState<number>(2);
const [mangas, setMangas] = useState<any>({}); const [mangas, setMangas] = useState<any>({});
const [shownLangs, setShownLangs] = useLocalStorage<string[]>( const [shownLangs, setShownLangs] = useLocalStorage<string[]>('shownSourceLangs', sourceDefualtLangs());
'shownSourceLangs',
sourceDefualtLangs(),
);
const [showNsfw] = useLocalStorage<boolean>('showNsfw', true); const [showNsfw] = useLocalStorage<boolean>('showNsfw', true);
const [sources, setSources] = useState<ISource[]>([]); const [sources, setSources] = useState<ISource[]>([]);
@@ -210,9 +202,7 @@ const SearchAll: React.FC = () => {
sx={{ p: 3 }} sx={{ p: 3 }}
> >
<Typography variant="h5">{displayName}</Typography> <Typography variant="h5">{displayName}</Typography>
<Typography variant="caption"> <Typography variant="caption">{langCodeToName(lang)}</Typography>
{langCodeToName(lang)}
</Typography>
</CardActionArea> </CardActionArea>
</Card> </Card>
<MangaGrid <MangaGrid

View File

@@ -118,11 +118,7 @@ export default function Settings() {
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Dark Theme" /> <ListItemText primary="Dark Theme" />
<ListItemSecondaryAction> <ListItemSecondaryAction>
<Switch <Switch edge="end" checked={darkTheme} onChange={() => setDarkTheme(!darkTheme)} />
edge="end"
checked={darkTheme}
onChange={() => setDarkTheme(!darkTheme)}
/>
</ListItemSecondaryAction> </ListItemSecondaryAction>
</ListItem> </ListItem>
<ListItemButton> <ListItemButton>
@@ -141,16 +137,9 @@ export default function Settings() {
<ListItemIcon> <ListItemIcon>
<FavoriteIcon /> <FavoriteIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText primary="Show NSFW" secondary="Hide NSFW extensions and sources" />
primary="Show NSFW"
secondary="Hide NSFW extensions and sources"
/>
<ListItemSecondaryAction> <ListItemSecondaryAction>
<Switch <Switch edge="end" checked={showNsfw} onChange={() => setShowNsfw(!showNsfw)} />
edge="end"
checked={showNsfw}
onChange={() => setShowNsfw(!showNsfw)}
/>
</ListItemSecondaryAction> </ListItemSecondaryAction>
</ListItem> </ListItem>
<ListItem> <ListItem>
@@ -163,11 +152,7 @@ export default function Settings() {
but uses it much more internet traffic in turn" but uses it much more internet traffic in turn"
/> />
<ListItemSecondaryAction> <ListItemSecondaryAction>
<Switch <Switch edge="end" checked={useCache} onChange={() => setUseCache(!useCache)} />
edge="end"
checked={useCache}
onChange={() => setUseCache(!useCache)}
/>
</ListItemSecondaryAction> </ListItemSecondaryAction>
</ListItem> </ListItem>
<ListItem> <ListItem>

View File

@@ -9,10 +9,7 @@ import React, { useContext, useEffect } from 'react';
import NavbarContext from 'components/context/NavbarContext'; import NavbarContext from 'components/context/NavbarContext';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import client, { useQuery } from 'util/client'; import client, { useQuery } from 'util/client';
import { import { SwitchPreferenceCompat, CheckBoxPreference } from 'components/sourceConfiguration/TwoStatePreference';
SwitchPreferenceCompat,
CheckBoxPreference,
} from 'components/sourceConfiguration/TwoStatePreference';
import ListPreference from 'components/sourceConfiguration/ListPreference'; import ListPreference from 'components/sourceConfiguration/ListPreference';
import EditTextPreference from 'components/sourceConfiguration/EditTextPreference'; import EditTextPreference from 'components/sourceConfiguration/EditTextPreference';
import MultiSelectListPreference from 'components/sourceConfiguration/MultiSelectListPreference'; import MultiSelectListPreference from 'components/sourceConfiguration/MultiSelectListPreference';

View File

@@ -221,9 +221,7 @@ export default function SourceMangas(props: { popular: boolean }) {
messageExtra = ( messageExtra = (
<> <>
<span>Check out </span> <span>Check out </span>
<a href="https://github.com/Suwayomi/Tachidesk-Server/wiki/Local-Source"> <a href="https://github.com/Suwayomi/Tachidesk-Server/wiki/Local-Source">Local source guide</a>
Local source guide
</a>
</> </>
); );
} }

View File

@@ -9,12 +9,7 @@ import React, { useContext, useEffect } from 'react';
import LangSelect from 'components/navbar/action/LangSelect'; import LangSelect from 'components/navbar/action/LangSelect';
import SourceCard from 'components/SourceCard'; import SourceCard from 'components/SourceCard';
import NavbarContext from 'components/context/NavbarContext'; import NavbarContext from 'components/context/NavbarContext';
import { import { sourceDefualtLangs, sourceForcedDefaultLangs, langCodeToName, langSortCmp } from 'util/language';
sourceDefualtLangs,
sourceForcedDefaultLangs,
langCodeToName,
langSortCmp,
} from 'util/language';
import useLocalStorage from 'util/useLocalStorage'; import useLocalStorage from 'util/useLocalStorage';
import LoadingPlaceholder from 'components/util/LoadingPlaceholder'; import LoadingPlaceholder from 'components/util/LoadingPlaceholder';
import { IconButton } from '@mui/material'; import { IconButton } from '@mui/material';
@@ -50,10 +45,7 @@ function groupByLang(sources: ISource[]) {
export default function Sources() { export default function Sources() {
const { setTitle, setAction } = useContext(NavbarContext); const { setTitle, setAction } = useContext(NavbarContext);
const [shownLangs, setShownLangs] = useLocalStorage<string[]>( const [shownLangs, setShownLangs] = useLocalStorage<string[]>('shownSourceLangs', sourceDefualtLangs());
'shownSourceLangs',
sourceDefualtLangs(),
);
const [showNsfw] = useLocalStorage<boolean>('showNsfw', true); const [showNsfw] = useLocalStorage<boolean>('showNsfw', true);
const { data: sources, loading } = useQuery<ISource[]>('/api/v1/source/list'); const { data: sources, loading } = useQuery<ISource[]>('/api/v1/source/list');

View File

@@ -46,9 +46,7 @@ function getDateString(date: Date) {
return date.toLocaleDateString(); return date.toLocaleDateString();
} }
function groupByDate( function groupByDate(updates: IMangaChapter[]): [string, { item: IMangaChapter; globalIdx: number }[]][] {
updates: IMangaChapter[],
): [string, { item: IMangaChapter; globalIdx: number }[]][] {
if (updates.length === 0) return []; if (updates.length === 0) return [];
const groups = {}; const groups = {};
@@ -64,10 +62,7 @@ function groupByDate(
return Object.keys(groups).map((key) => [key, groups[key]]); return Object.keys(groups).map((key) => [key, groups[key]]);
} }
const baseWebsocketUrl = JSON.parse(window.localStorage.getItem('serverBaseURL')!).replace( const baseWebsocketUrl = JSON.parse(window.localStorage.getItem('serverBaseURL')!).replace('http', 'ws');
'http',
'ws',
);
const initialQueue = { const initialQueue = {
status: 'Stopped', status: 'Stopped',
queue: [], queue: [],
@@ -205,11 +200,7 @@ const Updates: React.FC = () => {
<Typography variant="h5" component="h2"> <Typography variant="h5" component="h2">
{manga.title} {manga.title}
</Typography> </Typography>
<Typography <Typography variant="caption" display="block" gutterBottom>
variant="caption"
display="block"
gutterBottom
>
{chapter.name} {chapter.name}
</Typography> </Typography>
</Box> </Box>

View File

@@ -74,10 +74,7 @@ export default function Backup() {
<> <>
<List sx={{ padding: 0 }}> <List sx={{ padding: 0 }}>
<ListItemLink to={`${baseURL}/api/v1/backup/export/file`} directLink> <ListItemLink to={`${baseURL}/api/v1/backup/export/file`} directLink>
<ListItemText <ListItemText primary="Create Backup" secondary="Backup library as a Tachiyomi backup" />
primary="Create Backup"
secondary="Backup library as a Tachiyomi backup"
/>
</ListItemLink> </ListItemLink>
<ListItem button onClick={() => document.getElementById('backup-file')?.click()}> <ListItem button onClick={() => document.getElementById('backup-file')?.click()}>
<ListItemText <ListItemText

View File

@@ -139,11 +139,7 @@ export default function Categories() {
{(provided) => ( {(provided) => (
<List ref={provided.innerRef}> <List ref={provided.innerRef}>
{categories.map((item, index) => ( {categories.map((item, index) => (
<Draggable <Draggable key={item.id} draggableId={item.id.toString()} index={index}>
key={item.id}
draggableId={item.id.toString()}
index={index}
>
{(provided, snapshot) => ( {(provided, snapshot) => (
<ListItem <ListItem
ContainerProps={{ ref: provided.innerRef } as any} ContainerProps={{ ref: provided.innerRef } as any}

View File

@@ -51,11 +51,7 @@ export default function DefaultReaderSettings() {
); );
} }
checkAndHandleMissingStoredReaderSettings( checkAndHandleMissingStoredReaderSettings({ meta: metadata }, 'server', getDefaultSettings()).catch(() => {});
{ meta: metadata },
'server',
getDefaultSettings(),
).catch(() => {});
return ( return (
<ReaderSettingsOptions <ReaderSettingsOptions

View File

@@ -83,10 +83,7 @@ export function langCodeToName(code: string): string {
let result = `language with code: ${code}`; let result = `language with code: ${code}`;
for (let i = 0; i < ISOLanguages.length; i++) { for (let i = 0; i < ISOLanguages.length; i++) {
if ( if (ISOLanguages[i].code === proccessedCode || ISOLanguages[i].code === code.toLocaleLowerCase()) {
ISOLanguages[i].code === proccessedCode ||
ISOLanguages[i].code === code.toLocaleLowerCase()
) {
result = ISOLanguages[i].nativeName; result = ISOLanguages[i].nativeName;
} }
} }

View File

@@ -17,14 +17,10 @@ const migrations: IMetadataMigration[] = [
}, },
]; ];
const getMetadataKey = (key: string, appPrefix: string = APP_METADATA_KEY_PREFIX) => const getMetadataKey = (key: string, appPrefix: string = APP_METADATA_KEY_PREFIX) => `${appPrefix}${key}`;
`${appPrefix}${key}`;
const doesMetadataKeyExistIn = ( const doesMetadataKeyExistIn = (meta: IMetadata | undefined, key: string, appPrefix?: string): boolean =>
meta: IMetadata | undefined, Object.prototype.hasOwnProperty.call(meta ?? {}, getMetadataKey(key, appPrefix));
key: string,
appPrefix?: string,
): boolean => Object.prototype.hasOwnProperty.call(meta ?? {}, getMetadataKey(key, appPrefix));
const convertValueFromMetadata = <T extends AllowedMetadataValueTypes = AllowedMetadataValueTypes>( const convertValueFromMetadata = <T extends AllowedMetadataValueTypes = AllowedMetadataValueTypes>(
value: string, value: string,
@@ -44,10 +40,7 @@ const convertValueFromMetadata = <T extends AllowedMetadataValueTypes = AllowedM
return value as T; return value as T;
}; };
const getAppMetadataFrom = ( const getAppMetadataFrom = (meta: IMetadata, appPrefix: string = APP_METADATA_KEY_PREFIX): IMetadata => {
meta: IMetadata,
appPrefix: string = APP_METADATA_KEY_PREFIX,
): IMetadata => {
const appMetadata: IMetadata = {}; const appMetadata: IMetadata = {};
Object.entries(meta).forEach(([key, value]) => { Object.entries(meta).forEach(([key, value]) => {
@@ -71,9 +64,7 @@ const applyAppKeyPrefixMigration = (meta: IMetadata, migration: IMetadataMigrati
const oldAppMetadata = getAppMetadataFrom(meta, oldPrefix); const oldAppMetadata = getAppMetadataFrom(meta, oldPrefix);
const newAppMetadata = getAppMetadataFrom(meta, newPrefix); const newAppMetadata = getAppMetadataFrom(meta, newPrefix);
const missingMetadataKeys = Object.keys(oldAppMetadata).filter( const missingMetadataKeys = Object.keys(oldAppMetadata).filter((key) => !Object.keys(newAppMetadata).includes(key));
(key) => !Object.keys(newAppMetadata).includes(key),
);
const isMissingOldMetadata = missingMetadataKeys.length; const isMissingOldMetadata = missingMetadataKeys.length;
if (isMissingOldMetadata) { if (isMissingOldMetadata) {
@@ -134,9 +125,7 @@ const applyMetadataMigrations = (meta?: IMetadata): IMetadata | undefined => {
return migrationToMetadata.pop()![1]; return migrationToMetadata.pop()![1];
}; };
export const getMetadataValueFrom = < export const getMetadataValueFrom = <T extends AllowedMetadataValueTypes = AllowedMetadataValueTypes>(
T extends AllowedMetadataValueTypes = AllowedMetadataValueTypes,
>(
{ meta }: IMetadataHolder, { meta }: IMetadataHolder,
key: AppMetadataKeys, key: AppMetadataKeys,
defaultValue?: T, defaultValue?: T,
@@ -220,22 +209,14 @@ export const requestUpdateMetadata = async (
): Promise<void[]> => ): Promise<void[]> =>
Promise.all( Promise.all(
keysToValues.map(([key, value]) => keysToValues.map(([key, value]) =>
requestUpdateMetadataValue( requestUpdateMetadataValue(endpoint, metadataHolder, key, value, endpointToMutate, wrapWithMetaKey),
endpoint,
metadataHolder,
key,
value,
endpointToMutate,
wrapWithMetaKey,
),
), ),
); );
export const requestUpdateServerMetadata = async ( export const requestUpdateServerMetadata = async (
serverMetadata: IMetadata, serverMetadata: IMetadata,
keysToValues: MetadataKeyValuePair[], keysToValues: MetadataKeyValuePair[],
): Promise<void[]> => ): Promise<void[]> => requestUpdateMetadata('', { meta: serverMetadata }, keysToValues, '/meta', false);
requestUpdateMetadata('', { meta: serverMetadata }, keysToValues, '/meta', false);
export const requestUpdateMangaMetadata = async ( export const requestUpdateMangaMetadata = async (
manga: IMangaCard | IManga, manga: IMangaCard | IManga,

View File

@@ -6,11 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
import { import { getMetadataFrom, requestUpdateMangaMetadata, requestUpdateServerMetadata } from 'util/metadata';
getMetadataFrom,
requestUpdateMangaMetadata,
requestUpdateServerMetadata,
} from 'util/metadata';
import { useQuery } from 'util/client'; import { useQuery } from 'util/client';
export const getDefaultSettings = (forceUndefined: boolean = false) => export const getDefaultSettings = (forceUndefined: boolean = false) =>
@@ -75,9 +71,7 @@ export const checkAndHandleMissingStoredReaderSettings = async (
const settingsToCheck = getReaderSettingsFor({ meta }, getDefaultSettings(true), false); const settingsToCheck = getReaderSettingsFor({ meta }, getDefaultSettings(true), false);
const newSettings = getReaderSettingsFor({ meta }, defaultSettings); const newSettings = getReaderSettingsFor({ meta }, defaultSettings);
const undefinedSettings = Object.entries(settingsToCheck).filter( const undefinedSettings = Object.entries(settingsToCheck).filter((setting) => setting[1] === undefined);
(setting) => setting[1] === undefined,
);
const settingsToUpdate: MetadataKeyValuePair[] = []; const settingsToUpdate: MetadataKeyValuePair[] = [];
undefinedSettings.forEach((setting) => { undefinedSettings.forEach((setting) => {

View File

@@ -9,10 +9,7 @@ import React, { useState, Dispatch, SetStateAction, useReducer, Reducer, useCall
import storage from 'util/localStorage'; import storage from 'util/localStorage';
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
export default function useLocalStorage<T>( export default function useLocalStorage<T>(key: string, defaultValue: T | (() => T)): [T, Dispatch<SetStateAction<T>>] {
key: string,
defaultValue: T | (() => T),
): [T, Dispatch<SetStateAction<T>>] {
const initialState = defaultValue instanceof Function ? defaultValue() : defaultValue; const initialState = defaultValue instanceof Function ? defaultValue() : defaultValue;
const [storedValue, setStoredValue] = useState<T>(storage.getItem(key, initialState)); const [storedValue, setStoredValue] = useState<T>(storage.getItem(key, initialState));
@@ -31,11 +28,7 @@ export default function useLocalStorage<T>(
return [storedValue, setValue]; return [storedValue, setValue];
} }
export function useReducerLocalStorage<S, A>( export function useReducerLocalStorage<S, A>(reducer: Reducer<S, A>, key: string, defaultState: S | (() => S)) {
reducer: Reducer<S, A>,
key: string,
defaultState: S | (() => S),
) {
const [storedValue, setValue] = useLocalStorage(key, defaultState); const [storedValue, setValue] = useLocalStorage(key, defaultState);
return useReducer((state: S, action: A): S => { return useReducer((state: S, action: A): S => {
const newState = reducer(state, action); const newState = reducer(state, action);