diff --git a/webUI/react/package.json b/webUI/react/package.json index 97d2d9c..11d19f8 100644 --- a/webUI/react/package.json +++ b/webUI/react/package.json @@ -14,7 +14,7 @@ "react-lazyload": "^3.2.0", "react-router-dom": "^5.2.0", "react-scripts": "4.0.3", - "react-window": "^1.8.6", + "react-virtuoso": "^1.8.6", "web-vitals": "^0.2.4" }, "scripts": { @@ -40,7 +40,6 @@ "@types/react-dom": "^17.0.2", "@types/react-lazyload": "^3.1.0", "@types/react-router-dom": "^5.1.7", - "@types/react-window": "^1.8.3", "@typescript-eslint/eslint-plugin": "4.23.0", "@typescript-eslint/parser": "4.23.0", "eslint": "^7.26.0", diff --git a/webUI/react/src/components/ChapterCard.tsx b/webUI/react/src/components/ChapterCard.tsx index ce311bd..068d00e 100644 --- a/webUI/react/src/components/ChapterCard.tsx +++ b/webUI/react/src/components/ChapterCard.tsx @@ -7,12 +7,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import React from 'react'; -import { makeStyles } from '@material-ui/core/styles'; +import { makeStyles, useTheme } from '@material-ui/core/styles'; import Card from '@material-ui/core/Card'; import CardContent from '@material-ui/core/CardContent'; -import Button from '@material-ui/core/Button'; +import IconButton from '@material-ui/core/IconButton'; +import MoreVertIcon from '@material-ui/icons/MoreVert'; import Typography from '@material-ui/core/Typography'; import { Link, useHistory } from 'react-router-dom'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; const useStyles = makeStyles((theme) => ({ root: { @@ -47,41 +50,63 @@ interface IProps{ export default function ChapterCard(props: IProps) { const classes = useStyles(); const history = useHistory(); + const theme = useTheme(); const { chapter } = props; const dateStr = chapter.uploadDate && new Date(chapter.uploadDate).toISOString().slice(0, 10); + const [anchorEl, setAnchorEl] = React.useState(null); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + return ( <>
  • -
    -
    - - {chapter.name} - {chapter.chapterNumber > 0 && ` : ${chapter.chapterNumber}`} - - - {chapter.scanlator} - {chapter.scanlator && ' '} - {dateStr} - -
    -
    - + + {chapter.name} + {chapter.chapterNumber > 0 && ` : ${chapter.chapterNumber}`} + + + {chapter.scanlator} + {chapter.scanlator && ' '} + {dateStr} + + + + + + + + {/* Download */} + Bookmark + Mark as Read + Mark previous as Read +
  • diff --git a/webUI/react/src/index.tsx b/webUI/react/src/index.tsx index c3f91a3..b4100d1 100644 --- a/webUI/react/src/index.tsx +++ b/webUI/react/src/index.tsx @@ -10,7 +10,7 @@ import ReactDOM from 'react-dom'; import App from './App'; import './index.css'; // roboto font -import 'fontsource-roboto'; +import '@fontsource/roboto'; ReactDOM.render( diff --git a/webUI/react/src/screens/Manga.tsx b/webUI/react/src/screens/Manga.tsx index c7d997d..032fcd7 100644 --- a/webUI/react/src/screens/Manga.tsx +++ b/webUI/react/src/screens/Manga.tsx @@ -7,9 +7,9 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import React, { useEffect, useState, useContext } from 'react'; -import { makeStyles, Theme } from '@material-ui/core/styles'; +import { makeStyles, Theme, useTheme } from '@material-ui/core/styles'; import { useParams } from 'react-router-dom'; -import CircularProgress from '@material-ui/core/CircularProgress'; +import { Virtuoso } from 'react-virtuoso'; import ChapterCard from '../components/ChapterCard'; import MangaDetails from '../components/MangaDetails'; import NavbarContext from '../context/NavbarContext'; @@ -41,13 +41,26 @@ const useStyles = makeStyles((theme: Theme) => ({ }, })); +const InnerItem = React.memo(({ chapters, index }: any) => { + React.useEffect(() => { + console.log('inner mounting', index); + return () => { + console.log('inner unmounting', index); + }; + }, [index]); + return ( + + ); +}); + export default function Manga() { const classes = useStyles(); + const theme = useTheme(); const { setTitle } = useContext(NavbarContext); useEffect(() => { setTitle('Manga'); }, []); // delegate setting topbar action to MangaDetails - const { id } = useParams<{id: string}>(); + const { id } = useParams<{ id: string }>(); const [manga, setManga] = useState(); const [chapters, setChapters] = useState([]); @@ -67,16 +80,10 @@ export default function Manga() { .then((data) => setChapters(data)); }, []); - const chapterCards = ( - 0} - > -
      - {chapters.map((chapter) => ())} -
    -
    - - ); + const itemContent = (index:any) => { + console.log('providing content', index); + return ; + }; return (
    @@ -85,7 +92,32 @@ export default function Manga() { component={MangaDetails} componentProps={{ manga }} /> - {chapterCards} + + 0} + > + {/*
      + {chapters.map((chapter) => ())} +
    */} + +
    +
    ); } diff --git a/webUI/react/src/screens/Reader.tsx b/webUI/react/src/screens/Reader.tsx index 5a787ba..f618b5c 100644 --- a/webUI/react/src/screens/Reader.tsx +++ b/webUI/react/src/screens/Reader.tsx @@ -50,7 +50,7 @@ export default function Reader() { const [serverAddress] = useLocalStorage('serverBaseURL', ''); - const { chapterIndex, mangaId } = useParams<{chapterIndex: string, mangaId: string}>(); + const { chapterIndex, mangaId } = useParams<{ chapterIndex: string, mangaId: string }>(); const [manga, setManga] = useState({ id: +mangaId, title: '', thumbnailUrl: '' }); const [chapter, setChapter] = useState(initialChapter()); const [curPage, setCurPage] = useState(0); diff --git a/webUI/react/src/screens/SearchSingle.tsx b/webUI/react/src/screens/SearchSingle.tsx index 070056e..483b88e 100644 --- a/webUI/react/src/screens/SearchSingle.tsx +++ b/webUI/react/src/screens/SearchSingle.tsx @@ -27,7 +27,7 @@ export default function SearchSingle() { const { setTitle, setAction } = useContext(NavbarContext); useEffect(() => { setTitle('Search'); setAction(<>); }, []); - const { sourceId } = useParams<{sourceId: string}>(); + const { sourceId } = useParams<{ sourceId: string }>(); const classes = useStyles(); const [error, setError] = useState(false); const [mangas, setMangas] = useState([]); diff --git a/webUI/react/src/screens/SourceMangas.tsx b/webUI/react/src/screens/SourceMangas.tsx index e0f4381..01d8ab1 100644 --- a/webUI/react/src/screens/SourceMangas.tsx +++ b/webUI/react/src/screens/SourceMangas.tsx @@ -15,7 +15,7 @@ export default function SourceMangas(props: { popular: boolean }) { const { setTitle, setAction } = useContext(NavbarContext); useEffect(() => { setTitle('Source'); setAction(<>); }, []); - const { sourceId } = useParams<{sourceId: string}>(); + const { sourceId } = useParams<{ sourceId: string }>(); const [mangas, setMangas] = useState([]); const [hasNextPage, setHasNextPage] = useState(false); const [lastPageNum, setLastPageNum] = useState(1); diff --git a/webUI/react/yarn.lock b/webUI/react/yarn.lock index bfa1bc5..2cb20bc 100644 --- a/webUI/react/yarn.lock +++ b/webUI/react/yarn.lock @@ -1157,7 +1157,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== @@ -1928,13 +1928,6 @@ dependencies: "@types/react" "*" -"@types/react-window@^1.8.3": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.3.tgz#14f74b144b4e3df9421eb31182dc580b7ccc7617" - integrity sha512-Xf+IR2Zyiyh/6z1CM8kv1aQba3S3X/hBXt4tH+T9bDSIGwFhle0GZFZGTSU8nw2cUT3UNbCHDjhxVQVZPtE8cA== - dependencies: - "@types/react" "*" - "@types/react@*", "@types/react@^17.0.2": version "17.0.5" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.5.tgz#3d887570c4489011f75a3fc8f965bf87d09a1bea" @@ -2118,6 +2111,18 @@ "@typescript-eslint/types" "4.23.0" eslint-visitor-keys "^2.0.0" +"@virtuoso.dev/react-urx@^0.2.5": + version "0.2.6" + resolved "https://registry.yarnpkg.com/@virtuoso.dev/react-urx/-/react-urx-0.2.6.tgz#e1d8bc717723b2fc23d80ea4e07703dbc276448b" + integrity sha512-+PLQ2iWmSH/rW7WGPEf+Kkql+xygHFL43Jij5aREde/O9mE0OFFGqeetA2a6lry3LDVWzupPntvvWhdaYw0TyA== + dependencies: + "@virtuoso.dev/urx" "^0.2.6" + +"@virtuoso.dev/urx@^0.2.5", "@virtuoso.dev/urx@^0.2.6": + version "0.2.6" + resolved "https://registry.yarnpkg.com/@virtuoso.dev/urx/-/urx-0.2.6.tgz#0028c49e52037e673993900d32abea83262fbd53" + integrity sha512-EKJ0WvJgWaXIz6zKbh9Q63Bcq//p8OHXHbdz4Fy+ruhjJCyI8ADE8E5gwSqBoUchaiYlgwKrT+sX4L2h/H+hMg== + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -3668,7 +3673,7 @@ core-js@^2.4.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-js@^3.6.5: +core-js@^3.5.0, core-js@^3.6.5: version "3.12.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.12.1.tgz#6b5af4ff55616c08a44d386f1f510917ff204112" integrity sha512-Ne9DKPHTObRuB09Dru5AjwKjY4cJHVGu+y5f7coGn1E9Grkc3p2iBwE9AI/nJzsE29mQF7oq+mhYYRqOMFN1Bw== @@ -7370,7 +7375,7 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -"memoize-one@>=3.1.1 <6", memoize-one@^5.1.1: +memoize-one@^5.1.1: version "5.2.1" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== @@ -9093,7 +9098,7 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= -promise@^8.1.0: +promise@^8.0.3, promise@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/promise/-/promise-8.1.0.tgz#697c25c3dfe7435dd79fcd58c38a135888eaf05e" integrity sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q== @@ -9285,6 +9290,18 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +react-app-polyfill@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz#890f8d7f2842ce6073f030b117de9130a5f385f0" + integrity sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g== + dependencies: + core-js "^3.5.0" + object-assign "^4.1.1" + promise "^8.0.3" + raf "^3.4.1" + regenerator-runtime "^0.13.3" + whatwg-fetch "^3.0.0" + react-app-polyfill@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz#a0bea50f078b8a082970a9d853dc34b6dcc6a3cf" @@ -9491,13 +9508,15 @@ react-transition-group@^4.4.0: loose-envify "^1.4.0" prop-types "^15.6.2" -react-window@^1.8.6: +react-virtuoso@^1.8.6: version "1.8.6" - resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.6.tgz#d011950ac643a994118632665aad0c6382e2a112" - integrity sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg== + resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-1.8.6.tgz#dc7d79ee9e309c13700296ff65b04f6ebecdcbaa" + integrity sha512-WFSI4YzdyAFrr3CuZnQ8cmubGMJjgmgyuhx/OpWLls1uK9O43s+6DMr9oBXHAgvCDjS3Nd3vkIJAhsJBJzS1nQ== dependencies: - "@babel/runtime" "^7.0.0" - memoize-one ">=3.1.1 <6" + "@virtuoso.dev/react-urx" "^0.2.5" + "@virtuoso.dev/urx" "^0.2.5" + react-app-polyfill "^1.0.6" + resize-observer-polyfill "^1.5.1" react@^17.0.2: version "17.0.2" @@ -9612,7 +9631,7 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: +regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: version "0.13.7" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== @@ -9767,6 +9786,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +resize-observer-polyfill@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -11564,7 +11588,7 @@ whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" -whatwg-fetch@^3.4.1: +whatwg-fetch@^3.0.0, whatwg-fetch@^3.4.1: version "3.6.2" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==