|
@@ -1,14 +1,22 @@
|
|
|
import clsx from "clsx";
|
|
import clsx from "clsx";
|
|
|
import Link from "next/link";
|
|
import Link from "next/link";
|
|
|
-import { useState } from "react";
|
|
|
|
|
|
|
+import { useMemo, useState } from "react";
|
|
|
import { useRouter } from "next/router";
|
|
import { useRouter } from "next/router";
|
|
|
import type { GetServerSideProps, NextPage } from "next";
|
|
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 type { Detail, ChapterListData } from "../../../types/http";
|
|
|
import { get } from "../../../utils/http";
|
|
import { get } from "../../../utils/http";
|
|
|
import useGet from "../../../utils/hooks/useGet";
|
|
import useGet from "../../../utils/hooks/useGet";
|
|
|
import NovelCover from "../../../components/NovelCover";
|
|
import NovelCover from "../../../components/NovelCover";
|
|
|
|
|
|
|
|
import styles from "../../../styles/novel-info.module.scss";
|
|
import styles from "../../../styles/novel-info.module.scss";
|
|
|
|
|
+import { isServer } from "../../../libs/config";
|
|
|
|
|
|
|
|
interface NovelPageProps {
|
|
interface NovelPageProps {
|
|
|
detail?: Detail;
|
|
detail?: Detail;
|
|
@@ -17,13 +25,31 @@ interface NovelPageProps {
|
|
|
|
|
|
|
|
const Novel: NextPage<NovelPageProps> = (props) => {
|
|
const Novel: NextPage<NovelPageProps> = (props) => {
|
|
|
const { query } = useRouter();
|
|
const { query } = useRouter();
|
|
|
|
|
+
|
|
|
const { data: { data: detail } = { data: null } } = useGet<Detail>(
|
|
const { data: { data: detail } = { data: null } } = useGet<Detail>(
|
|
|
`/api/novel/${query.slug}`
|
|
`/api/novel/${query.slug}`
|
|
|
);
|
|
);
|
|
|
|
|
+
|
|
|
const { data: { data: chapters } = { data: null } } = useGet<ChapterListData>(
|
|
const { data: { data: chapters } = { data: null } } = useGet<ChapterListData>(
|
|
|
`/api/novel/${query.slug}/chapters`
|
|
`/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) {
|
|
if (!detail || !chapters) {
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
@@ -108,22 +134,16 @@ const Novel: NextPage<NovelPageProps> = (props) => {
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</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
|
|
About
|
|
|
- </button>
|
|
|
|
|
- <button
|
|
|
|
|
- className={clsx(["tab", { active: tab === "chapters" }])}
|
|
|
|
|
- onClick={() => setTab("chapters")}
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ </TabUnstyled>
|
|
|
|
|
+ <TabUnstyled value={1} className="tab">
|
|
|
Chapters
|
|
Chapters
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className={clsx({ hidden: tab !== "about" })}>
|
|
|
|
|
|
|
+ </TabUnstyled>
|
|
|
|
|
+ </TabsListUnstyled>
|
|
|
|
|
+ <TabPanelUnstyled value={0}>
|
|
|
<h2 className="sub-title">Tags</h2>
|
|
<h2 className="sub-title">Tags</h2>
|
|
|
<div className="tags">
|
|
<div className="tags">
|
|
|
{detail.genres.map((item) => (
|
|
{detail.genres.map((item) => (
|
|
@@ -143,23 +163,53 @@ const Novel: NextPage<NovelPageProps> = (props) => {
|
|
|
className={styles["novel-text"]}
|
|
className={styles["novel-text"]}
|
|
|
dangerouslySetInnerHTML={{ __html: detail.desc }}
|
|
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>
|
|
<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>
|
|
</main>
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|