[update] migrate the project formatter from prettier and eslint to biome

This commit is contained in:
PrinOrange
2024-08-14 12:57:22 +08:00
parent 009be6e7d9
commit 81de437888
61 changed files with 480 additions and 3865 deletions

View File

@@ -1,8 +0,0 @@
{
"extends": ["next/core-web-vitals"],
"rules": {
"@next/next/no-img-element": "off",
"react/jsx-uses-vars": "error",
"react/jsx-sort-props": 2
}
}

View File

@@ -1,3 +0,0 @@
*.woff2
*.woff2
*.ttf

View File

@@ -1,6 +0,0 @@
{
"printWidth": 120,
"endOfLine": "auto",
"trailingComma": "all",
"plugins": ["prettier-plugin-tailwindcss", "prettier-plugin-organize-imports", "react"]
}

39
biome.json Normal file
View File

@@ -0,0 +1,39 @@
{
"$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
"files": {
"ignore": [".next", "VSCodeCounter", ".turbo", "node_modules"]
},
"formatter": {
"indentStyle": "space",
"lineWidth": 120
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"a11y": {
"useKeyWithClickEvents": "off"
},
"complexity": {
"noForEach": "off"
},
"correctness": {
"useExhaustiveDependencies": "off"
},
"suspicious": {
"noExplicitAny": "off"
},
"style": {
"noParameterAssign": "off",
"noNonNullAssertion": "off",
"useNodejsImportProtocol": "off"
},
"nursery": {
"useSortedClasses": "error"
},
"recommended": true
}
}
}

View File

