b8e7b94586
* docs: optimize route higtlight (#4520) * docs: optimize home display (#4519) * docs: optimize home display and route highlight * docs: optimize home display * fix(alert): propagate className (#4535) * fix(alert): propagate className * chore(alert): remove className from alert theme * fix(avatar): title type in Avatar (#4529) * fix(avatar): title type in Avatar * fix(alert): apply isEmpty check on title * fix(alert): alert interface props type * refactor: remove unnecessary props types (#4530) * refactor(docs): remove string type as it is included in ReactNode * refactor: remove unnecessary types * feat(changeset): add changeset * chore: remove changeset * refactor: remove null since ReactNode unions it already * fix(input): use onPress for wrapper click focus (#4483) * fix(input): use onPress for wrapper click focus * test(input): wrapper click focus test * chore(changeset): input onPress for wrapper click focus * chore(changeset): minor wording * Refactor/rebrand (#4532) * chore: rebrand in progress * chore: update docs to use heroui * chore: components renbranded * chore: figma moved to the docs files * fix: posthog config * fix(docs): extra classname in form example (#4465) * chore: clean git * chore: make heroui private * chore: new logo * chore: node env var renamed * chore: public robots txt deleted * chore: wrangler installed * chore: wrangler renamed * chore: cloudlfare workers removed * chore: force vercel deploy * refactor: first migration and provider * refactor: rename nextui plugin * refactor: rename github site * refactor: rename CONTRIBUTING * refactor: rename package name * refactor: nextjs image hostname * refactor: mdx repo nextui-org rename frontio-ai * refactor: nextui.org rename heroui.com * refactor: add heroui to missing places * fix: heroui plugin name * fix: update docs * docs: nextui to heroui add npmrc pnpm migratation * chore: rename all packages with new org name * chore: replace frontio-ai by frontioai * chore: revert previous changes * chore: small adjustment * chore: doc updated * feat: blog * chore: avatar updated * fix: url * chore: add new ogimage * fix: ogimage command * fix: heroui name and storybook welcome page * fix: og image url * feat: favicon and icon changed --------- Co-authored-by: աӄա <wingkwong.code@gmail.com> Co-authored-by: winches <329487092@qq.com> * fix: postbuild script * chore: core package updates * ci(changesets): version packages (#4569) Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * feat: contributors added to the blog --------- Co-authored-by: winches <329487092@qq.com> Co-authored-by: աӄա <wingkwong.code@gmail.com> Co-authored-by: Peterl561 <76144929+Peterl561@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
133 lines
3.6 KiB
TypeScript
133 lines
3.6 KiB
TypeScript
import type {Metadata} from "next";
|
|
|
|
import {notFound} from "next/navigation";
|
|
import {allBlogPosts} from "contentlayer2/generated";
|
|
import {Link, User} from "@heroui/react";
|
|
import {format, parseISO} from "date-fns";
|
|
import NextLink from "next/link";
|
|
import {Balancer} from "react-wrap-balancer";
|
|
|
|
import {__DEV__, __PREVIEW__} from "@/utils";
|
|
import {MDXContent} from "@/components/mdx-content";
|
|
import {siteConfig} from "@/config/site";
|
|
import {Route} from "@/libs/docs/page";
|
|
import {ChevronRightLinearIcon} from "@/components/icons";
|
|
|
|
interface BlogPostProps {
|
|
params: {
|
|
slug: string;
|
|
};
|
|
}
|
|
|
|
const isDraftVisible = __DEV__ || __PREVIEW__;
|
|
|
|
async function getBlogPostFromParams({params}: BlogPostProps) {
|
|
const slug = params.slug || "";
|
|
const post = allBlogPosts.find((post) => post.slugAsParams === slug);
|
|
|
|
if (!post) {
|
|
null;
|
|
}
|
|
|
|
const currentRoute: Route = {
|
|
key: post?._id,
|
|
title: post?.title,
|
|
path: `/${post?._raw?.sourceFilePath}`,
|
|
};
|
|
|
|
return {post, currentRoute};
|
|
}
|
|
|
|
export async function generateMetadata({params}: BlogPostProps): Promise<Metadata> {
|
|
const {post} = await getBlogPostFromParams({params});
|
|
|
|
if (!post) {
|
|
return {};
|
|
}
|
|
|
|
return {
|
|
title: post.title,
|
|
description: post.description,
|
|
openGraph: {
|
|
title: post.title,
|
|
description: post.description,
|
|
type: "article",
|
|
url: post.url,
|
|
images: [
|
|
{
|
|
url: post.imageAsParams || siteConfig.ogImage,
|
|
width: 1200,
|
|
height: 630,
|
|
alt: post.title || siteConfig.name,
|
|
},
|
|
],
|
|
},
|
|
twitter: {
|
|
card: "summary_large_image",
|
|
title: post.title,
|
|
description: post.description,
|
|
images: [siteConfig.ogImage],
|
|
creator: siteConfig.creator,
|
|
},
|
|
};
|
|
}
|
|
|
|
export async function generateStaticParams(): Promise<BlogPostProps["params"][]> {
|
|
return allBlogPosts.map((doc) => ({
|
|
slug: doc.slugAsParams,
|
|
}));
|
|
}
|
|
|
|
export default async function DocPage({params}: BlogPostProps) {
|
|
const {post} = await getBlogPostFromParams({params});
|
|
|
|
if (!post || (post.draft && !isDraftVisible)) {
|
|
notFound();
|
|
}
|
|
|
|
return (
|
|
<div className="w-full mt-12 flex flex-col justify-start items-center prose prose-neutral">
|
|
<div className="w-full max-w-4xl">
|
|
<Link
|
|
isBlock
|
|
as={NextLink}
|
|
className="mb-8 -ml-3 text-default-500 hover:text-default-900"
|
|
color="foreground"
|
|
href="/blog"
|
|
size="sm"
|
|
>
|
|
<ChevronRightLinearIcon className="rotate-180 inline-block mr-1" size={15} />
|
|
Back to blog
|
|
</Link>
|
|
|
|
<time className="block text-small mb-2 text-default-500" dateTime={post.date}>
|
|
{format(parseISO(post.date), "LLLL d, yyyy")}
|
|
</time>
|
|
<div className="mb-3 flex w-full flex-col items-start">
|
|
<User
|
|
isExternal
|
|
as={Link}
|
|
avatarProps={{
|
|
className: "w-9 h-9 text-large",
|
|
src: post.author?.avatar,
|
|
}}
|
|
className="hover:opacity-100"
|
|
classNames={{
|
|
base: "-ml-2 px-2 py-1.5 hover:bg-default-100 dark:hover:bg-default-50 cursor-pointer transition-colors",
|
|
name: "text-foreground",
|
|
}}
|
|
description={post.author?.username}
|
|
href={post.author?.link}
|
|
name={post.author?.name}
|
|
/>
|
|
</div>
|
|
<h1 className="mb-2 font-bold text-4xl">
|
|
<Balancer>{post.title}</Balancer>
|
|
<strong className="text-default-300">{post?.draft && " (Draft)"}</strong>
|
|
</h1>
|
|
<MDXContent code={post.body.code} />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|