diff --git a/components/about-page/Introduction.tsx b/components/about-page/Introduction.tsx new file mode 100644 index 0000000..613e043 --- /dev/null +++ b/components/about-page/Introduction.tsx @@ -0,0 +1,19 @@ +export const Introduction = () => { + return ( +
+
+ my-profile +
+
+
Hi, there👋
I am a student / entrepreneur / engineer (Your + profession) majoring in (Your Research Field) born in XXXX (Your birth year) +
+
+ My main research interests includes XXXX +
+
+ Additionally, I am also interested in XXXX. +
+
+ ); +}; diff --git a/components/about-page/PersonalStatus.tsx b/components/about-page/PersonalStatus.tsx new file mode 100644 index 0000000..62064b4 --- /dev/null +++ b/components/about-page/PersonalStatus.tsx @@ -0,0 +1,30 @@ +import { Config } from "@/data/config"; +import Link from "next/link"; + +export const PersonalStatus = () => { + return ( + + ); +}; diff --git a/components/friend-links-page/FriendLinksList.tsx b/components/friend-links-page/FriendLinksList.tsx new file mode 100644 index 0000000..6a2c9b1 --- /dev/null +++ b/components/friend-links-page/FriendLinksList.tsx @@ -0,0 +1,29 @@ +import { Separator } from "@/components/ui/separator"; +import { Config } from "@/data/config"; +import { FriendsList } from "@/data/friends"; +import type { TFriendItem } from "@/types/friend.type"; +import { nanoid } from "nanoid"; +import Link from "next/link"; + +export const FriendLinkList = (props: { friends: TFriendItem[] }) => { + return ( +
+
+ {FriendsList.map((item) => ( + + {item.title} + + ))} +
+ +
+
+ {"Welcome to exchange our friend links and every high-quality blog websites are welcomed. "} + + {"Email me please"} + +
+
+
+ ); +}; diff --git a/components/post-list-page/TagsList.tsx b/components/post-list-page/TagsList.tsx new file mode 100644 index 0000000..6656412 --- /dev/null +++ b/components/post-list-page/TagsList.tsx @@ -0,0 +1,29 @@ +import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@/components/ui/accordion"; +import { Separator } from "@/components/ui/separator"; +import Link from "next/link"; +import { nanoid } from "nanoid"; +import type { TTagListItem } from "@/types/docs.type"; + +export const TagsList = (props: { tagsList: TTagListItem[] }) => { + return ( + + + {"TAG FILTER"} + + +
+ {props.tagsList.map((item) => ( + + {`${item.name} (${item.count})`} + + ))} +
+
+
+
+ ); +}; diff --git a/components/reader-page/BottomCard.tsx b/components/reader-page/BottomCard.tsx index 4884fa3..cabb77c 100644 --- a/components/reader-page/BottomCard.tsx +++ b/components/reader-page/BottomCard.tsx @@ -1,10 +1,14 @@ +import seal from "@/assets/icons/seal.svg"; import { Config } from "@/data/config"; export const BottomCard = () => { return ( -
- {Config.AuthorName} -

{Config.Sentence}

+
+
+

{Config.Sentence}

); }; diff --git a/components/reader-page/DrawerTOC.tsx b/components/reader-page/DrawerTOC.tsx index a7a67d5..cd0bf30 100644 --- a/components/reader-page/DrawerTOC.tsx +++ b/components/reader-page/DrawerTOC.tsx @@ -1,12 +1,12 @@ import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet"; import { useActiveHeading } from "@/hooks/useActiveHeading"; import useDrawerTOCState from "@/stores/useDrawerTOCState"; -import type { TTOCItem } from "@/types/docs.type"; +import type { TPostTOCItem } from "@/types/docs.type"; import Link from "next/link"; import { MdMenuBook } from "react-icons/md"; import { twMerge } from "tailwind-merge"; -export const DrawerTOC = (props: { data: TTOCItem[] }) => { +export const DrawerTOC = (props: { data: TPostTOCItem[] }) => { const isTOCOpen = useDrawerTOCState((state) => state.isOpen); const setIsTOCOpen = useDrawerTOCState((state) => state.changeDrawerTOCOpen); const activeId = useActiveHeading(props.data.map((item) => `#${item.anchorId}`)); @@ -16,13 +16,18 @@ export const DrawerTOC = (props: { data: TTOCItem[] }) => { className="fixed right-5 bottom-16 border border-gray-700 bg-white shadow-xl dark:border-gray-500 dark:bg-black" title="Open the table of contents" > -
setIsTOCOpen(!isTOCOpen)} title="Open the table of contents"> +
setIsTOCOpen(!isTOCOpen)} + onKeyDown={() => {}} + title="Open the table of contents" + >
- + - {"TABLE OF CONTENTS"} + {"TABLE OF CONTENTS"}
    {props.data?.map((item) => ( diff --git a/components/reader-page/MorePostLinks.tsx b/components/reader-page/MorePostLinks.tsx new file mode 100644 index 0000000..b6cd7ca --- /dev/null +++ b/components/reader-page/MorePostLinks.tsx @@ -0,0 +1,26 @@ +import type { TPostListItem } from "@/types/docs.type"; +import Link from "next/link"; + +export const MorePostLinks = (props: { + prevPostListItem: TPostListItem | null; + nextPostListItem: TPostListItem | null; +}) => { + return ( +
      + {props.prevPostListItem && ( +
    • + + {props.prevPostListItem?.frontMatter.title} + +
    • + )} + {props.nextPostListItem && ( +
    • + + {props.nextPostListItem?.frontMatter.title} + +
    • + )} +
    + ); +}; diff --git a/components/reader-page/PostComments.tsx b/components/reader-page/PostComments.tsx index 652153d..6d19e59 100644 --- a/components/reader-page/PostComments.tsx +++ b/components/reader-page/PostComments.tsx @@ -11,7 +11,6 @@ export const PostComments = (props: { postId: string }) => { category={Config.Giscus.category} categoryId={Config.Giscus.categoryId} emitMetadata="0" - id={props.postId} inputPosition="top" lang="en" loading="eager" diff --git a/components/reader-page/PostCover.tsx b/components/reader-page/PostCover.tsx index 5e3a493..5f43258 100644 --- a/components/reader-page/PostCover.tsx +++ b/components/reader-page/PostCover.tsx @@ -3,7 +3,7 @@ export const PostCover = (props: { coverURL: string }) => {
    { + const compiledSource = props.compiledSource; + return ( +
    +
    +
    + {props.frontMatter?.title} +
    + {props.frontMatter?.subtitle && ( +
    {props.frontMatter.subtitle}
    + )} +
    {normalizeDate(props.frontMatter?.time)}
    + {props.frontMatter?.summary && ( +

    + {props.frontMatter?.summary} +

    + )} + {props.frontMatter.tags && ( +
    + {props.frontMatter.tags.map((tagName) => ( + + {tagName} + + ))} +
    + )} +
    +
    + {compiledSource && ( + + )} +
    +
    + ); +}; diff --git a/components/reader-page/TOC.tsx b/components/reader-page/TOC.tsx index 14617b2..610efd7 100644 --- a/components/reader-page/TOC.tsx +++ b/components/reader-page/TOC.tsx @@ -1,13 +1,13 @@ import { useActiveHeading } from "@/hooks/useActiveHeading"; -import type { TTOCItem } from "@/types/docs.type"; +import type { TPostTOCItem } from "@/types/docs.type"; import Link from "next/link"; import { twMerge } from "tailwind-merge"; -export const TOC = (props: { data: TTOCItem[] }) => { +export const TOC = (props: { data: TPostTOCItem[] }) => { const activeId = useActiveHeading(props.data.map((item) => `#${item.anchorId}`)); return ( -
    +
    {"TABLE OF CONTENTS"}
    diff --git a/components/search-page/SearchInput.tsx b/components/search-page/SearchInput.tsx new file mode 100644 index 0000000..1de7b5f --- /dev/null +++ b/components/search-page/SearchInput.tsx @@ -0,0 +1,43 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { isEmptyString } from "@/lib/utils"; +import { type ChangeEvent, type KeyboardEvent, useEffect, useState } from "react"; + +export const SearchInput = (props: { + handleSearch: (word: string) => any; + isLoading: boolean; + word?: string | null; +}) => { + const [searchText, setSearchText] = useState(props.word ?? ""); + + useEffect(() => { + if (!isEmptyString(searchText)) { + props.handleSearch(searchText); + } + }, []); + + const handleInputSearchText = (event: ChangeEvent) => { + setSearchText(event.target.value); + }; + + const handleEnterKeySearch = (event: KeyboardEvent) => { + if (event.key === "Go" || event.key === "Enter") { + props.handleSearch(searchText); + } + }; + + return ( +
    + + +
    + ); +}; diff --git a/components/search-page/SearchResultList.tsx b/components/search-page/SearchResultList.tsx new file mode 100644 index 0000000..475abd2 --- /dev/null +++ b/components/search-page/SearchResultList.tsx @@ -0,0 +1,41 @@ +import type { TSearchResultItem } from "@/types/docs.type"; +import { nanoid } from "nanoid"; +import Link from "next/link"; + +export const SearchResultList = (props: { + searchResult: TSearchResultItem[]; +}) => { + return ( +
    +
    +
    + {props.searchResult.map((item, index) => ( + +
    +
    {item.title}
    + {item.summary &&
    {item.summary}
    } +
    +
    + {item.tags?.map((tagitem) => ( +
    + {tagitem} +
    + ))} +
    + + ))} +
    +
    +
    +

    {"For search efficiency, only the first 20 results are displayed."}

    +
    +
    + ); +}; diff --git a/components/utils/PageTitle.tsx b/components/utils/PageTitle.tsx new file mode 100644 index 0000000..4594a05 --- /dev/null +++ b/components/utils/PageTitle.tsx @@ -0,0 +1,12 @@ +import { twMerge } from "tailwind-merge"; + +export const PageTitle = (props: { + children?: React.ReactNode; + classNames?: string; +}) => { + return ( +

    + {props.children} +

    + ); +}; diff --git a/components/utils/Pagination.tsx b/components/utils/Pagination.tsx new file mode 100644 index 0000000..a0914d5 --- /dev/null +++ b/components/utils/Pagination.tsx @@ -0,0 +1,63 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { type ChangeEvent, type KeyboardEvent, useState } from "react"; +import { MdNavigateBefore, MdNavigateNext } from "react-icons/md"; + +export const Pagination = (props: { + pageNumber: number; + pageAmount: number; + onGotoNextPage: (nextPage: number) => any; + onGotoPrevPage: (prevPage: number) => any; + onJumpToSpecPage: (pageNum: number) => any; +}) => { + const [pageNumberInput, setPageNumberInput] = useState(props.pageNumber.toString()); + + const handleEnterKeyJump = (event: KeyboardEvent) => { + setPageNumberInput(pageNumberInput.replace(/[^\d]/g, "")); + if (Number.parseInt(pageNumberInput) > 0 && Number.parseInt(pageNumberInput) < props.pageAmount + 1) { + (event.key === "Go" || event.key === "Enter") && props.onJumpToSpecPage(Number.parseInt(pageNumberInput)); + return; + } + }; + + const handleInputPageNumber = (event: ChangeEvent) => { + setPageNumberInput(event.target.value); + }; + + return ( +
    + {props.pageNumber !== 1 && ( + + )} +
    + +
    {` / ${props.pageAmount}`}
    +
    + {props.pageNumber !== props.pageAmount && ( + + )} +
    + ); +}; diff --git a/components/utils/PostList.tsx b/components/utils/PostList.tsx index 2fa0d0e..9f573d4 100644 --- a/components/utils/PostList.tsx +++ b/components/utils/PostList.tsx @@ -37,7 +37,7 @@ export const PostList = (props: { data: TPostListItem[] }) => {
    {postItem.frontMatter.tags && (
    - {postItem.frontMatter.tags.map((tagName) => ( + {postItem.frontMatter.tags.map((tagName: string) => ( { - item.frontMatter.tags?.forEach((tagName) => { + item.frontMatter.tags?.forEach((tagName: string) => { if (postsByTag[tagName] == null) { postsByTag[tagName] = []; } diff --git a/lib/rss.tsx b/lib/rss.tsx index cfe7232..2d87a48 100644 --- a/lib/rss.tsx +++ b/lib/rss.tsx @@ -65,7 +65,7 @@ export const generateRSSFeed = async () => { for (let i = 0; i < Math.min(LatestPostCountInHomePage, sortedPosts.allPostList.length); i++) { const post = sortedPosts.allPostList[i]; const postFileContent = `${getPostFileContent(post.id)}${NoticeForRSSReaders(post.id)}`; - const dateNumber = post.frontMatter.time.split("-").map((num) => Number.parseInt(num)); + const dateNumber = post.frontMatter.time.split("-").map((num: string) => Number.parseInt(num)); const mdxSource = await serialize(postFileContent ?? "", { parseFrontmatter: true, mdxOptions: { @@ -89,7 +89,9 @@ export const generateRSSFeed = async () => { link: `https://${Config.SiteDomain}/about`, }, ], - category: post.frontMatter.tags?.map((tagname) => ({ name: tagname })), + category: post.frontMatter.tags?.map((tagname: string) => ({ + name: tagname, + })), date: new Date(dateNumber[0], dateNumber[1], dateNumber[2]), image: post.frontMatter.coverURL ?? undefined, }); diff --git a/lib/toc.ts b/lib/toc.ts index d1e6b4e..68c170a 100644 --- a/lib/toc.ts +++ b/lib/toc.ts @@ -1,4 +1,4 @@ -import type { TTOCItem } from "@/types/docs.type"; +import type { TPostTOCItem } from "@/types/docs.type"; import { JSDOM } from "jsdom"; /** @@ -10,7 +10,7 @@ import { JSDOM } from "jsdom"; export const makeTOCTree = (htmlCode: string) => { const doc_dom = new JSDOM(htmlCode); const all_headers = doc_dom.window.document.querySelectorAll("h1,h2,h3,h4,h5,h6"); - const result: TTOCItem[] = []; + const result: TPostTOCItem[] = []; for (let i = 0; i < all_headers.length; i++) { const level = Number.parseInt(all_headers[i].tagName.replace("H", "")); result.push({ diff --git a/pages/404.tsx b/pages/404.tsx index 2aa88ae..653d97c 100644 --- a/pages/404.tsx +++ b/pages/404.tsx @@ -3,6 +3,7 @@ import { Separator } from "@/components/ui/separator"; import { Footer } from "@/components/utils/Footer"; import { ContentContainer, Page } from "@/components/utils/Layout"; import { NavBar } from "@/components/utils/NavBar"; +import { PageTitle } from "@/components/utils/PageTitle"; import { TfiFaceSad } from "react-icons/tfi"; export default function NotFoundPage() { @@ -14,7 +15,7 @@ export default function NotFoundPage() { -

    {"404 NOT FOUND"}

    + {"404 NOT FOUND"}
    diff --git a/pages/500.tsx b/pages/500.tsx index 0257a9d..04bed27 100644 --- a/pages/500.tsx +++ b/pages/500.tsx @@ -3,6 +3,7 @@ import { Separator } from "@/components/ui/separator"; import { Footer } from "@/components/utils/Footer"; import { ContentContainer, Page } from "@/components/utils/Layout"; import { NavBar } from "@/components/utils/NavBar"; +import { PageTitle } from "@/components/utils/PageTitle"; import { MdOutlineDangerous } from "react-icons/md"; export default function ServerErrorPage() { @@ -14,7 +15,7 @@ export default function ServerErrorPage() { -

    {"INVALID OPERATION"}

    + {"INVALID OPERATION"}
    diff --git a/pages/about.tsx b/pages/about.tsx index 244fbdc..4b0d40b 100644 --- a/pages/about.tsx +++ b/pages/about.tsx @@ -1,7 +1,9 @@ +import { Introduction } from "@/components/about-page/Introduction"; import { Separator } from "@/components/ui/separator"; import { Footer } from "@/components/utils/Footer"; import { ContentContainer, Page } from "@/components/utils/Layout"; import { NavBar } from "@/components/utils/NavBar"; +import { PageTitle } from "@/components/utils/PageTitle"; import { SEO } from "@/components/utils/SEO"; import { SocialIcons } from "@/components/utils/SocialIcons"; import { Config } from "@/data/config"; @@ -18,23 +20,9 @@ export default function AboutPage() { /> -

    {"ABOUT ME"}

    + {"ABOUT ME"} -
    -
    - my-profile -
    -
    -
    Hi, there👋
    I am a student / entrepreneur / engineer - (Your profession) majoring in (Your Research Field) born in XXXX (Your birth year) -
    -
    - My main research interests includes XXXX -
    -
    - Additionally, I am also interested in XXXX. -
    -
    + diff --git a/pages/blog/[id].tsx b/pages/blog/[id].tsx index 843c3d5..cc3c2e5 100644 --- a/pages/blog/[id].tsx +++ b/pages/blog/[id].tsx @@ -1,7 +1,8 @@ -import { MDXComponentsSet } from "@/components/mdx"; import { DrawerTOC } from "@/components/reader-page/DrawerTOC"; +import { MorePostLinks } from "@/components/reader-page/MorePostLinks"; import { PostComments } from "@/components/reader-page/PostComments"; import { PostCover } from "@/components/reader-page/PostCover"; +import { PostRender } from "@/components/reader-page/PostRender"; import { ShareButtons } from "@/components/reader-page/ShareButtons"; import { Separator } from "@/components/ui/separator"; import { Toaster } from "@/components/ui/toaster"; @@ -10,16 +11,12 @@ import { ContentContainer, Page } from "@/components/utils/Layout"; import { NavBar } from "@/components/utils/NavBar"; import { SEO } from "@/components/utils/SEO"; import { Config } from "@/data/config"; -import { normalizeDate } from "@/lib/date"; import { getPostFileContent, sortedPosts } from "@/lib/post-process"; import { makeTOCTree } from "@/lib/toc"; -import type { TPostFrontmatter } from "@/types/frontmatter.type"; -import type { TPostListItem, TTOCItem } from "@/types/docs.type"; -import { nanoid } from "nanoid"; +import type { TPostFrontmatter, TPostListItem, TPostTOCItem } from "@/types/docs.type"; import type { GetStaticPaths, GetStaticProps } from "next"; import { MDXRemote, type MDXRemoteSerializeResult } from "next-mdx-remote"; import { serialize } from "next-mdx-remote/serialize"; -import Link from "next/link"; import { renderToString } from "react-dom/server"; import rehypeAutolinkHeadings from "rehype-autolink-headings"; import rehypeHighlight from "rehype-highlight"; @@ -34,7 +31,7 @@ import { titleCase } from "title-case"; type ReaderPageProps = { compiledSource: MDXRemoteSerializeResult; - tocList: TTOCItem[]; + tocList: TPostTOCItem[]; frontMatter: TPostFrontmatter; postId: string; nextPostListItem: TPostListItem | null; @@ -42,9 +39,6 @@ type ReaderPageProps = { }; const ReaderPage = (props: ReaderPageProps) => { - const compiledSource = props.compiledSource; - // const setIsTOCOpen = useDrawerTOCState((state) => state.changeDrawerTOCOpen); - // Only the TOC length reaches 3 can be displayed. // In order to avoid large blank spaces that ruin the visual perception const isTOCLongEnough = props.tocList.length > 2; @@ -63,97 +57,29 @@ const ReaderPage = (props: ReaderPageProps) => { -
    -
    - {props.frontMatter.coverURL && } -
    -
    - {props.frontMatter?.title} -
    - {props.frontMatter?.subtitle && ( -
    - {props.frontMatter.subtitle} -
    - )} -
    {normalizeDate(props.frontMatter?.time)}
    - {props.frontMatter?.summary && ( -

    - {props.frontMatter?.summary} -

    - )} - {props.frontMatter.tags && ( -
    - {props.frontMatter.tags.map((tagName) => ( - - {tagName} - - ))} -
    - )} -
    -
    - {compiledSource && ( - - )} -
    - - {/* */} - - - -
      - {props.prevPostListItem && ( -
    • - - {props.prevPostListItem?.frontMatter.title} - -
    • - )} - {props.nextPostListItem && ( -
    • - - {props.nextPostListItem?.frontMatter.title} - -
    • - )} -
    - {Config.Giscus?.enabled && } -
    +
    + {props.frontMatter.coverURL && } + + + + + + {Config.Giscus?.enabled && } + {isTOCLongEnough && }
    - {isTOCLongEnough && }