@@ -6,7 +6,7 @@ export const HomeCover = () => {
<> <>
<div className="w-full"> <div className="w-full">
<div <div
className="mb-20 mt-5 flex w-full justify-center rounded-xl" className="mt-5 mb-20 flex w-full justify-center rounded-xl"
style={{ style={{
aspectRatio: "4/1", aspectRatio: "4/1",
background: `url(${Config.PageCovers.websiteCoverURL})`, background: `url(${Config.PageCovers.websiteCoverURL})`,
@@ -20,10 +20,10 @@ export const HomeCover = () => {
/> />
</div> </div>
</div> </div>
<div className={`caption-font my-8 text-center text-4xl font-bold`}>{Config.Nickname}</div> <div className={"caption-font my-8 text-center font-bold text-4xl"}>{Config.Nickname}</div>
{Config.Sentence && ( {Config.Sentence && (
<div className="my-5 flex justify-center"> <div className="my-5 flex justify-center">
<p className={`content-font text-lg`}>{Config.Sentence}</p> <p className={"text-lg content-font"}>{Config.Sentence}</p>
</div> </div>
)} )}
<div className="my-8"> <div className="my-8">

View File

@@ -3,5 +3,5 @@ export const Page = ({ children }: { children: React.ReactNode }) => {
}; };
export const ContentContainer = ({ children }: { children: React.ReactNode }) => { export const ContentContainer = ({ children }: { children: React.ReactNode }) => {
return <main className="px-5 md:px-10 lg:px-20 xl:px-32 2xl:px-52 flex-grow">{children}</main>; return <main className="flex-grow px-5 md:px-10 lg:px-20 xl:px-32 2xl:px-52">{children}</main>;
}; };

View File

@@ -2,7 +2,7 @@ const Blockquote = (props: JSX.IntrinsicElements["blockquote"]) => {
return ( return (
<blockquote <blockquote
className={ className={
"not-prose scroll-mt-20 my-5 px-5 py-4 bg-gray-100 dark:bg-gray-800 dark:border-gray-700 border-gray-300 border-l-4" "not-prose my-5 scroll-mt-20 border-gray-300 border-l-4 bg-gray-100 px-5 py-4 dark:border-gray-700 dark:bg-gray-800"
} }
> >
{props.children} {props.children}

View File

@@ -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 scroll-mt-20"} id={props.id}>
{props.children} {props.children}
</h2> </h2>
); );

View File

@@ -2,9 +2,9 @@
// but all the attributes of the img tag. // but all the attributes of the img tag.
const ImageWrapper = (props: JSX.IntrinsicElements["img"]) => { const ImageWrapper = (props: JSX.IntrinsicElements["img"]) => {
return ( return (
<div className="flex flex-col my-5"> <div className="my-5 flex flex-col">
<img alt={props.alt} className="mx-auto my-0" src={props.src} /> <img alt={props.alt} className="mx-auto my-0" src={props.src} />
<div className="mx-auto my-1 text-sm text-gray-500 dark:text-gray-300">{props.alt}</div> <div className="mx-auto my-1 text-gray-500 text-sm dark:text-gray-300">{props.alt}</div>
</div> </div>
); );
}; };

View File

@@ -23,7 +23,7 @@ const PreWrapper = ({ children }: { children: JSX.Element }) => {
return ( return (
<div <div
className="relative flat-scrollbar-normal" className="flat-scrollbar-normal relative"
dir="ltr" dir="ltr"
onMouseLeave={onExit} onMouseLeave={onExit}
onMouseMove={onEnter} onMouseMove={onEnter}
@@ -32,14 +32,14 @@ const PreWrapper = ({ children }: { children: JSX.Element }) => {
{hovered && ( {hovered && (
<Button <Button
aria-label="Copy code" aria-label="Copy code"
className={`absolute right-2 top-2 h-8 w-8 rounded p-1 ${copied ? "hover:text-green-500 text-green-500" : ""}`} className={`absolute top-2 right-2 h-8 w-8 rounded p-1 ${copied ? "text-green-500 hover:text-green-500" : ""}`}
onClick={onCopy} onClick={onCopy}
variant={"outline"} variant={"outline"}
> >
{copied ? <FaCheck /> : <IoCopyOutline />} {copied ? <FaCheck /> : <IoCopyOutline />}
</Button> </Button>
)} )}
<pre className="p-2 dark:bg-[#0d1117] bg-[#F6F8FA] rounded-md flat-scrollbar-normal not-prose text-sm dark:selection:bg-gray-700 selection:bg-gray-300 selection:text-inherit"> <pre className="flat-scrollbar-normal not-prose rounded-md bg-[#F6F8FA] p-2 text-sm selection:bg-gray-300 selection:text-inherit dark:bg-[#0d1117] dark:selection:bg-gray-700">
{children} {children}
</pre> </pre>
</div> </div>

View File

@@ -1,6 +1,6 @@
const TableWrapper = ({ children }: { children: React.ReactNode }) => { const TableWrapper = ({ children }: { children: React.ReactNode }) => {
return ( return (
<div className="w-full overflow-x-auto flat-scrollbar-normal"> <div className="flat-scrollbar-normal w-full overflow-x-auto">
<table>{children}</table> <table>{children}</table>
</div> </div>
); );

View File

@@ -2,8 +2,8 @@ import { Config } from "@/data/config";
export const BottomCard = () => { export const BottomCard = () => {
return ( return (
<div className="p-8 w-full flex flex-col justify-center"> <div className="flex w-full flex-col justify-center p-8">
<img alt={Config.AuthorName} className="h-24 w-24 rounded-full mx-auto" src={Config.AvatarURL} /> <img alt={Config.AuthorName} className="mx-auto h-24 w-24 rounded-full" src={Config.AvatarURL} />
<p className="mx-auto mt-5 content-font">{Config.Sentence}</p> <p className="mx-auto mt-5 content-font">{Config.Sentence}</p>
</div> </div>
); );

View File

@@ -1,7 +1,7 @@
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet"; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
import { useActiveHeading } from "@/hooks/useActiveHeading"; import { useActiveHeading } from "@/hooks/useActiveHeading";
import useDrawerTOCState from "@/stores/useDrawerTOCState"; import useDrawerTOCState from "@/stores/useDrawerTOCState";
import { TTOCItem } from "@/types/toc.type"; import type { TTOCItem } from "@/types/toc.type";
import Link from "next/link"; import Link from "next/link";
import { MdMenuBook } from "react-icons/md"; import { MdMenuBook } from "react-icons/md";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
@@ -13,7 +13,7 @@ export const DrawerTOC = (props: { data: TTOCItem[] }) => {
return ( return (
<Sheet onOpenChange={setIsTOCOpen} open={isTOCOpen}> <Sheet onOpenChange={setIsTOCOpen} open={isTOCOpen}>
<SheetTrigger <SheetTrigger
className="bottom-16 right-5 fixed bg-white dark:bg-black border-gray-700 border dark:border-gray-500 shadow-xl" 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" title="Open the table of contents"
> >
<div className="p-1 font-bold" onClick={() => setIsTOCOpen(!isTOCOpen)} title="Open the table of contents"> <div className="p-1 font-bold" onClick={() => setIsTOCOpen(!isTOCOpen)} title="Open the table of contents">
@@ -24,12 +24,12 @@ export const DrawerTOC = (props: { data: TTOCItem[] }) => {
<SheetHeader> <SheetHeader>
<SheetTitle className="mt-8 font-bold">{"TABLE OF CONTENTS"}</SheetTitle> <SheetTitle className="mt-8 font-bold">{"TABLE OF CONTENTS"}</SheetTitle>
</SheetHeader> </SheetHeader>
<ul className="my-3 flat-scrollbar h-[70vh] flex flex-col overflow-y-auto flat-scrollbar-normal"> <ul className="flat-scrollbar flat-scrollbar-normal my-3 flex h-[70vh] flex-col overflow-y-auto">
{props.data?.map((item) => ( {props.data?.map((item) => (
<Link <Link
className={twMerge( className={twMerge(
"border-t border-b py-1 px-2 border-dashed hover:bg-gray-100 hover:dark:bg-gray-900", "border-t border-b border-dashed px-2 py-1 hover:bg-gray-100 hover:dark:bg-gray-900",
activeId === `#${item.anchorId}` ? "bg-gray-100 dark:bg-gray-900 text-sky-700 dark:text-sky-500" : "", activeId === `#${item.anchorId}` ? "bg-gray-100 text-sky-700 dark:bg-gray-900 dark:text-sky-500" : "",
)} )}
href={`#${item.anchorId}`} href={`#${item.anchorId}`}
key={`drawer-toc-${item.anchorId}`} key={`drawer-toc-${item.anchorId}`}

View File

@@ -1,7 +1,7 @@
export const PostCover = (props: { coverURL: string }) => { export const PostCover = (props: { coverURL: string }) => {
return ( return (
<div <div
className="mb-8 mt-0 flex w-full justify-center rounded-md" className="mt-0 mb-8 flex w-full justify-center rounded-md"
style={{ style={{
aspectRatio: "5/2", aspectRatio: "5/2",
background: `url(${props.coverURL})`, background: `url(${props.coverURL})`,

View File

@@ -17,8 +17,8 @@ export const ShareButtons = (props: {
}'s Blog ${postURL}`; }'s Blog ${postURL}`;
const { toast } = useToast(); const { toast } = useToast();
return ( return (
<div className="py-3 flex justify-center space-x-4 text-2xl"> <div className="flex justify-center space-x-4 py-3 text-2xl">
{props.allowShare != false ? ( {props.allowShare !== false ? (
<> <>
<FacebookShareButton className="mx-2" quote={props.quote ?? props.title} url={postURL}> <FacebookShareButton className="mx-2" quote={props.quote ?? props.title} url={postURL}>
<FaFacebook className="hover:text-blue-500" title="Share to Facebook" /> <FaFacebook className="hover:text-blue-500" title="Share to Facebook" />
@@ -39,13 +39,13 @@ export const ShareButtons = (props: {
text={copyShareText} text={copyShareText}
> >
<FaLink <FaLink
className="hover:text-gray-500 mx-2 cursor-pointer" className="mx-2 cursor-pointer hover:text-gray-500"
title="Share with the post url and description" title="Share with the post url and description"
/> />
</CopyToClipboard> </CopyToClipboard>
</> </>
) : ( ) : (
<div className="my-auto text-sm font-bold">{"SHARING IS NOT ALLOWED"}</div> <div className="my-auto font-bold text-sm">{"SHARING IS NOT ALLOWED"}</div>
)} )}
</div> </div>
); );

View File

@@ -1,5 +1,5 @@
import { useActiveHeading } from "@/hooks/useActiveHeading"; import { useActiveHeading } from "@/hooks/useActiveHeading";
import { TTOCItem } from "@/types/toc.type"; import type { TTOCItem } from "@/types/toc.type";
import Link from "next/link"; import Link from "next/link";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
@@ -8,16 +8,16 @@ export const TOC = (props: { data: TTOCItem[] }) => {
return ( return (
<div className="mx-5"> <div className="mx-5">
<div className="text-lg text-center p-2 font-bold border-t-2 border-b-2 border-gray-500"> <div className="border-gray-500 border-t-2 border-b-2 p-2 text-center font-bold text-lg">
{"TABLE OF CONTENTS"} {"TABLE OF CONTENTS"}
</div> </div>
<div className="px-2 py-2 h-[60vh] overflow-y-auto flat-scrollbar-normal"> <div className="flat-scrollbar-normal h-[60vh] overflow-y-auto px-2 py-2">
<div> <div>
{props.data?.map((item) => ( {props.data?.map((item) => (
<Link href={`#${item.anchorId}`} key={`toc-${item.anchorId}`}> <Link href={`#${item.anchorId}`} key={`toc-${item.anchorId}`}>
<div <div
className={twMerge( className={twMerge(
`py-2 text-sm rounded-lg hover:text-sky-700 dark:hover:text-sky-400`, "rounded-lg py-2 text-sm hover:text-sky-700 dark:hover:text-sky-400",
activeId === `#${item.anchorId}` ? "text-sky-700 dark:text-sky-400" : "", activeId === `#${item.anchorId}` ? "text-sky-700 dark:text-sky-400" : "",
)} )}
style={{ paddingLeft: `${item.level - 1}em` }} style={{ paddingLeft: `${item.level - 1}em` }}

View File

@@ -23,12 +23,12 @@ export const SponsorBoard = () => {
setIsCopiedList(Config.Sponsor?.Crypto?.map(() => false) ?? []); setIsCopiedList(Config.Sponsor?.Crypto?.map(() => false) ?? []);
}} }}
> >
<div className="mx-2 my-10 flex flex-col justify-around space-y-5"> <div className="mx-2 my-10 flex flex-col justify-around space-y-5">
{Config.Sponsor?.Crypto && ( {Config.Sponsor?.Crypto && (
<div className="py-3 flex justify-between border-b"> <div className="flex justify-between border-b py-3">
<div className="my-auto flex"> <div className="my-auto flex">
<div className="mx-3 my-auto"> <div className="mx-3 my-auto">
<h3 className="mx-auto text-sm font-bold">{"Crypto"}</h3> <h3 className="mx-auto font-bold text-sm">{"Crypto"}</h3>
<div className="text-xs">{"Supports BTC, USDT and ETH."}</div> <div className="text-xs">{"Supports BTC, USDT and ETH."}</div>
</div> </div>
</div> </div>
@@ -40,11 +40,11 @@ export const SponsorBoard = () => {
</div> </div>
)} )}
{Config.Sponsor?.Github && Config.SocialLinks.github && ( {Config.Sponsor?.Github && Config.SocialLinks.github && (
<div className="py-3 flex justify-between border-b"> <div className="flex justify-between border-b py-3">
<div className="my-auto flex"> <div className="my-auto flex">
<FaGithub className="mx-3 my-auto text-4xl text-gray-900 dark:text-gray-500" /> <FaGithub className="mx-3 my-auto text-4xl text-gray-900 dark:text-gray-500" />
<div className="my-auto"> <div className="my-auto">
<h3 className="mx-auto text-sm font-bold">{"Github Sponsor"}</h3> <h3 className="mx-auto font-bold text-sm">{"Github Sponsor"}</h3>
</div> </div>
</div> </div>
<div className="my-auto"> <div className="my-auto">
@@ -57,11 +57,11 @@ export const SponsorBoard = () => {
</div> </div>
)} )}
{!isEmptyString(Config.Sponsor?.WechatPayQRCodeContent) && ( {!isEmptyString(Config.Sponsor?.WechatPayQRCodeContent) && (
<div className="py-3 flex justify-between border-b"> <div className="flex justify-between border-b py-3">
<div className="my-auto flex"> <div className="my-auto flex">
<SiWechat className="mx-3 my-auto text-4xl text-green-500" /> <SiWechat className="mx-3 my-auto text-4xl text-green-500" />
<div className="my-auto"> <div className="my-auto">
<h3 className="mx-auto text-sm font-bold">{"Wechat Pay"}</h3> <h3 className="mx-auto font-bold text-sm">{"Wechat Pay"}</h3>
</div> </div>
</div> </div>
<div className="my-auto bg-white p-1"> <div className="my-auto bg-white p-1">
@@ -70,11 +70,11 @@ export const SponsorBoard = () => {
</div> </div>
)} )}
{!isEmptyString(Config.Sponsor?.AlipayLink) && ( {!isEmptyString(Config.Sponsor?.AlipayLink) && (
<div className="py-3 flex justify-between border-b"> <div className="flex justify-between border-b py-3">
<div className="my-auto flex"> <div className="my-auto flex">
<SiAlipay className="mx-3 my-auto text-4xl text-blue-500" /> <SiAlipay className="mx-3 my-auto text-4xl text-blue-500" />
<div className="my-auto"> <div className="my-auto">
<h3 className="mx-auto text-sm font-bold">{"Alipay"}</h3> <h3 className="mx-auto font-bold text-sm">{"Alipay"}</h3>
</div> </div>
</div> </div>
<div className="my-auto"> <div className="my-auto">
@@ -87,11 +87,11 @@ export const SponsorBoard = () => {
</div> </div>
)} )}
{!isEmptyString(Config.Sponsor?.PaypalId) && ( {!isEmptyString(Config.Sponsor?.PaypalId) && (
<div className="py-3 flex justify-between border-b"> <div className="flex justify-between border-b py-3">
<div className="my-auto flex"> <div className="my-auto flex">
<FaPaypal className="mx-3 my-auto text-4xl text-blue-600" /> <FaPaypal className="mx-3 my-auto text-4xl text-blue-600" />
<div className="my-auto"> <div className="my-auto">
<h3 className="mx-auto text-sm font-bold">{"Paypal"}</h3> <h3 className="mx-auto font-bold text-sm">{"Paypal"}</h3>
</div> </div>
</div> </div>
<div className="my-auto"> <div className="my-auto">
@@ -104,11 +104,11 @@ export const SponsorBoard = () => {
</div> </div>
)} )}
{!isEmptyString(Config.Sponsor?.PatreonId) && ( {!isEmptyString(Config.Sponsor?.PatreonId) && (
<div className="py-3 flex justify-between border-b"> <div className="flex justify-between border-b py-3">
<div className="my-auto flex"> <div className="my-auto flex">
<FaPatreon className="mx-3 my-auto text-4xl text-gray-500" /> <FaPatreon className="mx-3 my-auto text-4xl text-gray-500" />
<div className="my-auto"> <div className="my-auto">
<h3 className="mx-auto text-sm font-bold">{"Patreon"}</h3> <h3 className="mx-auto font-bold text-sm">{"Patreon"}</h3>
</div> </div>
</div> </div>
<div className="my-2"> <div className="my-2">
@@ -125,7 +125,7 @@ export const SponsorBoard = () => {
<DialogTitle className="flex">{"CRYPTO"}</DialogTitle> <DialogTitle className="flex">{"CRYPTO"}</DialogTitle>
</DialogHeader> </DialogHeader>
<div> <div>
<div className="w-full text-sm my-2"> <div className="my-2 w-full text-sm">
<div> <div>
<b>NOTE: </b> Please confirm the corresponding block network and address before transferring money to <b>NOTE: </b> Please confirm the corresponding block network and address before transferring money to
avoid loss. avoid loss.
@@ -133,9 +133,9 @@ export const SponsorBoard = () => {
</div> </div>
<Separator /> <Separator />
{Config.Sponsor?.Crypto?.map((cryptoItem, cryptoItemIndex) => ( {Config.Sponsor?.Crypto?.map((cryptoItem, cryptoItemIndex) => (
<div className="w-full py-3 border-b" key={nanoid()}> <div className="w-full border-b py-3" key={nanoid()}>
<div className="my-2 flex space-x-2"> <div className="my-2 flex space-x-2">
<div className="font-bold my-auto text-sm">{`${cryptoItem.Name} - ${cryptoItem.Blockchain}`}</div> <div className="my-auto font-bold text-sm">{`${cryptoItem.Name} - ${cryptoItem.Blockchain}`}</div>
</div> </div>
<div className="flex"> <div className="flex">
<Input autoFocus={false} defaultValue={cryptoItem.Address} readOnly /> <Input autoFocus={false} defaultValue={cryptoItem.Address} readOnly />
@@ -148,7 +148,7 @@ export const SponsorBoard = () => {
text={cryptoItem.Address} text={cryptoItem.Address}
> >
<Button <Button
className={`ml-3 my-auto ${isCopiedList[cryptoItemIndex] && "bg-green-500 hover:bg-green-500"}`} className={`my-auto ml-3 ${isCopiedList[cryptoItemIndex] && "bg-green-500 hover:bg-green-500"}`}
size="sm" size="sm"
type="submit" type="submit"
> >

View File

@@ -4,11 +4,11 @@ export const SponsorDescription = () => {
return ( return (
<div className="h-full"> <div className="h-full">
{!Config.Sponsor ? ( {!Config.Sponsor ? (
<p className={`content-font break-words text-lg`}> <p className={"break-words text-lg content-font"}>
{"Thank you, for data and personal private security, every sponsor method was paused."} {"Thank you, for data and personal private security, every sponsor method was paused."}
</p> </p>
) : ( ) : (
<p className={`content-font break-words text-lg`}> <p className={"break-words text-lg content-font"}>
{ {
"If you like my works, I would deeply appreciate your support as a patron. Your contribution not only fuels my creative journey but also allows me to delve deeper into my passion. Your support plays a vital role in making this vision a reality. Thank you for considering becoming a patron and being an integral part of this work endeavor." "If you like my works, I would deeply appreciate your support as a patron. Your contribution not only fuels my creative journey but also allows me to delve deeper into my passion. Your support plays a vital role in making this vision a reality. Thank you for considering becoming a patron and being an integral part of this work endeavor."
} }

View File

@@ -45,7 +45,7 @@ const AccordionContent = React.forwardRef<
ref={ref} ref={ref}
{...props} {...props}
> >
<div className={cn("pb-4 pt-0", className)}>{children}</div> <div className={cn("pt-0 pb-4", className)}>{children}</div>
</AccordionPrimitive.Content> </AccordionPrimitive.Content>
)); ));

View File

@@ -1,5 +1,5 @@
import { cva, type VariantProps } from "class-variance-authority"; import { type VariantProps, cva } from "class-variance-authority";
import * as React from "react"; import type * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View File

@@ -1,6 +1,6 @@
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Slot } from "@radix-ui/react-slot"; import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority"; import { type VariantProps, cva } from "class-variance-authority";
import * as React from "react"; import * as React from "react";
const buttonVariants = cva( const buttonVariants = cva(

View File

@@ -16,14 +16,14 @@ CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>( const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
({ className, ...props }, ref) => ( ({ className, ...props }, ref) => (
<h3 className={cn("text-2xl font-semibold leading-none tracking-tight", className)} ref={ref} {...props} /> <h3 className={cn("font-semibold text-2xl leading-none tracking-tight", className)} ref={ref} {...props} />
), ),
); );
CardTitle.displayName = "CardTitle"; CardTitle.displayName = "CardTitle";
const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>( const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
({ className, ...props }, ref) => ( ({ className, ...props }, ref) => (
<p className={cn("text-sm text-muted-foreground", className)} ref={ref} {...props} /> <p className={cn("text-muted-foreground text-sm", className)} ref={ref} {...props} />
), ),
); );
CardDescription.displayName = "CardDescription"; CardDescription.displayName = "CardDescription";

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { type DialogProps } from "@radix-ui/react-dialog"; import type { DialogProps } from "@radix-ui/react-dialog";
import { Command as CommandPrimitive } from "cmdk"; import { Command as CommandPrimitive } from "cmdk";
import { Search } from "lucide-react"; import { Search } from "lucide-react";
import * as React from "react"; import * as React from "react";
@@ -82,7 +82,7 @@ const CommandGroup = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<CommandPrimitive.Group <CommandPrimitive.Group
className={cn( className={cn(
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground", "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:text-xs",
className, className,
)} )}
ref={ref} ref={ref}
@@ -117,7 +117,7 @@ const CommandItem = React.forwardRef<
CommandItem.displayName = CommandPrimitive.Item.displayName; CommandItem.displayName = CommandPrimitive.Item.displayName;
const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => { const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
return <span className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)} {...props} />; return <span className={cn("ml-auto text-muted-foreground text-xs tracking-widest", className)} {...props} />;
}; };
CommandShortcut.displayName = "CommandShortcut"; CommandShortcut.displayName = "CommandShortcut";

View File

@@ -20,7 +20,7 @@ const DialogOverlay = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay <DialogPrimitive.Overlay
className={cn( className={cn(
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=closed]:animate-out data-[state=open]:animate-in",
className, className,
)} )}
ref={ref} ref={ref}
@@ -37,14 +37,14 @@ const DialogContent = React.forwardRef<
<DialogOverlay /> <DialogOverlay />
<DialogPrimitive.Content <DialogPrimitive.Content
className={cn( className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:rounded-lg",
className, className,
)} )}
ref={ref} ref={ref}
{...props} {...props}
> >
{children} {children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> <DialogPrimitive.Close className="absolute top-4 right-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" /> <X className="h-4 w-4" />
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
</DialogPrimitive.Close> </DialogPrimitive.Close>
@@ -68,7 +68,7 @@ const DialogTitle = React.forwardRef<
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<DialogPrimitive.Title <DialogPrimitive.Title
className={cn("text-lg font-semibold leading-none tracking-tight", className)} className={cn("font-semibold text-lg leading-none tracking-tight", className)}
ref={ref} ref={ref}
{...props} {...props}
/> />
@@ -79,7 +79,7 @@ const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>, React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<DialogPrimitive.Description className={cn("text-sm text-muted-foreground", className)} ref={ref} {...props} /> <DialogPrimitive.Description className={cn("text-muted-foreground text-sm", className)} ref={ref} {...props} />
)); ));
DialogDescription.displayName = DialogPrimitive.Description.displayName; DialogDescription.displayName = DialogPrimitive.Description.displayName;

View File

@@ -8,7 +8,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, type,
return ( return (
<input <input
className={cn( className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:font-medium file:text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className, className,
)} )}
ref={ref} ref={ref}

View File

@@ -2,7 +2,7 @@
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import * as SheetPrimitive from "@radix-ui/react-dialog"; import * as SheetPrimitive from "@radix-ui/react-dialog";
import { cva, type VariantProps } from "class-variance-authority"; import { type VariantProps, cva } from "class-variance-authority";
import { X } from "lucide-react"; import { X } from "lucide-react";
import * as React from "react"; import * as React from "react";
@@ -25,7 +25,7 @@ const SheetOverlay = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay <SheetPrimitive.Overlay
className={cn( className={cn(
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=closed]:animate-out data-[state=open]:animate-in",
className, className,
)} )}
{...props} {...props}
@@ -63,7 +63,7 @@ const SheetContent = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Con
<SheetOverlay /> <SheetOverlay />
<SheetPrimitive.Content className={cn(sheetVariants({ side }), className)} ref={ref} {...props}> <SheetPrimitive.Content className={cn(sheetVariants({ side }), className)} ref={ref} {...props}>
{children} {children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"> <SheetPrimitive.Close className="absolute top-4 right-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" /> <X className="h-4 w-4" />
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
</SheetPrimitive.Close> </SheetPrimitive.Close>
@@ -87,7 +87,7 @@ const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>, React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title> React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<SheetPrimitive.Title className={cn("text-lg font-semibold text-foreground", className)} ref={ref} {...props} /> <SheetPrimitive.Title className={cn("font-semibold text-foreground text-lg", className)} ref={ref} {...props} />
)); ));
SheetTitle.displayName = SheetPrimitive.Title.displayName; SheetTitle.displayName = SheetPrimitive.Title.displayName;
@@ -95,7 +95,7 @@ const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>, React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description> React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<SheetPrimitive.Description className={cn("text-sm text-muted-foreground", className)} ref={ref} {...props} /> <SheetPrimitive.Description className={cn("text-muted-foreground text-sm", className)} ref={ref} {...props} />
)); ));
SheetDescription.displayName = SheetPrimitive.Description.displayName; SheetDescription.displayName = SheetPrimitive.Description.displayName;

View File

@@ -1,5 +1,5 @@
import * as ToastPrimitives from "@radix-ui/react-toast"; import * as ToastPrimitives from "@radix-ui/react-toast";
import { cva, type VariantProps } from "class-variance-authority"; import { type VariantProps, cva } from "class-variance-authority";
import { X } from "lucide-react"; import { X } from "lucide-react";
import * as React from "react"; import * as React from "react";
@@ -13,7 +13,7 @@ const ToastViewport = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<ToastPrimitives.Viewport <ToastPrimitives.Viewport
className={cn( className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]", "fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:top-auto sm:right-0 sm:bottom-0 sm:flex-col md:max-w-[420px]",
className, className,
)} )}
ref={ref} ref={ref}
@@ -51,7 +51,7 @@ const ToastAction = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<ToastPrimitives.Action <ToastPrimitives.Action
className={cn( className={cn(
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive", "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 font-medium text-sm ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:focus:ring-destructive group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground",
className, className,
)} )}
ref={ref} ref={ref}
@@ -66,7 +66,7 @@ const ToastClose = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<ToastPrimitives.Close <ToastPrimitives.Close
className={cn( className={cn(
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600", "absolute top-2 right-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600 group-[.destructive]:hover:text-red-50",
className, className,
)} )}
ref={ref} ref={ref}
@@ -82,7 +82,7 @@ const ToastTitle = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Title>, React.ElementRef<typeof ToastPrimitives.Title>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title> React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<ToastPrimitives.Title className={cn("text-sm font-semibold", className)} ref={ref} {...props} /> <ToastPrimitives.Title className={cn("font-semibold text-sm", className)} ref={ref} {...props} />
)); ));
ToastTitle.displayName = ToastPrimitives.Title.displayName; ToastTitle.displayName = ToastPrimitives.Title.displayName;

View File

@@ -8,18 +8,16 @@ export function Toaster() {
return ( return (
<ToastProvider> <ToastProvider>
{toasts.map(function ({ id, title, description, action, ...props }) { {toasts.map(({ id, title, description, action, ...props }) => (
return ( <Toast key={id} {...props}>
<Toast key={id} {...props}> <div className="grid gap-1">
<div className="grid gap-1"> {title && <ToastTitle>{title}</ToastTitle>}
{title && <ToastTitle>{title}</ToastTitle>} {description && <ToastDescription>{description}</ToastDescription>}
{description && <ToastDescription>{description}</ToastDescription>} </div>
</div> {action}
{action} <ToastClose />
<ToastClose /> </Toast>
</Toast> ))}
);
})}
<ToastViewport /> <ToastViewport />
</ToastProvider> </ToastProvider>
); );

View File

@@ -31,7 +31,9 @@ export const Footer = () => {
</Link> </Link>
{Config.RSSFeed?.enabled && ( {Config.RSSFeed?.enabled && (
<DialogTrigger asChild> <DialogTrigger asChild>
<button title="Subscribe the RSS Feed.">{"Feed"}</button> <button title="Subscribe the RSS Feed." type="button">
{"Feed"}
</button>
</DialogTrigger> </DialogTrigger>
)} )}
</div> </div>
@@ -39,20 +41,20 @@ export const Footer = () => {
<DialogContent className="sm:max-w-md"> <DialogContent className="sm:max-w-md">
<DialogHeader> <DialogHeader>
<DialogTitle className="flex"> <DialogTitle className="flex">
<IoLogoRss className="mr-2 my-auto" /> <IoLogoRss className="my-auto mr-2" />
{"RSS Feed"} {"RSS Feed"}
</DialogTitle> </DialogTitle>
</DialogHeader> </DialogHeader>
<div> <div>
<div className="w-full text-sm my-2"> <div className="my-2 w-full text-sm">
<div> <div>
<b>NOTE: </b>Some RSS Feed Reader may has deficient in rendering SVG formulations, graphs. Such as the <b>NOTE: </b>Some RSS Feed Reader may has deficient in rendering SVG formulations, graphs. Such as the
Inoreader, Feedly. If it happens, please read the origin web page for better experience. Inoreader, Feedly. If it happens, please read the origin web page for better experience.
</div> </div>
</div> </div>
<Separator /> <Separator />
<div className="w-full flex my-3"> <div className="my-3 flex w-full">
<Input defaultValue={RSSFeedURL} readOnly /> <Input defaultValue={RSSFeedURL} readOnly />
<CopyToClipboard <CopyToClipboard
onCopy={() => { onCopy={() => {
@@ -61,7 +63,7 @@ export const Footer = () => {
text={RSSFeedURL} text={RSSFeedURL}
> >
<Button <Button
className={`ml-3 my-auto ${isCopied && "bg-green-500 hover:bg-green-500"}`} className={`my-auto ml-3 ${isCopied && "bg-green-500 hover:bg-green-500"}`}
size="sm" size="sm"
type="submit" type="submit"
> >

View File

@@ -32,16 +32,16 @@ export const NavBar = () => {
return ( return (
<Sheet onOpenChange={(open) => setIsSideNavOpen(open)} open={isSideNavOpen}> <Sheet onOpenChange={(open) => setIsSideNavOpen(open)} open={isSideNavOpen}>
<div className="sticky top-0 z-50 border-black-200 dark:border-gray-700 border-b bg-white dark:bg-gray-950 flex flex-wrap justify-between py-3 px-5 md:px-10 lg:px-20 xl:px-32 2xl:px-52"> <div className="sticky top-0 z-50 flex flex-wrap justify-between border-black-200 border-b bg-white px-5 py-3 md:px-10 lg:px-20 xl:px-32 2xl:px-52 dark:border-gray-700 dark:bg-gray-950">
<Link className="cursor-pointer my-auto text-2xl font-bold" href="/"> <Link className="my-auto cursor-pointer font-bold text-2xl" href="/">
<h1 className={`website-title-font my-auto`} title="Click to jump to home page."> <h1 className={"website-title-font my-auto"} title="Click to jump to home page.">
{Config.SiteTitle} {Config.SiteTitle}
</h1> </h1>
</Link> </Link>
<div className="my-auto hidden sm:flex"> <div className="my-auto hidden sm:flex">
{MenuItems.map((menuItem) => ( {MenuItems.map((menuItem) => (
<Link <Link
className="font-bold hover:text-sky-700 dark:hover:text-sky-500 mx-2 my-auto px-2" className="mx-2 my-auto px-2 font-bold hover:text-sky-700 dark:hover:text-sky-500"
href={menuItem.href} href={menuItem.href}
key={nanoid()} key={nanoid()}
onClick={() => setIsSideNavOpen(false)} onClick={() => setIsSideNavOpen(false)}
@@ -50,23 +50,23 @@ export const NavBar = () => {
</Link> </Link>
))} ))}
<Link <Link
className="cursor-pointer mx-2 rounded-full p-1 text-3xl text-black hover:bg-gray-200 dark:text-gray-50 dark:hover:bg-gray-800" className="mx-2 cursor-pointer rounded-full p-1 text-3xl text-black hover:bg-gray-200 dark:text-gray-50 dark:hover:bg-gray-800"
href={"/search"} href={"/search"}
title="Search posts by keywords" title="Search posts by keywords"
> >
<MdSearch /> <MdSearch />
</Link> </Link>
<div <div
className="cursor-pointer mx-1 rounded-full p-1 text-3xl text-black hover:bg-gray-200 dark:text-gray-50 dark:hover:bg-gray-800" className="mx-1 cursor-pointer rounded-full p-1 text-3xl text-black hover:bg-gray-200 dark:text-gray-50 dark:hover:bg-gray-800"
onClick={handleSwitchTheme} onClick={handleSwitchTheme}
title={theme === "light" ? "Switch to dark mode" : "Switch to light mode"} title={theme === "light" ? "Switch to dark mode" : "Switch to light mode"}
> >
{theme === "light" ? <MdOutlineDarkMode /> : <MdOutlineLightMode />} {theme === "light" ? <MdOutlineDarkMode /> : <MdOutlineLightMode />}
</div> </div>
</div> </div>
<div className="text-3xl sm:hidden my-auto"> <div className="my-auto text-3xl sm:hidden">
<SheetTrigger <SheetTrigger
className="text-black rounded-full p-1 hover:bg-gray-200 dark:text-gray-50 dark:hover:bg-gray-800" className="rounded-full p-1 text-black hover:bg-gray-200 dark:text-gray-50 dark:hover:bg-gray-800"
title="Spread the navigation menu" title="Spread the navigation menu"
> >
<MdMenu <MdMenu
@@ -77,7 +77,7 @@ export const NavBar = () => {
</SheetTrigger> </SheetTrigger>
</div> </div>
</div> </div>
<SheetContent className="bg:white border-none py-16 shadow-md dark:bg-black flex flex-col text-end"> <SheetContent className="bg:white flex flex-col border-none py-16 text-end shadow-md dark:bg-black">
{MenuItems.map((menuItem) => ( {MenuItems.map((menuItem) => (
<Link <Link
className="border-b border-dashed p-3 text-xl hover:text-sky-500" className="border-b border-dashed p-3 text-xl hover:text-sky-500"
@@ -97,11 +97,11 @@ export const NavBar = () => {
{"SEARCH"} {"SEARCH"}
</Link> </Link>
<div <div
className="flex text-xl p-3 cursor-pointer border-b border-dashed justify-end hover:text-sky-500" className="flex cursor-pointer justify-end border-b border-dashed p-3 text-xl hover:text-sky-500"
onClick={handleSwitchTheme} onClick={handleSwitchTheme}
> >
<div <div
className="cursor-pointer mx-1 my-auto rounded-full text-2xl" className="mx-1 my-auto cursor-pointer rounded-full text-2xl"
title={theme === "light" ? "Switch to dark mode" : "Switch to light mode"} title={theme === "light" ? "Switch to dark mode" : "Switch to light mode"}
> >
{theme === "light" ? <MdOutlineDarkMode /> : <MdOutlineLightMode />} {theme === "light" ? <MdOutlineDarkMode /> : <MdOutlineLightMode />}

View File

@@ -1,5 +1,5 @@
import { normalizeDate } from "@/lib/date"; import { normalizeDate } from "@/lib/date";
import { TPostListItem } from "@/types/post-list"; import type { TPostListItem } from "@/types/post-list";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import Link from "next/link"; import Link from "next/link";
import { Badge } from "../ui/badge"; import { Badge } from "../ui/badge";
@@ -12,34 +12,34 @@ export const PostList = (props: { data: TPostListItem[] }) => {
<div <div
className={`flex flex-col justify-center ${ className={`flex flex-col justify-center ${
index !== props.data.length - 1 && "border-b" index !== props.data.length - 1 && "border-b"
} border-gray-200 hover:bg-gray-50 dark:hover:bg-gray-900 dark:border-gray-800 px-3 py-1`} } border-gray-200 px-3 py-1 hover:bg-gray-50 dark:border-gray-800 dark:hover:bg-gray-900`}
> >
<div className={"post-list-caption-font flex-col py-3"}> <div className={"post-list-caption-font flex-col py-3"}>
<div className="flex justify-center"> <div className="flex justify-center">
<h3 className="mx-auto text-lg font-extrabold capitalize">{postItem.frontMatter.title}</h3> <h3 className="mx-auto font-extrabold text-lg capitalize">{postItem.frontMatter.title}</h3>
</div> </div>
<div className="flex justify-center"> <div className="flex justify-center">
{postItem.frontMatter.subtitle && ( {postItem.frontMatter.subtitle && (
<div className="mx-auto text-sm font-bold capitalize text-gray-700 dark:text-gray-300"> <div className="mx-auto font-bold text-gray-700 text-sm capitalize dark:text-gray-300">
{postItem.frontMatter.subtitle} {postItem.frontMatter.subtitle}
</div> </div>
)} )}
</div> </div>
</div> </div>
{postItem.frontMatter.summary && ( {postItem.frontMatter.summary && (
<div className={"content-font flex justify-center"}> <div className={"flex justify-center content-font"}>
<p>{postItem.frontMatter.summary}</p> <p>{postItem.frontMatter.summary}</p>
</div> </div>
)} )}
<div className="flex flex-wrap justify-between my-2"> <div className="my-2 flex flex-wrap justify-between">
<div className="text-center flex flex-col justify-center italic text-sm my-auto mr-2 h-6"> <div className="my-auto mr-2 flex h-6 flex-col justify-center text-center text-sm italic">
<div className="my-auto">{normalizeDate(postItem.frontMatter.time)}</div> <div className="my-auto">{normalizeDate(postItem.frontMatter.time)}</div>
</div> </div>
{postItem.frontMatter.tags && ( {postItem.frontMatter.tags && (
<div className="flex flex-wrap my-auto"> <div className="my-auto flex flex-wrap">
{postItem.frontMatter.tags.map((tagName) => ( {postItem.frontMatter.tags.map((tagName) => (
<Badge <Badge
className="mr-1 my-1 text-gray-600 dark:text-gray-300" className="my-1 mr-1 text-gray-600 dark:text-gray-300"
key={`tags-${nanoid()}`} key={`tags-${nanoid()}`}
variant={"secondary"} variant={"secondary"}
> >

View File

@@ -5,7 +5,7 @@ import { TbBrandFacebook, TbBrandLinkedin, TbBrandMastodon } from "react-icons/t
export const SocialIcons = () => { export const SocialIcons = () => {
return ( return (
<div className="my-5 flex justify-center space-x-4 text-2xl font-bold"> <div className="my-5 flex justify-center space-x-4 font-bold text-2xl">
{Config.SocialLinks.twitter && ( {Config.SocialLinks.twitter && (
<Link href={`https://x.com/${Config.SocialLinks.twitter}`} target="_blank" title="Twitter"> <Link href={`https://x.com/${Config.SocialLinks.twitter}`} target="_blank" title="Twitter">
<FiTwitter className="hover:text-sky-500" /> <FiTwitter className="hover:text-sky-500" />

View File

@@ -1,6 +1,6 @@
import path from "path";
import { Config } from "@/data/config"; import { Config } from "@/data/config";
import { getCurrentTime } from "@/lib/date"; import { getCurrentTime } from "@/lib/date";
import path from "path";
import process from "process"; import process from "process";
export const LatestPostCountInHomePage = 10; export const LatestPostCountInHomePage = 10;

View File

@@ -1,4 +1,4 @@
import { TConfig } from "@/types/config.type"; import type { TConfig } from "@/types/config.type";
export const Config: TConfig = { export const Config: TConfig = {
// Image url for avatar. // Image url for avatar.
@@ -33,7 +33,7 @@ export const Config: TConfig = {
// Giscus Configure. Please refer to the https://giscus.app for entire instruction // Giscus Configure. Please refer to the https://giscus.app for entire instruction
Giscus: { Giscus: {
enabled: true, enabled: true,
repo: `PrinOrange/nextjs-lexical-blog`, repo: "PrinOrange/nextjs-lexical-blog",
repoId: "R_kgDOK44zmw", repoId: "R_kgDOK44zmw",
category: "Announcements", category: "Announcements",
categoryId: "DIC_kwDOK44zm84Cb94g", categoryId: "DIC_kwDOK44zm84Cb94g",

View File

@@ -1,4 +1,4 @@
import { TFriendItem } from "@/types/friend.type"; import type { TFriendItem } from "@/types/friend.type";
export const FriendsList: TFriendItem[] = [ export const FriendsList: TFriendItem[] = [
{ {

View File

@@ -39,7 +39,7 @@ export function useActiveHeading(headingList: string[], options?: IntersectionOb
headingList headingList
.map((heading) => document?.querySelector(`[id='${removeFirstHash(heading)}']`)) .map((heading) => document?.querySelector(`[id='${removeFirstHash(heading)}']`))
//Remove null elments //Remove null elments
.flatMap((f) => (!!f ? [f] : [])) .flatMap((f) => (f ? [f] : []))
.forEach((element) => observer.observe(element)); .forEach((element) => observer.observe(element));
return () => observer.disconnect(); return () => observer.disconnect();

View File

@@ -8,6 +8,7 @@ export function checkAndCreateDirectory(dirPath: string) {
fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK); fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
return true; return true;
} catch (err) { } catch (err) {
console.log(err);
throw err; throw err;
} }
} }
@@ -20,6 +21,7 @@ export function isDirectoryEmptySync(directory: string) {
const files = fs.readdirSync(directory); const files = fs.readdirSync(directory);
return files.length === 0; return files.length === 0;
} catch (err) { } catch (err) {
console.log(err);
throw err; throw err;
} }
} }

View File

@@ -1,9 +1,9 @@
import { PostFilesDirectory } from "@/consts/consts";
import { TFrontmatter } from "@/types/frontmatter.type";
import { TPostListItem, TPostsByTag } from "@/types/post-list";
import fs from "fs"; import fs from "fs";
import { serialize } from "next-mdx-remote/serialize";
import path from "path"; import path from "path";
import { PostFilesDirectory } from "@/consts/consts";
import type { TFrontmatter } from "@/types/frontmatter.type";
import type { TPostListItem, TPostsByTag } from "@/types/post-list";
import { serialize } from "next-mdx-remote/serialize";
import { titleCase } from "title-case"; import { titleCase } from "title-case";
import { isEmptyString, nullifyEmptyArray, nullifyEmptyString } from "./utils"; import { isEmptyString, nullifyEmptyArray, nullifyEmptyString } from "./utils";

View File

@@ -1,7 +1,7 @@
import fs from "fs";
import { CopyrightAnnouncement, LatestPostCountInHomePage, WebsiteURL } from "@/consts/consts"; import { CopyrightAnnouncement, LatestPostCountInHomePage, WebsiteURL } from "@/consts/consts";
import { Config } from "@/data/config"; import { Config } from "@/data/config";
import { Feed } from "feed"; import { Feed } from "feed";
import fs from "fs";
import { JSDOM } from "jsdom"; import { JSDOM } from "jsdom";
import { MDXRemote } from "next-mdx-remote"; import { MDXRemote } from "next-mdx-remote";
import { serialize } from "next-mdx-remote/serialize"; import { serialize } from "next-mdx-remote/serialize";
@@ -17,7 +17,8 @@ import remarkMath from "remark-math";
import remarkPrism from "remark-prism"; import remarkPrism from "remark-prism";
import { getPostFileContent, sortedPosts } from "./post-process"; import { getPostFileContent, sortedPosts } from "./post-process";
const NoticeForRSSReaders = `\n---\n**NOTE:** Different RSS reader may have deficient even no support for svg formulations rendering. If it happens, please read the origin page to have better experience.`; const NoticeForRSSReaders =
"\n---\n**NOTE:** Different RSS reader may have deficient even no support for svg formulations rendering. If it happens, please read the origin page to have better experience.";
function minifyHTMLCode(htmlString: string): string { function minifyHTMLCode(htmlString: string): string {
const dom = new JSDOM(htmlString); const dom = new JSDOM(htmlString);
@@ -61,7 +62,7 @@ export const generateRSSFeed = async () => {
for (let i = 0; i < Math.min(LatestPostCountInHomePage, sortedPosts.allPostList.length); i++) { for (let i = 0; i < Math.min(LatestPostCountInHomePage, sortedPosts.allPostList.length); i++) {
const post = sortedPosts.allPostList[i]; const post = sortedPosts.allPostList[i];
const postFileContent = `${getPostFileContent(post.id)}${NoticeForRSSReaders}}`; const postFileContent = `${getPostFileContent(post.id)}${NoticeForRSSReaders}}`;
const dateNumber = post.frontMatter.time.split("-").map((num) => parseInt(num)); const dateNumber = post.frontMatter.time.split("-").map((num) => Number.parseInt(num));
const mdxSource = await serialize(postFileContent ?? "", { const mdxSource = await serialize(postFileContent ?? "", {
parseFrontmatter: true, parseFrontmatter: true,
mdxOptions: { mdxOptions: {

View File

@@ -23,7 +23,7 @@ function tokenizer(str: string) {
function makeSearchIndex() { function makeSearchIndex() {
const startTime = Date.now(); const startTime = Date.now();
let miniSearch = new minisearch({ const miniSearch = new minisearch({
fields: ["id", "title", "tags", "subtitle", "summary", "content"], fields: ["id", "title", "tags", "subtitle", "summary", "content"],
storeFields: ["id", "title", "tags", "summary"], storeFields: ["id", "title", "tags", "summary"],
tokenize: tokenizer, tokenize: tokenizer,

View File

@@ -1,4 +1,4 @@
import { TTOCItem } from "@/types/toc.type"; import type { TTOCItem } from "@/types/toc.type";
import { JSDOM } from "jsdom"; import { JSDOM } from "jsdom";
/** /**
@@ -12,7 +12,7 @@ export const makeTOCTree = (htmlCode: string) => {
const all_headers = doc_dom.window.document.querySelectorAll("h1,h2,h3,h4,h5,h6"); const all_headers = doc_dom.window.document.querySelectorAll("h1,h2,h3,h4,h5,h6");
const result: TTOCItem[] = []; const result: TTOCItem[] = [];
for (let i = 0; i < all_headers.length; i++) { for (let i = 0; i < all_headers.length; i++) {
const level = parseInt(all_headers[i].tagName.replace("H", "")); const level = Number.parseInt(all_headers[i].tagName.replace("H", ""));
result.push({ result.push({
level: level, level: level,
anchorId: all_headers[i].id, anchorId: all_headers[i].id,

View File

@@ -1,5 +1,5 @@
import { NonEmptyArray } from "@/types/utils.type"; import type { NonEmptyArray } from "@/types/utils.type";
import { clsx, type ClassValue } from "clsx"; import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {

View File

@@ -1,4 +1,4 @@
var WebpackObfuscator = require("webpack-obfuscator"); const WebpackObfuscator = require("webpack-obfuscator");
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"], pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"],

3842
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -14,12 +14,11 @@
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"dev:turbo": "npx turbo dev", "dev:turbo": "npx turbo dev",
"build:turbo": "npx turbo build lint", "build:turbo": "npx turbo build",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"format": "npx prettier . --write && npx autocorrect --fix", "format": "npx biome format --write . && npx autocorrect --fix",
"lint": "next lint", "lint:fix": "npx biome check --fix",
"lint:fix": "npx eslint --fix .",
"newpost": "bun ./scripts/newpost.ts", "newpost": "bun ./scripts/newpost.ts",
"archive": "bun ./scripts/archive.ts" "archive": "bun ./scripts/archive.ts"
}, },
@@ -43,8 +42,6 @@
"clsx": "^2.0.0", "clsx": "^2.0.0",
"cmdk": "^1.0.0", "cmdk": "^1.0.0",
"colors": "^1.4.0", "colors": "^1.4.0",
"eslint-config-next": "^14.1.4",
"eslint-config-plugin": "^1.0.11",
"highlight.js": "^11.9.0", "highlight.js": "^11.9.0",
"jsdom": "^24.0.0", "jsdom": "^24.0.0",
"katex": "^0.16.9", "katex": "^0.16.9",
@@ -89,6 +86,7 @@
"zustand": "^4.4.7" "zustand": "^4.4.7"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.8.3",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",
"@types/archiver": "^6.0.2", "@types/archiver": "^6.0.2",
"@types/inquirer": "^9.0.7", "@types/inquirer": "^9.0.7",
@@ -105,13 +103,8 @@
"archiver": "^7.0.1", "archiver": "^7.0.1",
"autocorrect-node": "^2.11.1", "autocorrect-node": "^2.11.1",
"bun": "^1.1.22", "bun": "^1.1.22",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.1",
"feed": "^4.2.2", "feed": "^4.2.2",
"inquirer": "^9.2.12", "inquirer": "^9.2.12",
"prettier": "^3.0.3",
"prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-tailwindcss": "^0.5.7",
"tar": "^7.0.1", "tar": "^7.0.1",
"turbo": "^2.0.12", "turbo": "^2.0.12",
"webpack-obfuscator": "^3.5.1" "webpack-obfuscator": "^3.5.1"

View File

@@ -14,11 +14,11 @@ export default function NotFoundPage() {
<Page> <Page>
<NavBar /> <NavBar />
<ContentContainer> <ContentContainer>
<h2 className={`my-5 flex justify-center text-2xl font-bold caption-font`}>{"404 NOT FOUND"}</h2> <h2 className={"caption-font my-5 flex justify-center font-bold text-2xl"}>{"404 NOT FOUND"}</h2>
<Separator /> <Separator />
<div className="my-5 flex flex-col justify-center"> <div className="my-5 flex flex-col justify-center">
<TfiFaceSad className="mx-auto my-4" size={"6em"} /> <TfiFaceSad className="mx-auto my-4" size={"6em"} />
<p className={`content-font mx-auto my-3 text-center text-xl`}> <p className={"mx-auto my-3 text-center text-xl content-font"}>
{"This page does not exist for it might be removed or closed."} {"This page does not exist for it might be removed or closed."}
</p> </p>
<div className="my-5 flex justify-center"> <div className="my-5 flex justify-center">

View File

@@ -14,11 +14,11 @@ export default function ServerErrorPage() {
<Page> <Page>
<NavBar /> <NavBar />
<ContentContainer> <ContentContainer>
<h2 className={`my-5 flex justify-center text-2xl font-bold caption-font`}>{"INVALID OPERATION"}</h2> <h2 className={"caption-font my-5 flex justify-center font-bold text-2xl"}>{"INVALID OPERATION"}</h2>
<Separator /> <Separator />
<div className="my-5 flex flex-col justify-center"> <div className="my-5 flex flex-col justify-center">
<MdOutlineDangerous className="mx-auto my-4" size={"6em"} /> <MdOutlineDangerous className="mx-auto my-4" size={"6em"} />
<p className={`content-font mx-auto my-3 text-center text-xl`}> <p className={"mx-auto my-3 text-center text-xl content-font"}>
{"Something went wrong. Please try again later."} {"Something went wrong. Please try again later."}
</p> </p>
<div className="my-5 flex justify-center"> <div className="my-5 flex justify-center">

View File

@@ -18,16 +18,15 @@ export default function AboutPage() {
/> />
<NavBar /> <NavBar />
<ContentContainer> <ContentContainer>
<h2 className={`my-5 flex justify-around text-2xl font-bold caption-font`}>{"ABOUT ME"}</h2> <h2 className={"caption-font my-5 flex justify-around font-bold text-2xl"}>{"ABOUT ME"}</h2>
<Separator /> <Separator />
<div className={`content-font my-5 justify-center md:flex md:space-x-10`}> <div className={"my-5 justify-center content-font md:flex md:space-x-10"}>
<div className="my-auto flex md:w-1/3"> <div className="my-auto flex md:w-1/3">
<img alt="my-profile" className="mx-auto my-auto max-h-[23rem] rounded-lg" src="/images/profile.webp" /> <img alt="my-profile" className="mx-auto my-auto max-h-[23rem] rounded-lg" src="/images/profile.webp" />
</div> </div>
<div className="my-auto md:w-1/3"> <div className="my-auto md:w-1/3">
<div className="mt-5 mb-3 text-3xl font-bold">Hi, there👋</div> <div className="mt-5 mb-3 font-bold text-3xl">Hi, there👋</div>I am a student / entrepreneur / engineer
I am a student / entrepreneur / engineer (Your profession) majoring in (Your Research Field) born in XXXX (Your profession) majoring in (Your Research Field) born in XXXX (Your birth year)
(Your birth year)
<br /> <br />
<br /> <br />
My main research interests includes XXXX My main research interests includes XXXX
@@ -40,7 +39,7 @@ export default function AboutPage() {
<SocialIcons /> <SocialIcons />
<Separator /> <Separator />
<ul className="mx-auto my-10 px-5 md:w-2/3 list-disc"> <ul className="mx-auto my-10 list-disc px-5 md:w-2/3">
{Config.SocialLinks.github && ( {Config.SocialLinks.github && (
<li className="my-2"> <li className="my-2">
{"📕 Check out my github profile at "} {"📕 Check out my github profile at "}
@@ -64,7 +63,7 @@ export default function AboutPage() {
<li className="my-2">From : Your Country, State / Province</li> <li className="my-2">From : Your Country, State / Province</li>
</ul> </ul>
<div className="mx-auto my-10 md:w-2/3 font-bold"> <div className="mx-auto my-10 font-bold md:w-2/3">
{ {
"** In addition to the above content, you can also add other customized components, content, etc. to this page. **" "** In addition to the above content, you can also add other customized components, content, etc. to this page. **"
} }

View File

@@ -1,6 +1,6 @@
import { SearchIndex } from "@/lib/search"; import { SearchIndex } from "@/lib/search";
import { isEmptyString } from "@/lib/utils"; import { isEmptyString } from "@/lib/utils";
import { TSearchResultItem } from "@/types/search-result"; import type { TSearchResultItem } from "@/types/search-result";
import type { NextApiRequest, NextApiResponse } from "next"; import type { NextApiRequest, NextApiResponse } from "next";
type ResponseData = TSearchResultItem[]; type ResponseData = TSearchResultItem[];

View File

@@ -16,12 +16,12 @@ 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 useDrawerTOCState from "@/stores/useDrawerTOCState";
import { TFrontmatter } from "@/types/frontmatter.type"; import type { TFrontmatter } from "@/types/frontmatter.type";
import { TPostListItem } from "@/types/post-list"; import type { TPostListItem } from "@/types/post-list";
import { TTOCItem } from "@/types/toc.type"; import type { TTOCItem } from "@/types/toc.type";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { GetStaticPaths, GetStaticProps } from "next"; import type { GetStaticPaths, GetStaticProps } from "next";
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote"; 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";
@@ -70,34 +70,36 @@ const ReaderPage = (props: ReaderPageProps) => {
<NavBar /> <NavBar />
<ContentContainer> <ContentContainer>
<div <div
className={`py-1 ${isTOCLongEnough ? "justify-between" : "justify-center"} lg:flex space-x-5`} className={`py-1 ${isTOCLongEnough ? "justify-between" : "justify-center"} space-x-5 lg:flex`}
style={{ borderRadius: "5px" }} style={{ borderRadius: "5px" }}
> >
<div className={`${isTOCLongEnough ? "lg:w-2/3" : "lg:w-5/6"} py-5`}> <div className={`${isTOCLongEnough ? "lg:w-2/3" : "lg:w-5/6"} py-5`}>
<div className="typesetting"> <div className="typesetting">
{props.frontMatter.coverURL && <PostCover coverURL={props.frontMatter.coverURL} />} {props.frontMatter.coverURL && <PostCover coverURL={props.frontMatter.coverURL} />}
<div className="pb-1 border-b-2 border-black dark:border-gray-300"> <div className="border-black border-b-2 pb-1 dark:border-gray-300">
<div <div
className={`caption-font my-2 text-black dark:text-white flex justify-center whitespace-normal break-words text-3xl font-bold capitalize`} className={
"caption-font my-2 flex justify-center whitespace-normal break-words font-bold text-3xl text-black capitalize dark:text-white"
}
> >
{props.frontMatter?.title} {props.frontMatter?.title}
</div> </div>
{props.frontMatter?.subtitle && ( {props.frontMatter?.subtitle && (
<div className={`caption-font my-1 flex justify-center text-xl font-bold capitalize`}> <div className={"caption-font my-1 flex justify-center font-bold text-xl capitalize"}>
{props.frontMatter.subtitle} {props.frontMatter.subtitle}
</div> </div>
)} )}
<div className="my-1 flex justify-center text-sm italic">{normalizeDate(props.frontMatter?.time)}</div> <div className="my-1 flex justify-center text-sm italic">{normalizeDate(props.frontMatter?.time)}</div>
{props.frontMatter?.summary && ( {props.frontMatter?.summary && (
<p className={"content-font my-4 indent-8 text-gray-800 dark:text-gray-300"}> <p className={"my-4 indent-8 text-gray-800 content-font dark:text-gray-300"}>
{props.frontMatter?.summary} {props.frontMatter?.summary}
</p> </p>
)} )}
{props.frontMatter.tags && ( {props.frontMatter.tags && (
<div className={"pt-1 flex flex-wrap border-t-2 border-black dark:border-gray-300"}> <div className={"flex flex-wrap border-black border-t-2 pt-1 dark:border-gray-300"}>
{props.frontMatter.tags.map((tagName) => ( {props.frontMatter.tags.map((tagName) => (
<Link <Link
className="not-prose mr-2 px-2 py-1 font-bold border-2 border-black dark:border-gray-300 my-1 text-gray-700 hover:text-black text-xs dark:text-gray-300 dark:hover:text-gray-200" 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}`} href={`/tags/${tagName}`}
key={`tags-${nanoid()}`} key={`tags-${nanoid()}`}
> >
@@ -135,7 +137,7 @@ const ReaderPage = (props: ReaderPageProps) => {
title={props.frontMatter.title} title={props.frontMatter.title}
/> />
<Separator /> <Separator />
<ul className="my-5 px-5 flex flex-col justify-center list-disc"> <ul className="my-5 flex list-disc flex-col justify-center px-5">
{props.prevPostListItem && ( {props.prevPostListItem && (
<li className="my-1"> <li className="my-1">
<Link <Link
@@ -160,7 +162,7 @@ const ReaderPage = (props: ReaderPageProps) => {
{Config.Giscus?.enabled && <PostComments postId={props.postId} />} {Config.Giscus?.enabled && <PostComments postId={props.postId} />}
</div> </div>
{isTOCLongEnough && ( {isTOCLongEnough && (
<div className="hidden lg:block md:w-1/3 py-5"> <div className="hidden py-5 md:w-1/3 lg:block">
<div className="sticky top-[5em]"> <div className="sticky top-[5em]">
<TOC data={props.tocList} /> <TOC data={props.tocList} />
</div> </div>

View File

@@ -14,9 +14,9 @@ export default function FriendsPage() {
<SEO description={"My Friend Links"} title={`${Config.SiteTitle} - Friends`} /> <SEO description={"My Friend Links"} title={`${Config.SiteTitle} - Friends`} />
<NavBar /> <NavBar />
<ContentContainer> <ContentContainer>
<h2 className={`my-5 flex justify-center text-2xl font-bold caption-font`}>{"FRIENDS"}</h2> <h2 className={"caption-font my-5 flex justify-center font-bold text-2xl"}>{"FRIENDS"}</h2>
<Separator /> <Separator />
<div className={`my-5 flex flex-wrap justify-center text-2xl content-font`}> <div className={"my-5 flex flex-wrap justify-center text-2xl content-font"}>
{FriendsList.map((item) => ( {FriendsList.map((item) => (
<Link className="mx-2 p-2 underline" href={item.url} key={nanoid()}> <Link className="mx-2 p-2 underline" href={item.url} key={nanoid()}>
{item.title} {item.title}
@@ -24,7 +24,7 @@ export default function FriendsPage() {
))} ))}
</div> </div>
<Separator /> <Separator />
<div className="my-2 text-base flex-col flex justify-start"> <div className="my-2 flex flex-col justify-start text-base">
<div className="mx-auto"> <div className="mx-auto">
{"Welcome to exchange our friend links and every high-quality blog websites are welcomed. "} {"Welcome to exchange our friend links and every high-quality blog websites are welcomed. "}
<Link className="underline" href={`mailto:${Config.SocialLinks.email}`}> <Link className="underline" href={`mailto:${Config.SocialLinks.email}`}>

View File

@@ -10,8 +10,8 @@ import { LatestPostCountInHomePage } from "@/consts/consts";
import { Config } from "@/data/config"; import { Config } from "@/data/config";
import { sortedPosts } from "@/lib/post-process"; import { sortedPosts } from "@/lib/post-process";
import { generateRSSFeed } from "@/lib/rss"; import { generateRSSFeed } from "@/lib/rss";
import { TPostListItem } from "@/types/post-list"; import type { TPostListItem } from "@/types/post-list";
import { GetStaticProps } from "next"; import type { GetStaticProps } from "next";
import Link from "next/link"; import Link from "next/link";
import { LuPenTool } from "react-icons/lu"; import { LuPenTool } from "react-icons/lu";
import { RiStarFill } from "react-icons/ri"; import { RiStarFill } from "react-icons/ri";
@@ -35,7 +35,7 @@ export default function Home(props: HomePageProps) {
{props.pinnedPostList.length !== 0 && ( {props.pinnedPostList.length !== 0 && (
<div> <div>
<Separator /> <Separator />
<h2 className={`my-5 flex justify-center text-2xl font-bold caption-font`}> <h2 className={"caption-font my-5 flex justify-center font-bold text-2xl"}>
<RiStarFill className="mx-2 my-auto" /> <RiStarFill className="mx-2 my-auto" />
{"PINNED POSTS"} {"PINNED POSTS"}
</h2> </h2>
@@ -46,7 +46,7 @@ export default function Home(props: HomePageProps) {
{props.latestPostList.length !== 0 && ( {props.latestPostList.length !== 0 && (
<div> <div>
<Separator /> <Separator />
<h2 className={`my-5 flex justify-center text-2xl font-bold caption-font`}> <h2 className={"caption-font my-5 flex justify-center font-bold text-2xl"}>
<LuPenTool className="mx-2 my-auto" /> <LuPenTool className="mx-2 my-auto" />
{"LATEST POSTS"} {"LATEST POSTS"}
</h2> </h2>

View File

@@ -11,12 +11,12 @@ import { PostCountPerPagination } from "@/consts/consts";
import { Config } from "@/data/config"; import { Config } from "@/data/config";
import { sortedPosts } from "@/lib/post-process"; import { sortedPosts } from "@/lib/post-process";
import { isEmptyArray, paginateArray } from "@/lib/utils"; import { isEmptyArray, paginateArray } from "@/lib/utils";
import { TPostListItem } from "@/types/post-list"; import type { TPostListItem } from "@/types/post-list";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { GetStaticPaths, GetStaticProps } from "next"; import type { GetStaticPaths, GetStaticProps } from "next";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { ChangeEvent, KeyboardEvent, useEffect, useState } from "react"; import { type ChangeEvent, type KeyboardEvent, useEffect, useState } from "react";
import { LuPenTool } from "react-icons/lu"; import { LuPenTool } from "react-icons/lu";
type PostsPageProps = { type PostsPageProps = {
@@ -32,7 +32,7 @@ export default function PostsPage(props: PostsPageProps) {
const handleEnterKeyJump = (event: KeyboardEvent<HTMLInputElement>) => { const handleEnterKeyJump = (event: KeyboardEvent<HTMLInputElement>) => {
setPageNumber(pageNumber.replace(/[^\d]/g, "")); setPageNumber(pageNumber.replace(/[^\d]/g, ""));
if (parseInt(pageNumber) > 0 && parseInt(pageNumber) < props.pageAmount + 1) { if (Number.parseInt(pageNumber) > 0 && Number.parseInt(pageNumber) < props.pageAmount + 1) {
(event.key === "Go" || event.key === "Enter") && router.push(`/posts/${pageNumber}`); (event.key === "Go" || event.key === "Enter") && router.push(`/posts/${pageNumber}`);
return; return;
} }
@@ -55,20 +55,20 @@ export default function PostsPage(props: PostsPageProps) {
/> />
<NavBar /> <NavBar />
<ContentContainer> <ContentContainer>
<h2 className={`my-5 flex justify-center text-2xl caption-font font-bold`}> <h2 className={"caption-font my-5 flex justify-center font-bold text-2xl"}>
<LuPenTool className="mx-2 my-auto" /> <LuPenTool className="mx-2 my-auto" />
{"ALL POSTS"} {"ALL POSTS"}
</h2> </h2>
{!isEmptyArray(props.tagList) && ( {!isEmptyArray(props.tagList) && (
<Accordion collapsible type="single"> <Accordion collapsible type="single">
<AccordionItem className="border-t" value="item-1"> <AccordionItem className="border-t" value="item-1">
<AccordionTrigger className="hover:no-underline font-bold">{"TAG FILTER"}</AccordionTrigger> <AccordionTrigger className="font-bold hover:no-underline">{"TAG FILTER"}</AccordionTrigger>
<AccordionContent> <AccordionContent>
<Separator /> <Separator />
<div className={`my-5 flex flex-wrap text-wrap text-sm justify-center px-2`}> <div className={"my-5 flex flex-wrap justify-center text-wrap px-2 text-sm"}>
{props.tagList.map((item) => ( {props.tagList.map((item) => (
<Link <Link
className="m-1 p-1 underline underline-offset-[5px] my-auto text-gray-700 decoration-2 hover:text-black dark:text-gray-300 dark:hover:text-white font-bold" className="m-1 my-auto p-1 font-bold text-gray-700 underline decoration-2 underline-offset-[5px] hover:text-black dark:text-gray-300 dark:hover:text-white"
href={`/tags/${item.name}`} href={`/tags/${item.name}`}
key={`tags-${nanoid()}`} key={`tags-${nanoid()}`}
> >
@@ -83,7 +83,7 @@ export default function PostsPage(props: PostsPageProps) {
<Separator /> <Separator />
<PostList data={props.postList} /> <PostList data={props.postList} />
<Separator /> <Separator />
<div className="my-5 flex justify-between text-base font-bold"> <div className="my-5 flex justify-between font-bold text-base">
{props.pageNumber !== 1 && ( {props.pageNumber !== 1 && (
<Button asChild> <Button asChild>
<Link className="font-bold" href={`/posts/${props.pageNumber - 1}/`}> <Link className="font-bold" href={`/posts/${props.pageNumber - 1}/`}>
@@ -91,9 +91,9 @@ export default function PostsPage(props: PostsPageProps) {
</Link> </Link>
</Button> </Button>
)} )}
<div className="my-auto font-bold flex justify-center"> <div className="my-auto flex justify-center font-bold">
<Input <Input
className="my-auto mx-2 w-11 h-6" className="mx-2 my-auto h-6 w-11"
onChange={handleInputPageNumber} onChange={handleInputPageNumber}
onKeyDown={handleEnterKeyJump} onKeyDown={handleEnterKeyJump}
title="Type the specified page number and press Enter to jump." title="Type the specified page number and press Enter to jump."
@@ -130,9 +130,9 @@ export const getStaticPaths: GetStaticPaths = () => {
export const getStaticProps: GetStaticProps<PostsPageProps> = async (context) => { export const getStaticProps: GetStaticProps<PostsPageProps> = async (context) => {
const params = (context.params?.slug as string[]) ?? []; const params = (context.params?.slug as string[]) ?? [];
const pageNumber = params[0] ? parseInt(params[0]) : 1; const pageNumber = params[0] ? Number.parseInt(params[0]) : 1;
let postList: TPostListItem[] = paginateArray(sortedPosts.allPostList, PostCountPerPagination, pageNumber); const postList: TPostListItem[] = paginateArray(sortedPosts.allPostList, PostCountPerPagination, pageNumber);
const pageAmount = Math.ceil(sortedPosts.allPostList.length / PostCountPerPagination); const pageAmount = Math.ceil(sortedPosts.allPostList.length / PostCountPerPagination);

View File

@@ -8,14 +8,14 @@ import { NavBar } from "@/components/utils/NavBar";
import { SEO } from "@/components/utils/SEO"; import { SEO } from "@/components/utils/SEO";
import { Config } from "@/data/config"; import { Config } from "@/data/config";
import { isEmptyString } from "@/lib/utils"; import { isEmptyString } from "@/lib/utils";
import { TSearchResultItem } from "@/types/search-result"; import type { TSearchResultItem } from "@/types/search-result";
import axios from "axios"; import axios from "axios";
import { isArray } from "lodash"; import { isArray } from "lodash";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { GetServerSideProps } from "next"; import type { GetServerSideProps } from "next";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { ChangeEvent, KeyboardEvent, useEffect, useState } from "react"; import { type ChangeEvent, type KeyboardEvent, useEffect, useState } from "react";
type SearchPageProps = { query: string | null }; type SearchPageProps = { query: string | null };
@@ -88,8 +88,8 @@ export default function SearchPage(props: SearchPageProps) {
<Toaster /> <Toaster />
<NavBar /> <NavBar />
<ContentContainer> <ContentContainer>
<h2 className={`my-10 flex justify-center text-2xl font-bold caption-font`}>{"SEARCH POSTS"}</h2> <h2 className={"caption-font my-10 flex justify-center font-bold text-2xl"}>{"SEARCH POSTS"}</h2>
<div className="flex my-10"> <div className="my-10 flex">
<Input <Input
className="my-auto py-0" className="my-auto py-0"
onChange={handleInputSearchText} onChange={handleInputSearchText}
@@ -97,26 +97,26 @@ export default function SearchPage(props: SearchPageProps) {
placeholder="Input the keyword" placeholder="Input the keyword"
value={searchText} value={searchText}
/> />
<Button className="mx-3 w-32 my-auto" disabled={isLoading} onClick={handleMakeSearch}> <Button className="mx-3 my-auto w-32" disabled={isLoading} onClick={handleMakeSearch}>
{isLoading ? "Loading" : "Search"} {isLoading ? "Loading" : "Search"}
</Button> </Button>
</div> </div>
<div className="flex flex-col justify-center"> <div className="flex flex-col justify-center">
<div className={`min-h-full flex flex-col content-font`}> <div className={"flex min-h-full flex-col content-font"}>
{searchResult.map((item, index) => ( {searchResult.map((item, index) => (
<Link <Link
className={`p-2 border-t ${index === searchResult.length - 1 && "border-b"} hover:bg-gray-50 dark:hover:bg-gray-900 flex flex-col`} className={`border-t p-2 ${index === searchResult.length - 1 && "border-b"} flex flex-col hover:bg-gray-50 dark:hover:bg-gray-900`}
href={`/blog/${item.id}`} href={`/blog/${item.id}`}
key={nanoid()} key={nanoid()}
target="_blank" target="_blank"
> >
<div className="my-1"> <div className="my-1">
<div className="capitalize post-list-caption-font text-md font-bold">{item.title}</div> <div className="post-list-caption-font font-bold text-md capitalize">{item.title}</div>
{item.summary && <div>{item.summary}</div>} {item.summary && <div>{item.summary}</div>}
</div> </div>
<div className="flex space-x-2 flex-wrap"> <div className="flex flex-wrap space-x-2">
{item.tags?.map((tagitem) => ( {item.tags?.map((tagitem) => (
<div className="text-sm text-gray-500 dark:text-gray-400" key={nanoid()}> <div className="text-gray-500 text-sm dark:text-gray-400" key={nanoid()}>
{tagitem} {tagitem}
</div> </div>
))} ))}
@@ -125,7 +125,7 @@ export default function SearchPage(props: SearchPageProps) {
))} ))}
</div> </div>
</div> </div>
<div className="text-center my-3 text-gray-500 dark:text-gray-400"> <div className="my-3 text-center text-gray-500 dark:text-gray-400">
<p className="mx-auto text-sm">{"For search efficiency, only the first 20 results are displayed."}</p> <p className="mx-auto text-sm">{"For search efficiency, only the first 20 results are displayed."}</p>
</div> </div>
</ContentContainer> </ContentContainer>

View File

@@ -20,15 +20,15 @@ export default function SponsorPage() {
<Toaster /> <Toaster />
<NavBar /> <NavBar />
<ContentContainer> <ContentContainer>
<div className="md:flex mt-10"> <div className="mt-10 md:flex">
<div className="flex flex-col justify-center md:w-1/2"> <div className="flex flex-col justify-center md:w-1/2">
<h2 className={`my-5 flex justify-center text-2xl font-bold text-red-500 caption-font`}> <h2 className={"caption-font my-5 flex justify-center font-bold text-2xl text-red-500"}>
<GoHeartFill className="mx-2 my-auto" /> <GoHeartFill className="mx-2 my-auto" />
{"SPONSOR"} {"SPONSOR"}
</h2> </h2>
<SponsorDescription /> <SponsorDescription />
</div> </div>
<div className="md:px-15 md:w-1/2"> <div className="md:w-1/2 md:px-15">
<SponsorBoard /> <SponsorBoard />
</div> </div>
</div> </div>

View File

@@ -10,11 +10,11 @@ import { PostCountPerPagination } from "@/consts/consts";
import { Config } from "@/data/config"; import { Config } from "@/data/config";
import { sortedPosts } from "@/lib/post-process"; import { sortedPosts } from "@/lib/post-process";
import { paginateArray } from "@/lib/utils"; import { paginateArray } from "@/lib/utils";
import { TPostListItem } from "@/types/post-list"; import type { TPostListItem } from "@/types/post-list";
import { GetStaticPaths, GetStaticProps } from "next"; import type { GetStaticPaths, GetStaticProps } from "next";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { ChangeEvent, KeyboardEvent, useEffect, useState } from "react"; import { type ChangeEvent, type KeyboardEvent, useEffect, useState } from "react";
type TagsContentPageProps = { type TagsContentPageProps = {
tagName: string | null; tagName: string | null;
@@ -29,7 +29,7 @@ export default function TagsContentPage(props: TagsContentPageProps) {
const handleEnterKeyJump = (event: KeyboardEvent<HTMLInputElement>) => { const handleEnterKeyJump = (event: KeyboardEvent<HTMLInputElement>) => {
setPageNumber(pageNumber.replace(/[^\d]/g, "")); setPageNumber(pageNumber.replace(/[^\d]/g, ""));
if (parseInt(pageNumber) > 0 && parseInt(pageNumber) < props.pageAmount + 1) { if (Number.parseInt(pageNumber) > 0 && Number.parseInt(pageNumber) < props.pageAmount + 1) {
(event.key === "Go" || event.key === "Enter") && router.push(`/tags/${props.tagName}/${pageNumber}`); (event.key === "Go" || event.key === "Enter") && router.push(`/tags/${props.tagName}/${pageNumber}`);
return; return;
} }
@@ -52,13 +52,13 @@ export default function TagsContentPage(props: TagsContentPageProps) {
/> />
<NavBar /> <NavBar />
<ContentContainer> <ContentContainer>
<h2 className={"my-5 flex flex-col justify-center text-center font-bold caption-font"}> <h2 className={"caption-font my-5 flex flex-col justify-center text-center font-bold"}>
<div className="mx-auto text-2xl">{`Posts of ${props.tagName}`}</div> <div className="mx-auto text-2xl">{`Posts of ${props.tagName}`}</div>
</h2> </h2>
<Separator /> <Separator />
<PostList data={props.postList} /> <PostList data={props.postList} />
<Separator /> <Separator />
<div className="my-5 flex justify-between text-base font-bold"> <div className="my-5 flex justify-between font-bold text-base">
{props.pageNumber !== 1 && ( {props.pageNumber !== 1 && (
<Button asChild> <Button asChild>
<Link className="font-bold" href={`/tags/${props.tagName}/${props.pageNumber - 1}/`}> <Link className="font-bold" href={`/tags/${props.tagName}/${props.pageNumber - 1}/`}>
@@ -66,9 +66,9 @@ export default function TagsContentPage(props: TagsContentPageProps) {
</Link> </Link>
</Button> </Button>
)} )}
<div className="my-auto font-bold flex justify-center"> <div className="my-auto flex justify-center font-bold">
<Input <Input
className="my-auto mx-2 w-11 h-6" className="mx-2 my-auto h-6 w-11"
onChange={handleInputPageNumber} onChange={handleInputPageNumber}
onKeyDown={handleEnterKeyJump} onKeyDown={handleEnterKeyJump}
title="Type the specified page number and press Enter to jump." title="Type the specified page number and press Enter to jump."
@@ -112,7 +112,7 @@ export const getStaticProps: GetStaticProps<TagsContentPageProps> = async (conte
const params = (context.params?.slug as string[]) ?? []; const params = (context.params?.slug as string[]) ?? [];
const tagName = params[0] ?? null; const tagName = params[0] ?? null;
const pageNumber = params[1] ? parseInt(params[1]) : 1; const pageNumber = params[1] ? Number.parseInt(params[1]) : 1;
let postList: TPostListItem[] = []; let postList: TPostListItem[] = [];
postList = paginateArray(sortedPosts.postsByTag[tagName], PostCountPerPagination, pageNumber); postList = paginateArray(sortedPosts.postsByTag[tagName], PostCountPerPagination, pageNumber);

View File

@@ -1,11 +1,11 @@
import * as fs from "fs";
import * as path from "path";
import { UserDataDirectory } from "@/consts/consts"; import { UserDataDirectory } from "@/consts/consts";
import { getCurrentTime } from "@/lib/date"; import { getCurrentTime } from "@/lib/date";
import { checkAndCreateDirectory, isDirectoryEmptySync } from "@/lib/file"; import { checkAndCreateDirectory, isDirectoryEmptySync } from "@/lib/file";
import archiver from "archiver"; import archiver from "archiver";
import Color from "colors"; import Color from "colors";
import * as fs from "fs";
import inquirer from "inquirer"; import inquirer from "inquirer";
import * as path from "path";
import * as tar from "tar"; import * as tar from "tar";
function packageDirectory(sourceDir: string, outputFilePath: string) { function packageDirectory(sourceDir: string, outputFilePath: string) {

View File

@@ -1,11 +1,11 @@
import { type ChildProcessWithoutNullStreams, type SpawnSyncReturns, spawn, spawnSync } from "child_process";
import fs from "fs";
import path from "path";
import { PostFilesDirectory } from "@/consts/consts"; import { PostFilesDirectory } from "@/consts/consts";
import { getCurrentTime } from "@/lib/date"; import { getCurrentTime } from "@/lib/date";
import { ChildProcessWithoutNullStreams, SpawnSyncReturns, spawn, spawnSync } from "child_process";
import colors from "colors"; import colors from "colors";
import fs from "fs"; import inquirer, { type QuestionCollection } from "inquirer";
import inquirer, { QuestionCollection } from "inquirer";
import _ from "lodash"; import _ from "lodash";
import path from "path";
import { titleCase } from "title-case"; import { titleCase } from "title-case";
type TAnswer = { type TAnswer = {

View File

@@ -19,20 +19,6 @@ module.exports = {
}, },
}, },
extend: { extend: {
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
fontFamily: { fontFamily: {
fangzhengxiaobiaosong: "--font-fangzhengxiaobiaosong", fangzhengxiaobiaosong: "--font-fangzhengxiaobiaosong",
sourceSerifScreenCN: "--content-font-cn", sourceSerifScreenCN: "--content-font-cn",

View File

@@ -1,4 +1,4 @@
import { NonEmptyArray } from "./utils.type"; import type { NonEmptyArray } from "./utils.type";
export type TFrontmatter = { export type TFrontmatter = {
title: string; title: string;

View File

@@ -1,4 +1,4 @@
import { TFrontmatter } from "./frontmatter.type"; import type { TFrontmatter } from "./frontmatter.type";
export type TPostListItem = { export type TPostListItem = {
id: string; id: string;