diff --git a/package.json b/package.json index 095d3e7..01c72bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "scripts": { - "dev": "SNOWPACK_PUBLIC_API_URL=http://localhost:5000 SNOWPACK_PUBLIC_BASE_URL=http://localhost:8080 snowpack dev", + "dev": "SNOWPACK_PUBLIC_API_URL=https://publitebackend.dmitriy.icu SNOWPACK_PUBLIC_BASE_URL=http://localhost:8080 snowpack dev", "build": "snowpack build", "test": "echo \"Error: no test specified\" && exit 1" }, diff --git a/src/App/App.module.css b/src/App/App.module.css index ed0c801..73c2411 100644 --- a/src/App/App.module.css +++ b/src/App/App.module.css @@ -3,3 +3,15 @@ width: 100vw; overflow: hidden; } + +.loadingIndicator { + position: fixed; + top: 0; + left: 0; + height: 100vh; + width: 100vw; + background-color: white; + display: flex; + align-items: center; + justify-content: center; +} diff --git a/src/App/index.tsx b/src/App/index.tsx index a333545..cb24e71 100644 --- a/src/App/index.tsx +++ b/src/App/index.tsx @@ -1,23 +1,42 @@ -import React from "react"; +import React, { useState } from "react"; import { Route, Switch } from "wouter"; import { BookListContextProvider } from "~/context"; import { Bookshelf } from "~/pages/Bookshelf"; import { BookView } from "~/pages/BookView"; import { UploadForm } from "~/pages/UploadForm"; +import { Dots } from "~/utils/Dots"; import styles from "./App.module.css"; -export const App = () => ( -
- - - - - - - -
-); +export const App = () => { + const [loading, setLoading] = useState(false); + + return ( +
+ {loading && ( +
+

+ Loading + +

+
+ )} + + + + + + + + + + + + + +
+ ); +}; export default App; diff --git a/src/hooks/useLibrary.ts b/src/hooks/useLibrary.ts index 81cb19a..db501b3 100644 --- a/src/hooks/useLibrary.ts +++ b/src/hooks/useLibrary.ts @@ -10,13 +10,13 @@ import { export type AddBookFT = (book: IBook) => void; export type UseLibraryReturnTuple = [ - Record, + Record | null, AddBookFT, string[] ]; export const useLibrary = (): UseLibraryReturnTuple => { - const [library, setLibrary] = useState>({}); + const [library, setLibrary] = useState | null>(null); const [hashList, setHashList] = useState([]); const addBook: AddBookFT = (book) => { diff --git a/src/hooks/usePagination.ts b/src/hooks/usePagination.ts index 2000971..21cf3e9 100644 --- a/src/hooks/usePagination.ts +++ b/src/hooks/usePagination.ts @@ -25,7 +25,7 @@ export const usePagination = ( const [pages, setPages] = useState([]); const [currentPage, setCurrentPage] = useState(0); - const computeStartPositionsOfElements = (root: HTMLDivElement) => { + const computeStartPositionsOfElements = async (root: HTMLDivElement) => { const positionToElement: PositionElement[] = []; const idPositions: IdPositions = {}; @@ -56,7 +56,7 @@ export const usePagination = ( setIdPositions(idPositions); }; - const findPages = (page: HTMLElement, pageContainer: HTMLElement) => { + const findPages = async (page: HTMLElement, pageContainer: HTMLElement) => { const pages = []; pages.push(0); let jump = 100; diff --git a/src/pages/BookView/BookView.module.css b/src/pages/BookView/BookView.module.css index c5a66a1..32521fe 100644 --- a/src/pages/BookView/BookView.module.css +++ b/src/pages/BookView/BookView.module.css @@ -17,16 +17,4 @@ img { max-height: 98vh; max-width: 80vw; -} - -.loadingIndicator { - position: fixed; - top: 0; - left: 0; - height: 100vh; - width: 100vw; - background-color: white; - display: flex; - align-items: center; - justify-content: center; -} +} \ No newline at end of file diff --git a/src/pages/BookView/index.tsx b/src/pages/BookView/index.tsx index 0654319..23bbfd7 100644 --- a/src/pages/BookView/index.tsx +++ b/src/pages/BookView/index.tsx @@ -5,9 +5,12 @@ import styles from "./BookView.module.css"; import { BookListContext } from "~/context"; import { usePagination } from "~/hooks/usePagination"; +import { IPageProps } from "~/types/page"; -export const BookView = () => { - const [match, params] = useRoute("/:hash"); +export const BookView = ({ setLoading, loading }: IPageProps) => { + useEffect(() => setLoading(true), []); + + const [_, params] = useRoute("/:hash"); const [books] = useContext(BookListContext); const contentRef = useRef(null); @@ -18,7 +21,7 @@ export const BookView = () => { contentRef, pageContainerRef, pageRef, - params?.hash ? books[params.hash]?.content : undefined + params?.hash && books && loading ? books[params.hash]?.content : undefined ); const currentPageRef = useRef(currentPage); @@ -29,6 +32,8 @@ export const BookView = () => { useEffect(() => { if (ready) { + setLoading(false); + const handleKey = ({ key }: KeyboardEvent) => { switch (key) { case "ArrowLeft": @@ -44,19 +49,16 @@ export const BookView = () => { } }, [ready]); - if (params?.hash && params.hash in books) - return ( - <> - {!ready && ( -
-

Loading

+ if (books) { + if (params?.hash && params.hash in books) + return ( + <> +
+
+
- )} -
-
-
-
- - ); - return ; + + ); + return ; + } else return <>; }; diff --git a/src/pages/Bookshelf/index.tsx b/src/pages/Bookshelf/index.tsx index e337957..77d9620 100644 --- a/src/pages/Bookshelf/index.tsx +++ b/src/pages/Bookshelf/index.tsx @@ -5,18 +5,27 @@ import styles from "./Bookshelf.module.css"; import { BookItem } from "./BookItem"; import { AddBook } from "./AddBook"; import { BookListContext } from "~/context"; +import { IPageProps } from "~/types/page"; + +export const Bookshelf = ({ setLoading }: IPageProps) => { + useEffect(() => setLoading(true), []); -export const Bookshelf = () => { const [books] = useContext(BookListContext); - return ( -
-
- - {Object.values(books).map((book, index) => ( - - ))} + useEffect(() => { + if (books) setLoading(false); + }, [books]); + + if (books) + return ( +
+
+ + {Object.values(books).map((book, index) => ( + + ))} +
-
- ); + ); + else return <>; }; diff --git a/src/pages/UploadForm/index.tsx b/src/pages/UploadForm/index.tsx index 659c271..028f5eb 100644 --- a/src/pages/UploadForm/index.tsx +++ b/src/pages/UploadForm/index.tsx @@ -1,14 +1,14 @@ -import React, { useContext, useState } from "react"; +import React, { useContext, useEffect, useState } from "react"; import { useLocation } from "wouter"; import plusIcon from "~/assets/plus.svg"; import styles from "./UploadForm.module.css"; import { submitFile, validateResponse, validState } from "~/utils/api"; import { BookListContext } from "~/context"; +import { IPageProps } from "~/types/page"; -export const UploadForm = () => { +export const UploadForm = ({ setLoading }: IPageProps) => { const [error, setError] = useState(""); - const [loading, setLoading] = useState(false); const [_, setLocation] = useLocation(); const [__, saveBook] = useContext(BookListContext); diff --git a/src/types/page.ts b/src/types/page.ts new file mode 100644 index 0000000..98928a6 --- /dev/null +++ b/src/types/page.ts @@ -0,0 +1,6 @@ +import React from "react"; + +export interface IPageProps { + setLoading: React.Dispatch>; + loading: boolean; +} diff --git a/src/utils/Dots.tsx b/src/utils/Dots.tsx new file mode 100644 index 0000000..8eab127 --- /dev/null +++ b/src/utils/Dots.tsx @@ -0,0 +1,13 @@ +import React, { useEffect, useState } from "react"; + +export const Dots = () => { + const [n, setN] = useState(3); + + useEffect(() => { + const timeout = setTimeout(() => setN((n + 1) % 4), 500); + + return () => clearTimeout(timeout); + }, [n]); + + return {".".repeat(n)}; +};