[update] upgrade the reader page
This commit is contained in:
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -10,6 +10,7 @@
|
|||||||
"micromessenger",
|
"micromessenger",
|
||||||
"nextjs",
|
"nextjs",
|
||||||
"prin",
|
"prin",
|
||||||
|
"quora",
|
||||||
"readerpage",
|
"readerpage",
|
||||||
"rehype",
|
"rehype",
|
||||||
"Swipeable",
|
"Swipeable",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"noForEach": "off"
|
"noForEach": "off"
|
||||||
},
|
},
|
||||||
"correctness": {
|
"correctness": {
|
||||||
|
"noUnusedImports": "error",
|
||||||
"useExhaustiveDependencies": "off"
|
"useExhaustiveDependencies": "off"
|
||||||
},
|
},
|
||||||
"suspicious": {
|
"suspicious": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const H2 = (props: JSX.IntrinsicElements["h2"]) => {
|
const H2 = (props: JSX.IntrinsicElements["h2"]) => {
|
||||||
return (
|
return (
|
||||||
<h2 className={"caption-font scroll-mt-20"} id={props.id}>
|
<h2 className={"caption-font mt-6 mb-2 scroll-mt-20"} id={props.id}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</h2>
|
</h2>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Config } from "@/data/config";
|
import { Config } from "@/data/config";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { FaQuora, FaWeibo } from "react-icons/fa";
|
||||||
import { FiGithub, FiInstagram, FiMail, FiTwitter } from "react-icons/fi";
|
import { FiGithub, FiInstagram, FiMail, FiTwitter } from "react-icons/fi";
|
||||||
import { FaWeibo } from "react-icons/fa";
|
|
||||||
import {
|
import {
|
||||||
TbBrandBilibili,
|
TbBrandBilibili,
|
||||||
TbBrandFacebook,
|
TbBrandFacebook,
|
||||||
@@ -95,6 +95,16 @@ export const SocialIcons = () => {
|
|||||||
<TbBrandFacebook className="hover:text-blue-500" />
|
<TbBrandFacebook className="hover:text-blue-500" />
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
|
{Config.SocialLinks.quora && (
|
||||||
|
<Link
|
||||||
|
className="flex w-1/5 basis-0 justify-center p-2"
|
||||||
|
href={`https://quora.com/profile/${Config.SocialLinks.quora}`}
|
||||||
|
target="_blank"
|
||||||
|
title="Quora"
|
||||||
|
>
|
||||||
|
<FaQuora className="hover:text-red-500" />
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
{Config.SocialLinks.linkedin && (
|
{Config.SocialLinks.linkedin && (
|
||||||
<Link
|
<Link
|
||||||
className="flex w-1/5 basis-0 justify-center p-2"
|
className="flex w-1/5 basis-0 justify-center p-2"
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export const Config: TConfig = {
|
|||||||
bilibili: "123456", // Bilibili Number ID
|
bilibili: "123456", // Bilibili Number ID
|
||||||
weibo: "123456", // Weibo UID
|
weibo: "123456", // Weibo UID
|
||||||
telegram: "example", // Telegram ID
|
telegram: "example", // Telegram ID
|
||||||
|
quora: "example", //Quora ID
|
||||||
mastodon: "https://mas.to/@example", // Mastodon link
|
mastodon: "https://mas.to/@example", // Mastodon link
|
||||||
email: "me@example.com", // Email address, required.
|
email: "me@example.com", // Email address, required.
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { MDXComponentsSet } from "@/components/mdx";
|
import { MDXComponentsSet } from "@/components/mdx";
|
||||||
import { BottomCard } from "@/components/reader-page/BottomCard";
|
|
||||||
import { DrawerTOC } from "@/components/reader-page/DrawerTOC";
|
import { DrawerTOC } from "@/components/reader-page/DrawerTOC";
|
||||||
import { PostComments } from "@/components/reader-page/PostComments";
|
import { PostComments } from "@/components/reader-page/PostComments";
|
||||||
import { PostCover } from "@/components/reader-page/PostCover";
|
import { PostCover } from "@/components/reader-page/PostCover";
|
||||||
import { ShareButtons } from "@/components/reader-page/ShareButtons";
|
import { ShareButtons } from "@/components/reader-page/ShareButtons";
|
||||||
import { TOC } from "@/components/reader-page/TOC";
|
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { Toaster } from "@/components/ui/toaster";
|
import { Toaster } from "@/components/ui/toaster";
|
||||||
import { Footer } from "@/components/utils/Footer";
|
import { Footer } from "@/components/utils/Footer";
|
||||||
@@ -15,7 +13,6 @@ import { Config } from "@/data/config";
|
|||||||
import { normalizeDate } from "@/lib/date";
|
import { normalizeDate } from "@/lib/date";
|
||||||
import { getPostFileContent, sortedPosts } from "@/lib/post-process";
|
import { getPostFileContent, sortedPosts } from "@/lib/post-process";
|
||||||
import { makeTOCTree } from "@/lib/toc";
|
import { makeTOCTree } from "@/lib/toc";
|
||||||
import useDrawerTOCState from "@/stores/useDrawerTOCState";
|
|
||||||
import type { TFrontmatter } from "@/types/frontmatter.type";
|
import type { TFrontmatter } from "@/types/frontmatter.type";
|
||||||
import type { TPostListItem } from "@/types/post-list";
|
import type { TPostListItem } from "@/types/post-list";
|
||||||
import type { TTOCItem } from "@/types/toc.type";
|
import type { TTOCItem } from "@/types/toc.type";
|
||||||
@@ -25,7 +22,6 @@ import { MDXRemote, type MDXRemoteSerializeResult } from "next-mdx-remote";
|
|||||||
import { serialize } from "next-mdx-remote/serialize";
|
import { serialize } from "next-mdx-remote/serialize";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { renderToString } from "react-dom/server";
|
import { renderToString } from "react-dom/server";
|
||||||
import { useSwipeable } from "react-swipeable";
|
|
||||||
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
||||||
import rehypeHighlight from "rehype-highlight";
|
import rehypeHighlight from "rehype-highlight";
|
||||||
import rehypeKatex from "rehype-katex";
|
import rehypeKatex from "rehype-katex";
|
||||||
@@ -35,6 +31,7 @@ import rehypeSlug from "rehype-slug";
|
|||||||
import externalLinks from "remark-external-links";
|
import externalLinks from "remark-external-links";
|
||||||
import remarkGfm from "remark-gfm";
|
import remarkGfm from "remark-gfm";
|
||||||
import remarkMath from "remark-math";
|
import remarkMath from "remark-math";
|
||||||
|
import { titleCase } from "title-case";
|
||||||
|
|
||||||
type ReaderPageProps = {
|
type ReaderPageProps = {
|
||||||
compiledSource: MDXRemoteSerializeResult;
|
compiledSource: MDXRemoteSerializeResult;
|
||||||
@@ -47,87 +44,82 @@ type ReaderPageProps = {
|
|||||||
|
|
||||||
const ReaderPage = (props: ReaderPageProps) => {
|
const ReaderPage = (props: ReaderPageProps) => {
|
||||||
const compiledSource = props.compiledSource;
|
const compiledSource = props.compiledSource;
|
||||||
const setIsTOCOpen = useDrawerTOCState((state) => state.changeDrawerTOCOpen);
|
// const setIsTOCOpen = useDrawerTOCState((state) => state.changeDrawerTOCOpen);
|
||||||
|
|
||||||
// Only the TOC length reaches 3 can be displayed.
|
// Only the TOC length reaches 3 can be displayed.
|
||||||
// In order to avoid large blank spaces that ruin the visual perception
|
// In order to avoid large blank spaces that ruin the visual perception
|
||||||
const isTOCLongEnough = props.tocList.length > 2;
|
const isTOCLongEnough = props.tocList.length > 2;
|
||||||
const handleRightSwipe = useSwipeable({
|
// const handleLeftSwipe = useSwipeable({
|
||||||
onSwipedRight: () => {
|
// onSwipedLeft: () => isTOCLongEnough && setIsTOCOpen(true),
|
||||||
isTOCLongEnough && setIsTOCOpen(true);
|
// delta: 150,
|
||||||
},
|
// });
|
||||||
delta: 150,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<SEO
|
<SEO
|
||||||
coverURL={props.frontMatter.coverURL ?? Config.AvatarURL}
|
coverURL={props.frontMatter.coverURL}
|
||||||
description={props.frontMatter.summary}
|
description={props.frontMatter.summary}
|
||||||
title={`${props.frontMatter.title} - ${Config.SiteTitle}`}
|
title={`${titleCase(props.frontMatter.title)} - ${Config.SiteTitle}`}
|
||||||
/>
|
/>
|
||||||
<Toaster />
|
<Toaster />
|
||||||
<NavBar />
|
<NavBar />
|
||||||
<ContentContainer>
|
<ContentContainer>
|
||||||
<div
|
<div className="flex justify-center py-5">
|
||||||
className={`py-1 ${isTOCLongEnough ? "justify-between" : "justify-center"} space-x-5 lg:flex`}
|
<div className="typesetting" style={{ width: "min(50rem,100%)" }}>
|
||||||
style={{ borderRadius: "5px" }}
|
{props.frontMatter.coverURL && <PostCover coverURL={props.frontMatter.coverURL} />}
|
||||||
>
|
<div className="border-black border-b-2 pb-1 dark:border-gray-300">
|
||||||
<div className={`${isTOCLongEnough ? "lg:w-2/3" : "lg:w-5/6"} py-5`}>
|
<div
|
||||||
<div className="typesetting">
|
className={
|
||||||
{props.frontMatter.coverURL && <PostCover coverURL={props.frontMatter.coverURL} />}
|
"caption-font my-2 flex justify-center whitespace-normal break-words font-bold text-3xl text-black dark:text-white"
|
||||||
<div className="border-black border-b-2 pb-1 dark:border-gray-300">
|
}
|
||||||
<div
|
>
|
||||||
|
{props.frontMatter?.title}
|
||||||
|
</div>
|
||||||
|
{props.frontMatter?.subtitle && (
|
||||||
|
<div className={"my-1 flex justify-center font-bold text-xl content-font"}>
|
||||||
|
{props.frontMatter.subtitle}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="my-1 flex justify-center text-sm italic">{normalizeDate(props.frontMatter?.time)}</div>
|
||||||
|
{props.frontMatter?.summary && (
|
||||||
|
<p
|
||||||
className={
|
className={
|
||||||
"caption-font my-2 flex justify-center whitespace-normal break-words font-bold text-3xl text-black capitalize dark:text-white"
|
"my-4 border-gray-400 border-l-4 bg-gray-100 py-5 pr-2 pl-5 text-[16px] text-gray-800 content-font dark:border-gray-600 dark:bg-gray-900 dark:text-gray-300"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{props.frontMatter?.title}
|
{props.frontMatter?.summary}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{props.frontMatter.tags && (
|
||||||
|
<div className={"flex flex-wrap border-black border-t-2 pt-1 dark:border-gray-300"}>
|
||||||
|
{props.frontMatter.tags.map((tagName) => (
|
||||||
|
<Link
|
||||||
|
className="not-prose my-1 mr-2 border-2 border-black px-2 py-1 font-bold text-gray-700 text-xs hover:text-black dark:border-gray-300 dark:text-gray-300 dark:hover:text-gray-200"
|
||||||
|
href={`/tags/${tagName}`}
|
||||||
|
key={`tags-${nanoid()}`}
|
||||||
|
>
|
||||||
|
{tagName}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
{props.frontMatter?.subtitle && (
|
)}
|
||||||
<div className={"caption-font my-1 flex justify-center font-bold text-xl capitalize"}>
|
</div>
|
||||||
{props.frontMatter.subtitle}
|
<div
|
||||||
</div>
|
className={`text-wrap border-gray-500 content-font ${!props.frontMatter.allowShare ? "select-none" : ""}`}
|
||||||
)}
|
// {...handleLeftSwipe}
|
||||||
<div className="my-1 flex justify-center text-sm italic">{normalizeDate(props.frontMatter?.time)}</div>
|
>
|
||||||
{props.frontMatter?.summary && (
|
{compiledSource && (
|
||||||
<p className={"my-4 indent-8 text-gray-800 content-font dark:text-gray-300"}>
|
<MDXRemote
|
||||||
{props.frontMatter?.summary}
|
compiledSource={compiledSource.compiledSource}
|
||||||
</p>
|
// @ts-ignore
|
||||||
)}
|
components={MDXComponentsSet}
|
||||||
{props.frontMatter.tags && (
|
frontmatter={compiledSource.frontmatter}
|
||||||
<div className={"flex flex-wrap border-black border-t-2 pt-1 dark:border-gray-300"}>
|
scope={compiledSource.scope}
|
||||||
{props.frontMatter.tags.map((tagName) => (
|
/>
|
||||||
<Link
|
)}
|
||||||
className="not-prose my-1 mr-2 border-2 border-black px-2 py-1 font-bold text-gray-700 text-xs hover:text-black dark:border-gray-300 dark:text-gray-300 dark:hover:text-gray-200"
|
|
||||||
href={`/tags/${tagName}`}
|
|
||||||
key={`tags-${nanoid()}`}
|
|
||||||
>
|
|
||||||
{tagName}
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`text-wrap border-gray-500 content-font ${
|
|
||||||
!props.frontMatter.allowShare ? "select-none" : ""
|
|
||||||
}`}
|
|
||||||
{...handleRightSwipe}
|
|
||||||
>
|
|
||||||
{compiledSource && (
|
|
||||||
<MDXRemote
|
|
||||||
compiledSource={compiledSource.compiledSource}
|
|
||||||
// @ts-ignore
|
|
||||||
components={MDXComponentsSet}
|
|
||||||
frontmatter={compiledSource.frontmatter}
|
|
||||||
scope={compiledSource.scope}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<Separator />
|
<Separator />
|
||||||
<BottomCard />
|
{/* <BottomCard /> */}
|
||||||
<Separator />
|
<Separator />
|
||||||
<ShareButtons
|
<ShareButtons
|
||||||
allowShare={props.frontMatter.allowShare}
|
allowShare={props.frontMatter.allowShare}
|
||||||
@@ -161,19 +153,8 @@ const ReaderPage = (props: ReaderPageProps) => {
|
|||||||
</ul>
|
</ul>
|
||||||
{Config.Giscus?.enabled && <PostComments postId={props.postId} />}
|
{Config.Giscus?.enabled && <PostComments postId={props.postId} />}
|
||||||
</div>
|
</div>
|
||||||
{isTOCLongEnough && (
|
|
||||||
<div className="hidden py-5 md:w-1/3 lg:block">
|
|
||||||
<div className="sticky top-[5em]">
|
|
||||||
<TOC data={props.tocList} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{isTOCLongEnough && (
|
{isTOCLongEnough && <DrawerTOC data={props.tocList} />}
|
||||||
<div className="lg:hidden">
|
|
||||||
<DrawerTOC data={props.tocList} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</ContentContainer>
|
</ContentContainer>
|
||||||
<Footer />
|
<Footer />
|
||||||
</Page>
|
</Page>
|
||||||
@@ -209,6 +190,7 @@ export const getStaticProps: GetStaticProps<ReaderPageProps> = async (context) =
|
|||||||
remarkPlugins: [externalLinks, remarkMath, remarkGfm],
|
remarkPlugins: [externalLinks, remarkMath, remarkGfm],
|
||||||
rehypePlugins: [
|
rehypePlugins: [
|
||||||
rehypeRaw,
|
rehypeRaw,
|
||||||
|
|
||||||
rehypeKatex as any,
|
rehypeKatex as any,
|
||||||
rehypeAutolinkHeadings,
|
rehypeAutolinkHeadings,
|
||||||
rehypeSlug,
|
rehypeSlug,
|
||||||
|
|||||||
@@ -5,58 +5,63 @@
|
|||||||
overflow-x-hidden
|
overflow-x-hidden
|
||||||
break-words
|
break-words
|
||||||
px-0
|
px-0
|
||||||
|
dark:prose-invert
|
||||||
dark:prose-invert
|
|
||||||
|
|
||||||
prose-headings:scroll-mt-20
|
prose-headings:scroll-mt-20
|
||||||
|
|
||||||
prose-a:text-sky-800
|
prose-a:text-sky-800
|
||||||
|
|
||||||
prose-a:decoration-dashed
|
prose-a:decoration-dashed
|
||||||
prose-a:underline-offset-[5px]
|
prose-a:underline-offset-[5px]
|
||||||
|
|
||||||
prose-figure:mx-auto
|
prose-figure:mx-auto
|
||||||
|
|
||||||
|
prose-strong:font-semibold
|
||||||
|
|
||||||
prose-code:mx-1
|
prose-code:mx-1
|
||||||
prose-code:overflow-hidden
|
|
||||||
|
prose-code:overflow-hidden
|
||||||
prose-code:rounded-md
|
prose-code:rounded-md
|
||||||
|
|
||||||
prose-code:bg-gray-100
|
prose-code:bg-gray-100
|
||||||
|
|
||||||
prose-code:px-2
|
prose-code:px-2
|
||||||
prose-code:py-1
|
prose-code:py-1
|
||||||
prose-code:text-sky-700
|
prose-code:text-sky-700
|
||||||
prose-code:before:content-['']
|
prose-code:before:content-['']
|
||||||
prose-code:after:content-['']
|
prose-code:after:content-['']
|
||||||
|
prose-li:my-0
|
||||||
prose-li:marker:text-black
|
prose-li:marker:text-black
|
||||||
prose-table:mb-5
|
prose-table:mb-5
|
||||||
|
prose-table:mt-0
|
||||||
prose-table:mt-0
|
|
||||||
|
|
||||||
prose-table:border-2
|
prose-table:border-2
|
||||||
prose-table:border-gray-400
|
prose-table:border-gray-400
|
||||||
prose-tr:border-2
|
|
||||||
prose-tr:border-gray-400
|
|
||||||
|
|
||||||
|
prose-tr:border-2
|
||||||
|
|
||||||
|
prose-tr:border-gray-400
|
||||||
prose-tr:p-2
|
prose-tr:p-2
|
||||||
prose-th:border-2
|
prose-th:border-2
|
||||||
prose-th:border-gray-400
|
prose-th:border-gray-400
|
||||||
|
|
||||||
prose-th:bg-gray-100
|
prose-th:bg-gray-100
|
||||||
prose-th:p-2
|
prose-th:p-2
|
||||||
prose-td:border-2
|
prose-td:border-2
|
||||||
prose-td:border-gray-400
|
|
||||||
prose-td:p-2
|
prose-td:border-gray-400
|
||||||
|
prose-td:p-2
|
||||||
|
prose-img:mx-auto
|
||||||
|
prose-hr:my-6
|
||||||
|
prose-hr:border-gray-300
|
||||||
|
|
||||||
prose-img:mx-auto
|
|
||||||
dark:prose-a:text-sky-500
|
dark:prose-a:text-sky-500
|
||||||
prose-code:dark:bg-gray-800
|
prose-code:dark:bg-gray-800
|
||||||
dark:prose-code:text-sky-500
|
dark:prose-code:text-sky-500
|
||||||
|
|
||||||
dark:prose-li:marker:text-gray-100
|
dark:prose-li:marker:text-gray-100
|
||||||
|
|
||||||
dark:prose-table:border-gray-700
|
dark:prose-table:border-gray-700
|
||||||
|
|
||||||
dark:prose-tr:border-gray-700
|
dark:prose-tr:border-gray-700
|
||||||
dark:prose-th:border-gray-700
|
dark:prose-th:border-gray-700
|
||||||
dark:prose-th:bg-gray-900
|
dark:prose-th:bg-gray-900
|
||||||
dark:prose-td:border-gray-700;
|
dark:prose-td:border-gray-700
|
||||||
|
prose-hr:dark:border-gray-600;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export type TConfig = {
|
|||||||
twitter?: string;
|
twitter?: string;
|
||||||
bilibili?: string;
|
bilibili?: string;
|
||||||
weibo?: string;
|
weibo?: string;
|
||||||
|
quora?: string;
|
||||||
reddit?: string;
|
reddit?: string;
|
||||||
facebook?: string;
|
facebook?: string;
|
||||||
instagram?: string;
|
instagram?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user