|
@@ -16,6 +16,7 @@ import useStore from "libs/hooks/useStore";
|
|
|
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 { SeoHead, SeoHeadConfig } from "components/SeoHead";
|
|
|
|
|
|
|
|
interface NovelPageProps {
|
|
interface NovelPageProps {
|
|
|
detail?: Detail;
|
|
detail?: Detail;
|
|
@@ -36,92 +37,7 @@ const Novel: NextPage<NovelPageProps> = (props) => {
|
|
|
`/api/novel/${query.slug}/chapters`
|
|
`/api/novel/${query.slug}/chapters`
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- const ldJson = useMemo(() => {
|
|
|
|
|
- return JSON.stringify([
|
|
|
|
|
- {
|
|
|
|
|
- "@context": "https://schema.org",
|
|
|
|
|
- "@type": "Book",
|
|
|
|
|
- mainEntityOfPage: `https://${siteConfig.host}/novel/${query.slug}`,
|
|
|
|
|
- headline: detail?.name,
|
|
|
|
|
- name: detail?.name,
|
|
|
|
|
- genre: detail?.genres[0].name,
|
|
|
|
|
- image: {
|
|
|
|
|
- "@type": "ImageObject",
|
|
|
|
|
- url: detail?.img,
|
|
|
|
|
- },
|
|
|
|
|
- bookFormat: "https://schema.org/EBook",
|
|
|
|
|
- datePublished: detail?.create_time,
|
|
|
|
|
- dateModified: detail?.update_time,
|
|
|
|
|
- author: {
|
|
|
|
|
- "@type": "Person",
|
|
|
|
|
- name: detail?.author,
|
|
|
|
|
- },
|
|
|
|
|
- copyrightHolder: detail?.author,
|
|
|
|
|
- publisher: {
|
|
|
|
|
- "@type": "Organization",
|
|
|
|
|
- name: siteConfig.siteName,
|
|
|
|
|
- logo: {
|
|
|
|
|
- "@type": "ImageObject",
|
|
|
|
|
- url: `https://${siteConfig.host}/favicon-32x32.png`,
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- description: detail?.desc,
|
|
|
|
|
- // aggregateRating: {
|
|
|
|
|
- // "@type": "AggregateRating",
|
|
|
|
|
- // bestRating: "5.0",
|
|
|
|
|
- // ratingValue: "4.62",
|
|
|
|
|
- // ratingCount: "159",
|
|
|
|
|
- // },
|
|
|
|
|
- potentialAction: {
|
|
|
|
|
- "@type": "ReadAction",
|
|
|
|
|
- target: {
|
|
|
|
|
- "@type": "EntryPoint",
|
|
|
|
|
- urlTemplate: `https://${siteConfig.host}/novel/${chapters?.chapters[0].uri}`,
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- "@context": "https://schema.org",
|
|
|
|
|
- "@type": "BreadcrumbList",
|
|
|
|
|
- itemListElement: [
|
|
|
|
|
- {
|
|
|
|
|
- "@type": "ListItem",
|
|
|
|
|
- position: 1,
|
|
|
|
|
- name: "Home",
|
|
|
|
|
- item: `https://${siteConfig.host}`,
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- "@type": "ListItem",
|
|
|
|
|
- position: 2,
|
|
|
|
|
- name: detail?.genres[0].name,
|
|
|
|
|
- item: `https://${siteConfig.host}/novels/${detail?.genres[0].uri}`,
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- "@type": "ListItem",
|
|
|
|
|
- position: 3,
|
|
|
|
|
- name: `${detail?.name || ""}`,
|
|
|
|
|
- item: `https://${siteConfig.host}/novel/${query.slug}`,
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
- ...siteConfig.jsonLd,
|
|
|
|
|
- ]);
|
|
|
|
|
- }, [
|
|
|
|
|
- chapters?.chapters,
|
|
|
|
|
- detail?.author,
|
|
|
|
|
- detail?.create_time,
|
|
|
|
|
- detail?.desc,
|
|
|
|
|
- detail?.genres,
|
|
|
|
|
- detail?.img,
|
|
|
|
|
- detail?.name,
|
|
|
|
|
- detail?.update_time,
|
|
|
|
|
- query.slug,
|
|
|
|
|
- siteConfig.host,
|
|
|
|
|
- siteConfig.jsonLd,
|
|
|
|
|
- siteConfig.siteName,
|
|
|
|
|
- ]);
|
|
|
|
|
-
|
|
|
|
|
- const seoConfig = useMemo(() => {
|
|
|
|
|
|
|
+ const seoConfig: SeoHeadConfig = useMemo(() => {
|
|
|
const keys = detail?.genres.map((item) => item.name).join(", ");
|
|
const keys = detail?.genres.map((item) => item.name).join(", ");
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
@@ -140,15 +56,89 @@ const Novel: NextPage<NovelPageProps> = (props) => {
|
|
|
url: `https://${siteConfig.host}/novel/${query.slug}`,
|
|
url: `https://${siteConfig.host}/novel/${query.slug}`,
|
|
|
siteName: siteConfig.siteName,
|
|
siteName: siteConfig.siteName,
|
|
|
img: detail?.img,
|
|
img: detail?.img,
|
|
|
|
|
+ jsonLd: JSON.stringify([
|
|
|
|
|
+ {
|
|
|
|
|
+ "@context": "https://schema.org",
|
|
|
|
|
+ "@type": "Book",
|
|
|
|
|
+ mainEntityOfPage: `https://${siteConfig.host}/novel/${query.slug}`,
|
|
|
|
|
+ headline: detail?.name,
|
|
|
|
|
+ name: detail?.name,
|
|
|
|
|
+ genre: detail?.genres[0].name,
|
|
|
|
|
+ image: {
|
|
|
|
|
+ "@type": "ImageObject",
|
|
|
|
|
+ url: detail?.img,
|
|
|
|
|
+ },
|
|
|
|
|
+ bookFormat: "https://schema.org/EBook",
|
|
|
|
|
+ datePublished: detail?.create_time,
|
|
|
|
|
+ dateModified: detail?.update_time,
|
|
|
|
|
+ author: {
|
|
|
|
|
+ "@type": "Person",
|
|
|
|
|
+ name: detail?.author,
|
|
|
|
|
+ },
|
|
|
|
|
+ copyrightHolder: detail?.author,
|
|
|
|
|
+ publisher: {
|
|
|
|
|
+ "@type": "Organization",
|
|
|
|
|
+ name: siteConfig.siteName,
|
|
|
|
|
+ logo: {
|
|
|
|
|
+ "@type": "ImageObject",
|
|
|
|
|
+ url: `https://${siteConfig.host}/favicon-32x32.png`,
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ description: detail?.desc,
|
|
|
|
|
+ // aggregateRating: {
|
|
|
|
|
+ // "@type": "AggregateRating",
|
|
|
|
|
+ // bestRating: "5.0",
|
|
|
|
|
+ // ratingValue: "4.62",
|
|
|
|
|
+ // ratingCount: "159",
|
|
|
|
|
+ // },
|
|
|
|
|
+ potentialAction: {
|
|
|
|
|
+ "@type": "ReadAction",
|
|
|
|
|
+ target: {
|
|
|
|
|
+ "@type": "EntryPoint",
|
|
|
|
|
+ urlTemplate: `https://${siteConfig.host}/novel/${chapters?.chapters[0].uri}`,
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "@context": "https://schema.org",
|
|
|
|
|
+ "@type": "BreadcrumbList",
|
|
|
|
|
+ itemListElement: [
|
|
|
|
|
+ {
|
|
|
|
|
+ "@type": "ListItem",
|
|
|
|
|
+ position: 1,
|
|
|
|
|
+ name: "Home",
|
|
|
|
|
+ item: `https://${siteConfig.host}`,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "@type": "ListItem",
|
|
|
|
|
+ position: 2,
|
|
|
|
|
+ name: detail?.genres[0].name,
|
|
|
|
|
+ item: `https://${siteConfig.host}/novels/${detail?.genres[0].uri}`,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "@type": "ListItem",
|
|
|
|
|
+ position: 3,
|
|
|
|
|
+ name: `${detail?.name || ""}`,
|
|
|
|
|
+ item: `https://${siteConfig.host}/novel/${query.slug}`,
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ ...siteConfig.jsonLd,
|
|
|
|
|
+ ]),
|
|
|
};
|
|
};
|
|
|
}, [
|
|
}, [
|
|
|
|
|
+ chapters?.chapters,
|
|
|
detail?.author,
|
|
detail?.author,
|
|
|
|
|
+ detail?.create_time,
|
|
|
|
|
+ detail?.desc,
|
|
|
detail?.genres,
|
|
detail?.genres,
|
|
|
detail?.img,
|
|
detail?.img,
|
|
|
detail?.name,
|
|
detail?.name,
|
|
|
detail?.other_name,
|
|
detail?.other_name,
|
|
|
|
|
+ detail?.update_time,
|
|
|
query.slug,
|
|
query.slug,
|
|
|
siteConfig.host,
|
|
siteConfig.host,
|
|
|
|
|
+ siteConfig.jsonLd,
|
|
|
siteConfig.keywords,
|
|
siteConfig.keywords,
|
|
|
siteConfig.siteName,
|
|
siteConfig.siteName,
|
|
|
]);
|
|
]);
|
|
@@ -178,56 +168,7 @@ const Novel: NextPage<NovelPageProps> = (props) => {
|
|
|
}
|
|
}
|
|
|
return (
|
|
return (
|
|
|
<main>
|
|
<main>
|
|
|
- <Head>
|
|
|
|
|
- <title>{seoConfig.title}</title>
|
|
|
|
|
- {seoConfig.description ? (
|
|
|
|
|
- <meta name="description" content={seoConfig.description} />
|
|
|
|
|
- ) : null}
|
|
|
|
|
- {seoConfig.keywords ? (
|
|
|
|
|
- <meta name="keywords" content={seoConfig.keywords} />
|
|
|
|
|
- ) : null}
|
|
|
|
|
- <meta property="og:url" key="og:url" content={seoConfig.url} />
|
|
|
|
|
- <meta
|
|
|
|
|
- property="og:site_name"
|
|
|
|
|
- key="og:site_name"
|
|
|
|
|
- content={seoConfig.siteName}
|
|
|
|
|
- />
|
|
|
|
|
- <meta property="og:title" key="og:title" content={seoConfig.title} />
|
|
|
|
|
- {seoConfig.description ? (
|
|
|
|
|
- <meta property="og:description" key="og:description" content="" />
|
|
|
|
|
- ) : null}
|
|
|
|
|
- {seoConfig.img ? (
|
|
|
|
|
- <meta property="og:image" key="og:image" content={seoConfig.img} />
|
|
|
|
|
- ) : null}
|
|
|
|
|
- <meta
|
|
|
|
|
- name="twitter:title"
|
|
|
|
|
- key="twitter:title"
|
|
|
|
|
- content={seoConfig.title}
|
|
|
|
|
- />
|
|
|
|
|
- {seoConfig.description ? (
|
|
|
|
|
- <meta
|
|
|
|
|
- name="twitter:description"
|
|
|
|
|
- key="twitter:description"
|
|
|
|
|
- content=""
|
|
|
|
|
- />
|
|
|
|
|
- ) : null}
|
|
|
|
|
- <meta name="twitter:card" key="twitter:card" content="summary" />
|
|
|
|
|
- {seoConfig.img ? (
|
|
|
|
|
- <meta
|
|
|
|
|
- name="twitter:image"
|
|
|
|
|
- key="twitter:image"
|
|
|
|
|
- content={seoConfig.img}
|
|
|
|
|
- />
|
|
|
|
|
- ) : null}
|
|
|
|
|
- <link rel="canonical" key="canonical" href={seoConfig.url} />
|
|
|
|
|
- {ldJson ? (
|
|
|
|
|
- <script
|
|
|
|
|
- type="application/ld+json"
|
|
|
|
|
- key="application/ld+json"
|
|
|
|
|
- dangerouslySetInnerHTML={{ __html: ldJson }}
|
|
|
|
|
- />
|
|
|
|
|
- ) : null}
|
|
|
|
|
- </Head>
|
|
|
|
|
|
|
+ <SeoHead seoConfig={seoConfig} />
|
|
|
<div
|
|
<div
|
|
|
className={styles["novel-wrap"]}
|
|
className={styles["novel-wrap"]}
|
|
|
style={{
|
|
style={{
|