Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add i18n & TOC in blog page #32

Merged
merged 5 commits into from
Mar 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/[lang]/(home)/devbox/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function HomePage({ params }: { params: { lang: string } }) {
return (
<div className="h-full bg-[#EBF2FF]">
<Header lang={params.lang} />
<main className="custom-container pt-14">
<main className="custom-container px-8 pt-14 md:px-[15%]">
<Hero
title={title}
mainTitleEmphasis={1}
Expand Down
2 changes: 1 addition & 1 deletion app/[lang]/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function HomePage({ params }: { params: { lang: string } }) {
return (
<div className="h-full bg-[#EBF2FF]">
<Header lang={params.lang} />
<main className="custom-container pt-14">
<main className="custom-container px-8 pt-14 md:px-[15%]">
<Hero title={title} mainTitleEmphasis={2} getStartedLink={appDomain}>
<Video url="https://youtu.be/A9mxz0JaY2o" />
<div className="my-8 flex items-center justify-center">
Expand Down
203 changes: 120 additions & 83 deletions app/[lang]/blog/[slug]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,103 +8,136 @@ import Link from 'next/link';
import { notFound } from 'next/navigation';
import type { ReactNode } from 'react';
import { Fragment } from 'react';

import { DocsPage } from 'fumadocs-ui/page';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import '../blog.module.css';
export default async function BlogLayout({
params,
children,
}: {
params: { lang: string; slug: string };
children: ReactNode;
}) {
const page = blog.getPage([params.slug]);
const page = blog.getPage([params.slug], params.lang);

console.log(page);
if (!page) notFound();
const category = getPageCategory(page);

// inline style: set the postion for toc; set as a global style will make docs page strange

return (
<main
className="mx-auto w-full max-w-[900px] py-10 sm:py-20"
itemType="http://schema.org/Article"
itemScope
<DocsLayout
sidebar={{
enabled: false,
tabs: false,
}}
tree={blog.pageTree[params.lang]}
>
<div className="mb-10 overflow-hidden rounded-2xl bg-gradient-to-b from-primary/10 to-background ">
<div className="relative h-[250px] w-full">
<Image
src={getBlogImage(encodeURI(page.data.title))}
alt={page.data.title}
fill
className="object-cover"
priority
itemProp="image"
/>
</div>
<div className="px-8 py-6">
<div className="mb-2 flex flex-wrap items-center justify-between gap-2">
<div></div>
<div className="flex items-center gap-2">
<span className="inline-block rounded-full bg-primary/15 px-3 py-1 text-xs font-medium text-primary">
{category.toUpperCase()}
</span>
<span className="text-sm text-muted-foreground">
{new Date(page.data.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
})}
</span>
<style>
{`@media (min-width: 768px) {
.md\\:\\[--fd-nav-height\\:0px\\] {
--fd-nav-height: 100px !important;
}
}`}
</style>
<DocsPage
toc={page.data.toc}
tableOfContent={{
style: 'clerk',
single: false,
}}
tableOfContentPopover={{
style: 'normal',
}}
breadcrumb={{
enabled: false,
}}
>
<article
className="custom-container mx-auto w-full max-w-[900px] px-8 py-10 sm:py-20 md:px-[15%]"
itemType="http://schema.org/Article"
itemScope
>
<div className="mb-10 overflow-hidden rounded-2xl bg-gradient-to-b from-primary/10 to-background ">
<div className="relative h-[250px] w-full">
<Image
src={getBlogImage(encodeURI(page.data.title))}
alt={page.data.title}
fill
className="object-cover"
priority
itemProp="image"
/>
</div>
</div>
<h1
className="mb-4 text-4xl font-bold tracking-tight text-foreground"
itemProp="name"
>
{page.data.title}
</h1>
<div className="px-8 py-6">
<div className="mb-2 flex flex-wrap items-center justify-between gap-2">
<div></div>
<div className="flex items-center gap-2">
<span className="inline-block rounded-full bg-primary/15 px-3 py-1 text-xs font-medium text-primary">
{category.toUpperCase()}
</span>
<span className="text-sm text-muted-foreground">
{new Date(page.data.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
})}
</span>
</div>
</div>
<h1
className="mb-4 text-4xl font-bold tracking-tight text-foreground"
itemProp="name"
>
{page.data.title}
</h1>

{page.data.description && (
<p
className="mb-6 text-lg text-muted-foreground"
itemProp="description"
>
{page.data.description}
</p>
)}
{page.data.description && (
<p
className="mb-6 text-lg text-muted-foreground"
itemProp="description"
>
{page.data.description}
</p>
)}

<div className="flex flex-wrap items-center justify-between gap-4 border-t border-border pt-4">
<div className="flex flex-wrap items-center gap-4">
<div className="flex -space-x-2">
{page.data.authors.map((author, i) => (
<div
key={i}
className="z-[1] hover:z-10"
style={{ zIndex: page.data.authors.length - i }}
>
<AuthorAvatar author={blogAuthors[author]} />
<div className="flex flex-wrap items-center justify-between gap-4 border-t border-border pt-4">
<div className="flex flex-wrap items-center gap-4">
<div className="flex -space-x-2">
{page.data.authors.map((author, i) => (
<div
key={i}
className="z-[1] hover:z-10"
style={{ zIndex: page.data.authors.length - i }}
>
<AuthorAvatar author={blogAuthors[author]} />
</div>
))}
</div>
))}
</div>
<div className="flex flex-col">
<div className="flex flex-wrap items-center gap-1">
{page.data.authors.map((author, i) => (
<Fragment key={i}>
{i !== 0 && (
<span className="text-muted-foreground">&</span>
)}
<span className="font-medium">
{blogAuthors[author].name}
<div className="flex flex-col">
<div className="flex flex-wrap items-center gap-1">
{page.data.authors.map((author, i) => (
<Fragment key={i}>
{i !== 0 && (
<span className="text-muted-foreground">&</span>
)}
<span className="font-medium">
{blogAuthors[author].name}
</span>
</Fragment>
))}
</div>
{page.data.authors.length === 1 && (
<span className="text-sm text-muted-foreground">
{blogAuthors[page.data.authors[0]].title}
</span>
</Fragment>
))}
)}
</div>
</div>
{page.data.authors.length === 1 && (
<span className="text-sm text-muted-foreground">
{blogAuthors[page.data.authors[0]].title}
</span>
)}
</div>
</div>

{/* Tags section */}
{/* {page.data.tags && page.data.tags.length > 0 && (
{/* Tags section */}
{/* {page.data.tags && page.data.tags.length > 0 && (
<div className="flex flex-wrap items-center gap-2">
{page.data.tags.map((tag: string, index: number) => (
<span
Expand All @@ -116,12 +149,16 @@ export default async function BlogLayout({
))}
</div>
)} */}
</div>
</div>
</div>
</div>
</div>
<div className="blog-content -mt-4 w-full border-t pt-8">{children}</div>
<Cta />
</main>
<div className="blog-content -mt-4 w-full border-t pt-8">
{children}
</div>
<Cta />
</article>
</DocsPage>
</DocsLayout>
);
}

Expand Down
4 changes: 2 additions & 2 deletions app/[lang]/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { generateBlogMetadata } from '@/lib/utils/metadata';
export default async function BlogPage({
params,
}: {
params: Promise<{ slug: string }>;
params: Promise<{ lang: string; slug: string }>;
}) {
const page = blog.getPage([(await params).slug]);
const page = blog.getPage([(await params).slug], (await params).lang);
if (!page) notFound();

const Content = page.data.body;
Expand Down
1 change: 1 addition & 0 deletions app/[lang]/blog/blog.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
position: sticky;
padding-top: 100px !important;
}

2 changes: 1 addition & 1 deletion app/[lang]/blog/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default async function BlogIndex({ searchParams }: BlogIndexProps) {
const posts = getSortedBlogPosts({ tags: selectedTags });

return (
<main className="flex flex-1 flex-col pb-20">
<main className="flex flex-1 flex-col pb-20 mx-8 md:mx-[15%]">
<BlogHeader
title="Blog"
description="Sharing our technical insights, product updates and industry news"
Expand Down
Loading