Leo 3 years ago
parent
commit
8a9aea6280
5 changed files with 99 additions and 42 deletions
  1. 4 4
      components/novel/Settings/index.tsx
  2. 9 3
      pages/_app.tsx
  3. 82 32
      pages/novel/[slug]/index.tsx
  4. 2 2
      public/manifest.json
  5. 2 1
      styles/globals.scss

+ 4 - 4
components/novel/Settings/index.tsx

@@ -122,8 +122,8 @@ const Settings = (props: SettingsProps) => {
       </div>
       <div className={styles["toolbar-display-label"]}>Sizes</div>
       <div className="flex items-center">
-        <button className="mr-4" onClick={() => handleChangeFontSize(-1)}>
-          <svg className="w-5 h-5" viewBox="0 0 16 16">
+        <button className="mr-5" onClick={() => handleChangeFontSize(-1)}>
+          <svg className="w-5 h-5">
             <use href="/icons.svg#font-dn"></use>
           </svg>
         </button>
@@ -139,8 +139,8 @@ const Settings = (props: SettingsProps) => {
           classes={{ ...styles, root: styles.slider }}
           onChange={(e, value) => changeFontSize(value as FontSize)}
         />
-        <button className="ml-4" onClick={() => handleChangeFontSize(1)}>
-          <svg className="w-5 h-5" viewBox="0 0 16 16">
+        <button className="ml-5" onClick={() => handleChangeFontSize(1)}>
+          <svg className="w-5 h-5">
             <use href="/icons.svg#font-up"></use>
           </svg>
         </button>

+ 9 - 3
pages/_app.tsx

@@ -54,9 +54,15 @@ const MyApp = ({ Component, pageProps }: AppPropsWithLayout) => {
           name="viewport"
           content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"
         />
-        <title>NovelDit</title>
-        <meta name="description" content="" />
-        <meta name="keywords" content="" />
+        <title>NovelDit - Read Novels Online for Free</title>
+        <meta
+          name="description"
+          content="We are offering free books online read! Read novel updated daily: light novel translations, web novel, chinese novel, japanese novel, korean novel and other novel online."
+        />
+        <meta
+          name="keywords"
+          content="Novel updates, Free books online, Light Novel, Read light novel, Light novel translations, Free Novels Online"
+        />
         <link rel="manifest" href="/manifest.json" />
         <link rel="icon" href="/logo.svg" type="image/svg+xml" />
         <link rel="icon" href="/favicon.ico" type="image/x-icon" />

+ 82 - 32
pages/novel/[slug]/index.tsx

@@ -1,14 +1,22 @@
 import clsx from "clsx";
 import Link from "next/link";
-import { useState } from "react";
+import { useMemo, useState } from "react";
 import { useRouter } from "next/router";
 import type { GetServerSideProps, NextPage } from "next";
+import { styled } from "@mui/system";
+import TabsUnstyled from "@mui/base/TabsUnstyled";
+import TabsListUnstyled from "@mui/base/TabsListUnstyled";
+import TabPanelUnstyled from "@mui/base/TabPanelUnstyled";
+import { buttonUnstyledClasses } from "@mui/base/ButtonUnstyled";
+import TabUnstyled, { tabUnstyledClasses } from "@mui/base/TabUnstyled";
+
 import type { Detail, ChapterListData } from "../../../types/http";
 import { get } from "../../../utils/http";
 import useGet from "../../../utils/hooks/useGet";
 import NovelCover from "../../../components/NovelCover";
 
 import styles from "../../../styles/novel-info.module.scss";
+import { isServer } from "../../../libs/config";
 
 interface NovelPageProps {
   detail?: Detail;
@@ -17,13 +25,31 @@ interface NovelPageProps {
 
 const Novel: NextPage<NovelPageProps> = (props) => {
   const { query } = useRouter();
+
   const { data: { data: detail } = { data: null } } = useGet<Detail>(
     `/api/novel/${query.slug}`
   );
+
   const { data: { data: chapters } = { data: null } } = useGet<ChapterListData>(
     `/api/novel/${query.slug}/chapters`
   );
-  const [tab, setTab] = useState("about");
+
+  const chapterLists = useMemo(() => {
+    if (!chapters || !chapters.chapters.length) return [];
+    const len = Math.ceil(chapters.chapters.length / 100);
+    const list = [];
+    for (let i = 0; i < len; i++) {
+      list.push({
+        title: `${i * 100 + 1}-${(i + 1) * 100}`,
+        list: chapters.chapters.slice(
+          i * 100,
+          Math.min(chapters.chapters.length, (i + 1) * 100)
+        ),
+      });
+    }
+    return list;
+  }, [chapters]);
+
   if (!detail || !chapters) {
     return null;
   }
@@ -108,22 +134,16 @@ const Novel: NextPage<NovelPageProps> = (props) => {
           </div>
         </div>
       </div>
-      <div className="container bg-paper py-3">
-        <div className="tabs">
-          <button
-            className={clsx(["tab", { active: tab === "about" }])}
-            onClick={() => setTab("about")}
-          >
+      <TabsUnstyled defaultValue={0} className="container bg-paper py-3">
+        <TabsListUnstyled className="tabs">
+          <TabUnstyled value={0} className="tab">
             About
-          </button>
-          <button
-            className={clsx(["tab", { active: tab === "chapters" }])}
-            onClick={() => setTab("chapters")}
-          >
+          </TabUnstyled>
+          <TabUnstyled value={1} className="tab">
             Chapters
-          </button>
-        </div>
-        <div className={clsx({ hidden: tab !== "about" })}>
+          </TabUnstyled>
+        </TabsListUnstyled>
+        <TabPanelUnstyled value={0}>
           <h2 className="sub-title">Tags</h2>
           <div className="tags">
             {detail.genres.map((item) => (
@@ -143,23 +163,53 @@ const Novel: NextPage<NovelPageProps> = (props) => {
             className={styles["novel-text"]}
             dangerouslySetInnerHTML={{ __html: detail.desc }}
           />
-        </div>
-
-        <div className={clsx({ hidden: tab !== "chapters" })}>
+        </TabPanelUnstyled>
+        <TabPanelUnstyled value={isServer ? 0 : 1}>
           <h3 className="sub-title">{chapters.novel.name}</h3>
-          <ol className={styles["chapter-list"]}>
-            {chapters.chapters.map((item) => (
-              <li key={item.id}>
-                <Link href={`/novel/${item.uri}`} title={item.name}>
-                  <i>1</i>
-                  <strong>{item.name}</strong>
-                  <small>1yr</small>
-                </Link>
-              </li>
-            ))}
-          </ol>
-        </div>
-      </div>
+          {isServer ? (
+            <ol className={styles["chapter-list"]}>
+              {chapters.chapters.map((item) => (
+                <li key={item.id}>
+                  <Link href={`/novel/${item.uri}`} title={item.name}>
+                    <i>1</i>
+                    <strong>{item.name}</strong>
+                    <small>1yr</small>
+                  </Link>
+                </li>
+              ))}
+            </ol>
+          ) : (
+            <TabsUnstyled defaultValue={0} className="container bg-paper py-3">
+              <TabsListUnstyled className="tabs">
+                {chapterLists.map((chapter, idx) => (
+                  <TabUnstyled value={isServer ? 0 : idx} className="tab" key={chapter.title}>
+                    {chapter.title}
+                  </TabUnstyled>
+                ))}
+              </TabsListUnstyled>
+
+              {chapterLists.map((chapter, idx) => (
+                <TabPanelUnstyled
+                  value={isServer ? 0 : idx}
+                  component="ol"
+                  key={chapter.title}
+                  className={styles["chapter-list"]}
+                >
+                  {chapter.list.map((item) => (
+                    <li key={item.id}>
+                      <Link href={`/novel/${item.uri}`} title={item.name}>
+                        <i>1</i>
+                        <strong>{item.name}</strong>
+                        <small>1yr</small>
+                      </Link>
+                    </li>
+                  ))}
+                </TabPanelUnstyled>
+              ))}
+            </TabsUnstyled>
+          )}
+        </TabPanelUnstyled>
+      </TabsUnstyled>
     </main>
   );
 };

+ 2 - 2
public/manifest.json

@@ -1,6 +1,6 @@
 {
-  "name": "Next.JS Progressive Web App",
-  "short_name": "Next PWA",
+  "name": "NovelDit - free novel read online",
+  "short_name": "NovelDit",
   "theme_color": "#ffffff",
   "background_color": "#004740",
   "display": "fullscreen",

+ 2 - 1
styles/globals.scss

@@ -386,7 +386,8 @@
   @apply border-b border-slate-200 space-x-6 flex whitespace-nowrap dark:border-slate-200/5;
   .tab {
     @apply flex text-sm leading-6 font-semibold pt-3 pb-2.5 border-b-2 -mb-px text-slate-900 border-transparent hover:border-slate-300 dark:text-slate-200 dark:hover:border-slate-700;
-    &.active {
+    &.active,
+    &.Mui-selected {
       @apply text-sky-500 border-current;
     }
   }