Leo пре 3 година
родитељ
комит
b72dc64810

+ 4 - 10
components/VirtualScroll/index.tsx

@@ -31,34 +31,28 @@ export default function VirtualScroll(props: VirtualScrollProps) {
   } = props;
 
   const [wrapHeight, setWrapHeight] = useState(0);
-
   const [scrollY, setScrollY] = useState(startIndex * itemHeight);
-
   const offset = useMemo(
     () => Math.max(0, Math.floor(scrollY / itemHeight)),
     [itemHeight, scrollY]
   );
-
   const limit = useMemo(() => {
     return Math.floor(wrapHeight / itemHeight) + 1;
   }, [itemHeight, wrapHeight]);
-
   const [wrapElement, setWrapElement] = useState<HTMLDivElement | null>(null);
 
   const handleScroll: UIEventHandler<HTMLDivElement> = (e) => {
     setScrollY((e.target as HTMLDivElement).scrollTop);
   };
 
-  const resize = useCallback(
-    (e: UIEvent) => {
-      if (wrapElement) setWrapHeight(wrapElement.clientHeight);
-    },
-    [wrapElement]
-  );
+  const resize = useCallback(() => {
+    if (wrapElement) setWrapHeight(wrapElement.clientHeight);
+  }, [wrapElement]);
 
   const setWrapRef = useCallback((ele: HTMLDivElement) => {
     if (ele) {
       setWrapElement(ele);
+      ele.scrollTo(0, scrollY);
       if (ele) setWrapHeight(ele.clientHeight);
     } else {
       setWrapElement(null);

+ 22 - 5
components/novel/Toc/index.tsx

@@ -3,7 +3,7 @@ import useGet from "../../../utils/hooks/useGet";
 import type { ChapterListData } from "../../../types/http";
 
 import styles from "../../../styles/chapter.module.scss";
-import { useCallback } from "react";
+import { useCallback, useMemo } from "react";
 import VirtualScroll from "../../VirtualScroll";
 import clsx from "clsx";
 
@@ -14,12 +14,23 @@ interface TocProps {
 }
 
 const Toc = (props: TocProps) => {
-  const { novel, className } = props;
+  const { novel, chapter, className } = props;
 
   const { data: { data: chapters } = { data: null } } = useGet<ChapterListData>(
     `/api/novel/${novel}/chapters`
   );
 
+  const startIndex = useMemo(() => {
+    const uri = `${novel}/${chapter}`;
+    if (chapters && Array.isArray(chapters.chapters)) {
+      const idx = chapters.chapters.findIndex((item) => item.uri === uri);
+      if (idx > -1) {
+        return idx;
+      }
+    }
+    return 0;
+  }, [novel, chapter, chapters]);
+
   const getTocItem = useCallback(
     (offset: number, limit: number) => {
       if (!chapters) return [];
@@ -29,9 +40,14 @@ const Toc = (props: TocProps) => {
       for (let i = offset; i < len; i++) {
         const item = chapters.chapters[i];
         list.push(
-          <li key={item.id}>
+          <li
+            key={item.id}
+            className={clsx({
+              [styles["current"]]: item.uri === `${novel}/${chapter}`,
+            })}
+          >
             <Link href={`/novel/${item.uri}`} title={item.name} key={item.id}>
-              <i>1</i>
+              <i>{i + 1}</i>
               <strong>{item.name}</strong>
             </Link>
           </li>
@@ -39,7 +55,7 @@ const Toc = (props: TocProps) => {
       }
       return list;
     },
-    [chapters]
+    [chapter, chapters, novel]
   );
 
   return (
@@ -52,6 +68,7 @@ const Toc = (props: TocProps) => {
           total={chapters.chapters.length}
           getItems={getTocItem}
           className={styles["toolbar-scrollbar"]}
+          startIndex={startIndex}
         />
       ) : null}
       {/* {chapters ? (

+ 40 - 14
pages/novel/[slug]/[chapter].tsx

@@ -125,25 +125,51 @@ const Chapter: NextPageWithLayout = () => {
         </div> */}
       </header>
       <main className={styles["chapter-main"]} onClick={handleOpenToolbar}>
-        <div
-          className={clsx(styles["chapter-page"], {
-            ["font-serif"]: isSerif,
-            "text-sm": fontSize === 1,
-            "text-base": fontSize === 2,
-            "text-lg": fontSize === 3,
-            "text-xl": fontSize === 4,
-            "text-2xl": fontSize === 5,
-          })}
-        >
+        <div className={clsx(styles["chapter-page"])}>
           <article className={styles["novel"]}>
-            <header>
-              <h1 className="">{chapterData.title}</h1>
-              <h2 className="">{chapterData.chapter}</h2>
+            <header
+              className={clsx({
+                ["font-serif"]: isSerif,
+              })}
+            >
+              <h1>{chapterData.title}</h1>
+              <h2>{chapterData.chapter}</h2>
             </header>
             <div
-              className="content"
+              className={clsx("content", {
+                ["font-serif"]: isSerif,
+                "text-sm": fontSize === 1,
+                "text-base": fontSize === 2,
+                "text-lg": fontSize === 3,
+                "text-xl": fontSize === 4,
+                "text-2xl": fontSize === 5,
+              })}
               dangerouslySetInnerHTML={{ __html: chapterData.content }}
             />
+            <footer className="text-center py-5">
+              {chapterData.next ? (
+                <div>
+                  <Link
+                    className="btn btn-primary uppercase"
+                    href={`/novel${chapterData.next}`}
+                    onClick={handleStopPropagation}
+                  >
+                    Next Chapter
+                  </Link>
+                </div>
+              ) : null}
+              {chapterData.pre ? (
+                <div className="mt-5">
+                  <Link
+                    className="underline uppercase"
+                    href={`/novel${chapterData.pre}`}
+                    onClick={handleStopPropagation}
+                  >
+                    Previous Chapter
+                  </Link>
+                </div>
+              ) : null}
+            </footer>
           </article>
         </div>
         <div

+ 6 - 1
styles/chapter.module.scss

@@ -98,11 +98,16 @@
           @apply w-9 mr-1 flex-shrink-0 not-italic text-slate-400;
         }
         strong {
-          @apply block font-normal flex-1 whitespace-nowrap w-0 overflow-hidden text-ellipsis;
+          @apply block font-normal flex-1 whitespace-nowrap w-0 overflow-hidden text-ellipsis text-gray-100;
         }
         small {
           @apply text-slate-400 ml-2;
         }
+        &.current {
+          a strong {
+            @apply text-blue-300 font-extrabold;
+          }
+        }
       }
     }
   }