diff --git a/src/App.tsx b/src/App.tsx index 0ccf3529..c833a21b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,194 +5,124 @@ * 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/. */ -import React from 'react'; -import { - BrowserRouter as Router, - Switch, - Route, - Redirect, -} from 'react-router-dom'; -import { QueryParamProvider } from 'use-query-params'; import { Container } from '@mui/material'; import CssBaseline from '@mui/material/CssBaseline'; -import { - createTheme, - ThemeProvider, - Theme, - StyledEngineProvider, -} from '@mui/material/styles'; -import { SWRConfig } from 'swr'; -import { fetcher } from 'util/client'; +import AppContext from 'components/context/AppContext'; import DefaultNavBar from 'components/navbar/DefaultNavBar'; -import DarkTheme from 'components/context/DarkTheme'; -import useLocalStorage from 'util/useLocalStorage'; +import React from 'react'; +import { + Redirect, Route, Switch, +} from 'react-router-dom'; +import Browse from 'screens/Browse'; +import DownloadQueue from 'screens/DownloadQueue'; +import Extensions from 'screens/Extensions'; +import Library from 'screens/Library'; +import Manga from 'screens/Manga'; +import Reader from 'screens/Reader'; +import SearchAll from 'screens/SearchAll'; import Settings from 'screens/Settings'; import About from 'screens/settings/About'; -import Categories from 'screens/settings/Categories'; import Backup from 'screens/settings/Backup'; -import Library from 'screens/Library'; +import Categories from 'screens/settings/Categories'; import SourceConfigure from 'screens/SourceConfigure'; -import Manga from 'screens/Manga'; import SourceMangas from 'screens/SourceMangas'; -import Reader from 'screens/Reader'; -import Updates from 'screens/Updates'; -import DownloadQueue from 'screens/DownloadQueue'; -import Browse from 'screens/Browse'; import Sources from 'screens/Sources'; -import Extensions from 'screens/Extensions'; -import NavBarContextProvider from 'components/navbar/NavBarContextProvider'; -import LibraryOptionsContextProvider from 'components/library/LibraryOptionsProvider'; -import SearchAll from 'screens/SearchAll'; +import Updates from 'screens/Updates'; -declare module '@mui/styles/defaultTheme' { - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface DefaultTheme extends Theme {} -} +const App: React.FC = () => ( + + + + + + {/* General Routes */} + ( + + )} + /> + + + + + + + + + + + + -export default function App() { - const [darkTheme, setDarkTheme] = useLocalStorage( - 'darkTheme', - true, - ); + {/* Manga Routes */} - const darkThemeContext = { - darkTheme, - setDarkTheme, - }; - - const theme = React.useMemo( - () => createTheme({ - palette: { - mode: darkTheme ? 'dark' : 'light', - }, - components: { - MuiCssBaseline: { - styleOverrides: ` - *::-webkit-scrollbar { - width: 10px; - background: ${darkTheme ? '#222' : '#e1e1e1'}; + + + + + + + + + + + + + + + + + <>> + + + + + + + + + + + + + + + + + + + + + + + ( + + )} + /> + + +); - return ( - - - - - - - - - - - - {/* General Routes */} - ( - - )} - /> - - - - - - - - - - - - - - - - {/* Manga Routes */} - - - - - - - - - - - - - - - - - - <>> - - - - - - - - - - - - - - - - - - - - - - - ( - - )} - /> - - - - - - - - - ); -} +export default App; diff --git a/src/components/MangaCard.tsx b/src/components/MangaCard.tsx index 62a77d19..63296a64 100644 --- a/src/components/MangaCard.tsx +++ b/src/components/MangaCard.tsx @@ -37,16 +37,11 @@ const MangaTitle = styled(Typography)({ position: 'absolute', bottom: 0, padding: '0.5em', - color: 'white', fontSize: '1.05rem', - textShadow: '0px 0px 3px #000000', }); const BadgeContainer = styled('div')({ display: 'flex', - position: 'absolute', - top: 5, - left: 5, height: 'fit-content', borderRadius: '5px', overflow: 'hidden', @@ -94,10 +89,9 @@ const MangaCard = React.forwardRef((props: IProps, ref) const mangaLinkTo = { pathname: `/manga/${id}/`, state: { backLink: BACK } }; if (gridLayout !== 2) { - const colomns = Math.round(dimensions / ItemWidth); + const cols = Math.ceil(dimensions / ItemWidth); return ( - // @ts-ignore gridsize type isnt allowed to be a decimal but it works fine - + ((props: IProps, ref) > ((props: IProps, ref) }} > - + {inLibraryIndicator && inLibrary && ( ((props: IProps, ref) {(gridLayout === 1) ? ( <>> ) : ( - + {truncateText(title, 61)} )} @@ -183,6 +188,7 @@ const MangaCard = React.forwardRef((props: IProps, ref) {truncateText(title, 61)} @@ -193,83 +199,82 @@ const MangaCard = React.forwardRef((props: IProps, ref) ); } + return ( - - - + + - - - - {truncateText(title, 61)} - - - - {inLibrary && ( - - In library - - )} - { showUnreadBadge && unread! > 0 && ( - - {unread} - - )} - { showDownloadBadge && downloadCount! > 0 && ( - + - {downloadCount} + > + + {truncateText(title, 61)} - )} - - - + + + {inLibraryIndicator && inLibrary && ( + + In library + + )} + { showUnreadBadge && unread! > 0 && ( + + {unread} + + )} + { showDownloadBadge && downloadCount! > 0 && ( + + {downloadCount} + + )} + + + + ); }); diff --git a/src/components/SourceCard.tsx b/src/components/SourceCard.tsx index 628b442e..45de4928 100644 --- a/src/components/SourceCard.tsx +++ b/src/components/SourceCard.tsx @@ -5,16 +5,17 @@ * 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/. */ -import React from 'react'; +import { CardActionArea } from '@mui/material'; +import Avatar from '@mui/material/Avatar'; +import Button from '@mui/material/Button'; import Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; -import { useHistory } from 'react-router-dom'; -import Button from '@mui/material/Button'; -import Avatar from '@mui/material/Avatar'; import Typography from '@mui/material/Typography'; -import useLocalStorage from 'util/useLocalStorage'; -import { langCodeToName } from 'util/language'; import { Box, styled } from '@mui/system'; +import React from 'react'; +import { Link, useHistory } from 'react-router-dom'; +import { langCodeToName } from 'util/language'; +import useLocalStorage from 'util/useLocalStorage'; const MobileWidthButtons = styled('div')(({ theme }) => ({ display: 'flex', @@ -38,7 +39,7 @@ interface IProps { source: ISource } -export default function SourceCard(props: IProps) { +const SourceCard: React.FC = (props: IProps) => { const { source: { id, name, lang, iconUrl, supportsLatest, isNsfw, @@ -61,82 +62,83 @@ export default function SourceCard(props: IProps) { redirectTo(e, `/sources/${id}/popular/`)} > - + - - - - - {name} - - {id !== '0' && ( - - {langCodeToName(lang)} - {isNsfw && ( - - {' 18+'} - - )} + + + + + {name} - )} + {id !== '0' && ( + + {langCodeToName(lang)} + {isNsfw && ( + + {' 18+'} + + )} + + )} + - - <> - - {supportsLatest && ( + <> + + {supportsLatest && ( + redirectTo(e, `/sources/${id}/latest/`)} + > + Latest + + )} + + + {supportsLatest && ( + + Latest + + )} redirectTo(e, `/sources/${id}/latest/`)} > - Latest + Browse - )} - - - {supportsLatest && ( - redirectTo(e, `/sources/${id}/latest/`)} - > - Latest - - )} - redirectTo(e, `/sources/${id}/popular/`)} - > - Browse - - - > - + + > + + ); -} +}; + +export default SourceCard; diff --git a/src/components/context/AppContext.tsx b/src/components/context/AppContext.tsx new file mode 100644 index 00000000..da9184c6 --- /dev/null +++ b/src/components/context/AppContext.tsx @@ -0,0 +1,66 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * 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/. + */ + +import { + StyledEngineProvider, ThemeProvider, +} from '@mui/material/styles'; +import LibraryOptionsContextProvider from 'components/library/LibraryOptionsProvider'; +import NavBarContextProvider from 'components/navbar/NavBarContextProvider'; +import React, { useMemo } from 'react'; +import { + BrowserRouter as Router, Route, +} from 'react-router-dom'; +import { SWRConfig } from 'swr'; +import createTheme from 'theme'; +import { QueryParamProvider } from 'use-query-params'; +import { fetcher } from 'util/client'; +import useLocalStorage from 'util/useLocalStorage'; +import DarkTheme from './DarkTheme'; + +interface Props { + children: React.ReactNode +} + +const AppContext: React.FC = ({ children }) => { + const [darkTheme, setDarkTheme] = useLocalStorage( + 'darkTheme', + true, + ); + + const darkThemeContext = useMemo(() => ({ + darkTheme, + setDarkTheme, + }), [darkTheme]); + + const theme = useMemo( + () => createTheme(darkTheme), + [darkTheme], + ); + + return ( + + + + + + + + + {children} + + + + + + + + + ); +}; + +export default AppContext; diff --git a/src/components/manga/ChapterCard.tsx b/src/components/manga/ChapterCard.tsx index f4910ad7..f75c5712 100644 --- a/src/components/manga/ChapterCard.tsx +++ b/src/components/manga/ChapterCard.tsx @@ -16,8 +16,7 @@ import Download from '@mui/icons-material/Download'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import RemoveDone from '@mui/icons-material/RemoveDone'; import { - LinearProgress, - Checkbox, ListItemIcon, ListItemText, Stack, + CardActionArea, Checkbox, ListItemIcon, ListItemText, Stack, } from '@mui/material'; import Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; @@ -26,6 +25,7 @@ import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; import { useTheme } from '@mui/material/styles'; import Typography from '@mui/material/Typography'; +import DownloadStateIndicator from 'components/molecules/DownloadStateIndicator'; import React from 'react'; import { Link } from 'react-router-dom'; import client from 'util/client'; @@ -107,21 +107,12 @@ const ChapterCard: React.FC = (props: IProps) => { sx={{ position: 'relative', margin: 1, - ':hover': { - backgroundColor: 'action.hover', - transition: 'background-color 100ms cubic-bezier(0.4, 0, 0.2, 1) 0ms', - cursor: 'pointer', - }, - ':active': { - backgroundColor: 'action.selected', - transition: 'background-color 100ms cubic-bezier(0.4, 0, 0.2, 1) 0ms', - }, }} > - = (props: IProps) => { {dateStr} {isDownloaded && ' • Downloaded'} - {dc && ` • Downloading (${(dc.progress * 100).toFixed(2)}%)`} + {dc && } + {selected === null ? ( @@ -160,17 +152,7 @@ const ChapterCard: React.FC = (props: IProps) => { )} - - {dc != null && ( - - )} + { return ( <> setOpen(true)}> - - - + = ({ download }) => ( + + {download.progress !== 0 && ( + + )} + + + {download.progress !== 0 && `${Math.round(download.progress * 100)}%`} + {download.progress === 0 && download.state} + + + +); + +export default DownloadStateIndicator; diff --git a/src/components/navbar/DefaultNavBar.tsx b/src/components/navbar/DefaultNavBar.tsx index 4b74c440..1e1f8f59 100644 --- a/src/components/navbar/DefaultNavBar.tsx +++ b/src/components/navbar/DefaultNavBar.tsx @@ -25,7 +25,6 @@ import SettingsIcon from '@mui/icons-material/Settings'; import ArrowBack from '@mui/icons-material/ArrowBack'; import { Link, useHistory } from 'react-router-dom'; import NavBarContext from 'components/context/NavbarContext'; -import DarkTheme from 'components/context/DarkTheme'; import ExtensionOutlinedIcon from 'components/util/CustomExtensionOutlinedIcon'; import { Box } from '@mui/system'; import { createPortal } from 'react-dom'; @@ -82,7 +81,6 @@ const navbarItems: Array = [ export default function DefaultNavBar() { const { title, action, override } = useContext(NavBarContext); const backTo = useBackTo(); - const { darkTheme } = useContext(DarkTheme); const theme = useTheme(); const history = useHistory(); @@ -109,7 +107,7 @@ export default function DefaultNavBar() { return ( - + {!isMainRoute && ( ({ backgroundColor: theme.palette.background.default, '& header': { - backgroundColor: - theme.palette.mode === 'dark' ? theme.palette.grey[800] : theme.palette.grey[100], + backgroundColor: theme.palette.action.hover, display: 'flex', alignItems: 'center', minHeight: '64px', @@ -63,12 +62,6 @@ const Root = styled('div')(({ theme }) => ({ flexGrow: 1, }, }, - '& hr': { - margin: '0 16px', - height: '1px', - border: '0', - backgroundColor: theme.palette.mode === 'dark' ? theme.palette.grey[800] : theme.palette.grey[100], - }, })); const Navigation = styled('div')({ @@ -106,9 +99,9 @@ const OpenDrawerButton = styled(IconButton)(({ theme }) => ({ height: '40px', width: '40px', borderRadius: 5, - backgroundColor: theme.palette.mode === 'dark' ? 'black' : 'white', + backgroundColor: theme.palette.custom.main, '&:hover': { - backgroundColor: theme.palette.mode === 'dark' ? theme.palette.grey[900] : theme.palette.grey[100], + backgroundColor: theme.palette.custom.light, }, })); @@ -313,7 +306,7 @@ export default function ReaderNavBar(props: IProps) { - + {`Currently on page ${curPage + 1} of ${chapter.pageCount}`} @@ -357,7 +350,6 @@ export default function ReaderNavBar(props: IProps) { ({ height: '100vh', width: theme.spacing(8), - backgroundColor: theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900], + backgroundColor: theme.palette.custom, position: 'fixed', top: 0, left: 0, diff --git a/src/components/navbar/navigation/MobileBottomBar.tsx b/src/components/navbar/navigation/MobileBottomBar.tsx index 212a7986..66125939 100644 --- a/src/components/navbar/navigation/MobileBottomBar.tsx +++ b/src/components/navbar/navigation/MobileBottomBar.tsx @@ -16,7 +16,7 @@ const BottomNavContainer = styled('div')(({ theme }) => ({ left: 0, height: theme.spacing(7), width: '100vw', - backgroundColor: theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900], + backgroundColor: theme.palette.custom.light, position: 'fixed', display: 'flex', flexDirection: 'row', diff --git a/src/screens/DownloadQueue.tsx b/src/screens/DownloadQueue.tsx index e6818977..c5b8ef28 100644 --- a/src/screens/DownloadQueue.tsx +++ b/src/screens/DownloadQueue.tsx @@ -7,51 +7,39 @@ * 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/. */ -import NavbarContext from 'components/context/NavbarContext'; -import React, { useContext, useEffect } from 'react'; -import PlayArrowIcon from '@mui/icons-material/PlayArrow'; -import PauseIcon from '@mui/icons-material/Pause'; -import IconButton from '@mui/material/IconButton'; import DeleteIcon from '@mui/icons-material/Delete'; -import client from 'util/client'; +import DragHandle from '@mui/icons-material/DragHandle'; +import PauseIcon from '@mui/icons-material/Pause'; +import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import { - DragDropContext, Draggable, DraggingStyle, Droppable, DropResult, NotDraggingStyle, -} from 'react-beautiful-dnd'; -import { useTheme, Palette } from '@mui/material/styles'; -import List from '@mui/material/List'; -import DragHandleIcon from '@mui/icons-material/DragHandle'; -import ListItem from '@mui/material/ListItem'; -import { ListItemIcon } from '@mui/material'; + Card, CardActionArea, Stack, +} from '@mui/material'; +import IconButton from '@mui/material/IconButton'; +import NavbarContext from 'components/context/NavbarContext'; import EmptyView from 'components/util/EmptyView'; +import React, { useContext, useEffect } from 'react'; +import { + DragDropContext, Draggable, Droppable, DropResult, +} from 'react-beautiful-dnd'; +import client from 'util/client'; -import { Box } from '@mui/system'; import Typography from '@mui/material/Typography'; -import { useHistory } from 'react-router-dom'; +import { Box } from '@mui/system'; import useSubscription from 'components/library/useSubscription'; - -const getItemStyle = (isDragging: boolean, - draggableStyle: DraggingStyle | NotDraggingStyle | undefined, palette: Palette) => ({ - // styles we need to apply on draggables - ...draggableStyle, - - ...(isDragging && { - background: palette.mode === 'dark' ? '#424242' : 'rgb(235,235,235)', - }), -}); +import DownloadStateIndicator from 'components/molecules/DownloadStateIndicator'; +import { NavbarToolbar } from 'components/navbar/DefaultNavBar'; +import { Link } from 'react-router-dom'; +import { BACK } from 'util/useBackTo'; const initialQueue = { status: 'Stopped', queue: [], } as IQueue; -export default function DownloadQueue() { +const DownloadQueue: React.FC = () => { const { data: queueState } = useSubscription('/api/v1/downloads'); const { queue, status } = queueState ?? initialQueue; - const history = useHistory(); - - const theme = useTheme(); - const { setTitle, setAction } = useContext(NavbarContext); const toggleQueueStatus = () => { @@ -64,22 +52,8 @@ export default function DownloadQueue() { useEffect(() => { setTitle('Download Queue'); - - setAction(() => { - if (status === 'Stopped') { - return ( - - - - ); - } - return ( - - - - ); - }); - }, [status]); + setAction(null); + }, []); // eslint-disable-next-line @typescript-eslint/no-unused-vars const onDragEnd = (result: DropResult) => { @@ -89,27 +63,29 @@ export default function DownloadQueue() { return ; } - const callDeleteServer = (chapter: IChapter) => { - // remove from download queue - client.delete(`/api/v1/download/${chapter.mangaId}/chapter/${chapter.index}`); - - // delete partial download, should be handle server side? - // bug: The folder and the last image downloaded are not deleted - client.delete(`/api/v1/manga/${chapter.mangaId}/chapter/${chapter.index}`); - }; - - const deleteChapterQueue = (chapter: IChapter) => { + const handleDelete = (chapter: IChapter) => { // required to stop before deleting otherwise the download kept going. Server issue? client.get('/api/v1/downloads/stop') - .then(() => callDeleteServer(chapter)); + .then(() => Promise.all([ + // remove from download queue + client.delete(`/api/v1/download/${chapter.mangaId}/chapter/${chapter.index}`), + // delete partial download, should be handle server side? + // bug: The folder and the last image downloaded are not deleted + client.delete(`/api/v1/manga/${chapter.mangaId}/chapter/${chapter.index}`), + ])); }; return ( <> + + + {status === 'Stopped' ? : } + + {(provided) => ( - + {queue.map((item, index) => ( {(provided, snapshot) => ( - history.push(`/manga/${item.chapter.mangaId}`)} + - - - - - - - {item.manga.title} - - - {`${item.chapter.name} ` - + `(${(item.progress * 100).toFixed(2)}%)` - + ` => state: ${item.state}`} - - - - { - // deleteCategory(index); - // prevent parent tags from getting the event - e.stopPropagation(); - - // delete chapter from download queue - deleteChapterQueue(item.chapter); + - - - + + + + + + + {item.manga.title} + + + {item.chapter.name} + + + + { + e.preventDefault(); + e.stopPropagation(); + handleDelete(item.chapter); + }} + size="large" + > + + + + + )} - ))} {provided.placeholder} - + )} > ); -} +}; + +export default DownloadQueue; diff --git a/src/screens/Extensions.tsx b/src/screens/Extensions.tsx index eb043247..163e147c 100644 --- a/src/screens/Extensions.tsx +++ b/src/screens/Extensions.tsx @@ -185,7 +185,6 @@ export default function MangaExtensions() { paddingLeft: 25, paddingBottom: '0.83em', paddingTop: '0.83em', - backgroundColor: 'rgb(18, 18, 18)', fontSize: '2em', fontWeight: 'bold', }} diff --git a/src/screens/SearchAll.tsx b/src/screens/SearchAll.tsx index d6a6ff76..5bc3780c 100644 --- a/src/screens/SearchAll.tsx +++ b/src/screens/SearchAll.tsx @@ -6,20 +6,20 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Card } from '@mui/material'; -import { useHistory } from 'react-router-dom'; +import { Card, CardActionArea, Typography } from '@mui/material'; import NavbarContext from 'components/context/NavbarContext'; import MangaGrid from 'components/MangaGrid'; import LangSelect from 'components/navbar/action/LangSelect'; import AppbarSearch from 'components/util/AppbarSearch'; +import PQueue from 'p-queue/dist/index'; import React, { useContext, useEffect, useState } from 'react'; -import { useQueryParam, StringParam } from 'use-query-params'; +import { Link } from 'react-router-dom'; +import { StringParam, useQueryParam } from 'use-query-params'; import client from 'util/client'; import { langCodeToName, langSortCmp, sourceDefualtLangs, sourceForcedDefaultLangs, } from 'util/language'; import useLocalStorage from 'util/useLocalStorage'; -import PQueue from 'p-queue/dist/index'; function sourceToLangList(sources: ISource[]) { const result: string[] = []; @@ -32,7 +32,7 @@ function sourceToLangList(sources: ISource[]) { return result; } -export default function SearchAll() { +const SearchAll: React.FC = () => { const [query] = useQueryParam('query', StringParam); const { setTitle, setAction } = useContext(NavbarContext); const [triggerUpdate, setTriggerUpdate] = useState(2); @@ -150,14 +150,6 @@ export default function SearchAll() { ); }, [shownLangs, sources]); - const history = useHistory(); - - const redirectTo = (e: any, to: string) => { - history.push(to); - - // prevent parent tags from getting the event - e.stopPropagation(); - }; if (query) { return ( <> @@ -177,31 +169,19 @@ export default function SearchAll() { }).map(({ lang, id, displayName }) => ( ( <> - redirectTo(e, `/sources/${id}/popular/?R&query=${query}`)} - > - + - {displayName} - - - {langCodeToName(lang)} - + + {displayName} + + + {langCodeToName(lang)} + + >); -} +}; + +export default SearchAll; diff --git a/src/screens/Updates.tsx b/src/screens/Updates.tsx index 71814087..06d9dd31 100644 --- a/src/screens/Updates.tsx +++ b/src/screens/Updates.tsx @@ -5,22 +5,24 @@ * 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/. */ -import React, { - useContext, useEffect, useState, useRef, -} from 'react'; -import { useHistory } from 'react-router-dom'; +import DownloadIcon from '@mui/icons-material/Download'; +import { CardActionArea } from '@mui/material'; +import Avatar from '@mui/material/Avatar'; import Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; import IconButton from '@mui/material/IconButton'; -import DownloadIcon from '@mui/icons-material/Download'; -import Avatar from '@mui/material/Avatar'; import Typography from '@mui/material/Typography'; +import { Box } from '@mui/system'; import NavbarContext from 'components/context/NavbarContext'; -import client from 'util/client'; -import useLocalStorage from 'util/useLocalStorage'; +import DownloadStateIndicator from 'components/molecules/DownloadStateIndicator'; import EmptyView from 'components/util/EmptyView'; import LoadingPlaceholder from 'components/util/LoadingPlaceholder'; -import { Box } from '@mui/system'; +import React, { + useContext, useEffect, useRef, useState, +} from 'react'; +import { Link, useHistory } from 'react-router-dom'; +import client from 'util/client'; +import useLocalStorage from 'util/useLocalStorage'; function epochToDate(epoch: number) { const date = new Date(0); // The 0 there is the key, which sets the date to the epoch @@ -67,7 +69,7 @@ const initialQueue = { queue: [], } as IQueue; -export default function Updates() { +const Updates: React.FC = () => { const history = useHistory(); const { setTitle, setAction } = useContext(NavbarContext); @@ -135,17 +137,9 @@ export default function Updates() { if (!fetched) { return ; } if (fetched && updateEntries.length === 0) { return ; } - const downloadStatusStringFor = (chapter: IChapter) => { - let rtn = ''; - if (chapter.downloaded) { - rtn = ' • Downloaded'; - } - queue.forEach((q) => { - if (chapter.index === q.chapterIndex && chapter.mangaId === q.mangaId) { - rtn = ` • Downloading (${(q.progress * 100).toFixed(2)}%)`; - } - }); - return rtn; + const downloadForChapter = (chapter: IChapter) => { + const { index, mangaId } = chapter; + return queue.find((q) => index === q.chapterIndex && mangaId === q.mangaId); }; const downloadChapter = (chapter: IChapter) => { @@ -166,70 +160,69 @@ export default function Updates() { > {dateGroup[0]} - {dateGroup[1].map(({ item: { chapter, manga }, globalIdx }) => ( - history.push({ pathname: `/manga/${chapter.mangaId}/chapter/${chapter.index}`, state: history.location.state })} - > - { + const download = downloadForChapter(chapter); + return ( + - - + - - - {manga.title} - - - {chapter.name} - {downloadStatusStringFor(chapter)} - - - - {downloadStatusStringFor(chapter) === '' - && ( + > + + + + + {manga.title} + + + {chapter.name} + + + + {download && } + {download == null && !chapter.downloaded && ( { - downloadChapter(chapter); - // prevent parent tags from getting the event e.stopPropagation(); + e.preventDefault(); + downloadChapter(chapter); }} size="large" > )} - - - ))} + + + + ); + })} ))} > ); -} +}; + +export default Updates; diff --git a/src/theme.ts b/src/theme.ts new file mode 100644 index 00000000..b7730556 --- /dev/null +++ b/src/theme.ts @@ -0,0 +1,56 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * 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/. + */ + +import { Theme, createTheme as createMuiTheme } from '@mui/material/styles'; + +declare module '@mui/styles/defaultTheme' { + interface DefaultTheme extends Theme {} +} + +declare module '@mui/material/styles' { + interface PaletteOptions { + custom?: PaletteOptions['primary']; + } + +} + +const createTheme = (dark?: boolean) => { + const baseTheme = createMuiTheme({ + palette: { + mode: dark ? 'dark' : 'light', + }, + }); + + const tachideskTheme = createMuiTheme({ + palette: { + custom: { + main: dark ? baseTheme.palette.common.black : baseTheme.palette.common.white, + light: dark ? baseTheme.palette.grey[900] : baseTheme.palette.grey[100], + }, + }, + components: { + MuiCssBaseline: { + styleOverrides: ` + *::-webkit-scrollbar { + width: 10px; + background: ${dark ? '#222' : '#e1e1e1'}; + } + + *::-webkit-scrollbar-thumb { + background: ${dark ? '#111' : '#aaa'}; + border-radius: 5px; + } + `, + }, + }, + }, baseTheme); + + return tachideskTheme; +}; + +export default createTheme;
- {langCodeToName(lang)} -