Skip to content

Commit a6c4c52

Browse files
Copilothotlong
andcommitted
Fix blog routing conflict by merging listing and post pages
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 4cc06e3 commit a6c4c52

File tree

2 files changed

+200
-178
lines changed

2 files changed

+200
-178
lines changed

apps/site/app/blog/[[...slug]]/page.tsx

Lines changed: 200 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -6,108 +6,206 @@ import { HomeLayout } from 'fumadocs-ui/home-layout';
66
import { baseOptions } from '@/app/layout.config';
77
import Link from 'next/link';
88

9-
export default async function BlogPostPage({
9+
// Blog listing component
10+
function BlogListing() {
11+
const posts = blogSource.getPages();
12+
13+
return (
14+
<div className="mx-auto max-w-4xl">
15+
<div className="mb-12 text-center">
16+
<h1 className="text-4xl font-bold tracking-tight sm:text-5xl mb-4">
17+
ObjectQL Blog
18+
</h1>
19+
<p className="text-lg text-muted-foreground">
20+
Updates, tutorials, and insights about the standard protocol for AI software generation
21+
</p>
22+
</div>
23+
24+
<div className="space-y-8">
25+
{posts
26+
.sort((a, b) => {
27+
const dateA = new Date(a.data.date || 0);
28+
const dateB = new Date(b.data.date || 0);
29+
return dateB.getTime() - dateA.getTime();
30+
})
31+
.map((post) => (
32+
<article
33+
key={post.url}
34+
className="group rounded-xl border bg-card p-6 transition-all hover:shadow-md"
35+
>
36+
<Link href={post.url} className="block">
37+
<div className="mb-2 flex items-center gap-4 text-sm text-muted-foreground">
38+
{post.data.date && (
39+
<time dateTime={post.data.date}>
40+
{new Date(post.data.date).toLocaleDateString('en-US', {
41+
year: 'numeric',
42+
month: 'long',
43+
day: 'numeric',
44+
})}
45+
</time>
46+
)}
47+
{post.data.authors && (
48+
<span>by {post.data.authors.join(', ')}</span>
49+
)}
50+
</div>
51+
52+
<h2 className="mb-2 text-2xl font-bold group-hover:text-primary transition-colors">
53+
{post.data.title}
54+
</h2>
55+
56+
{post.data.description && (
57+
<p className="text-muted-foreground mb-4">
58+
{post.data.description}
59+
</p>
60+
)}
61+
62+
{post.data.tags && post.data.tags.length > 0 && (
63+
<div className="flex flex-wrap gap-2">
64+
{post.data.tags.map((tag: string) => (
65+
<span
66+
key={tag}
67+
className="inline-flex items-center rounded-full bg-primary/10 px-3 py-1 text-xs font-medium text-primary"
68+
>
69+
{tag}
70+
</span>
71+
))}
72+
</div>
73+
)}
74+
</Link>
75+
</article>
76+
))}
77+
</div>
78+
79+
{posts.length === 0 && (
80+
<div className="text-center py-12">
81+
<p className="text-muted-foreground">No blog posts yet. Check back soon!</p>
82+
</div>
83+
)}
84+
</div>
85+
);
86+
}
87+
88+
// Blog post component
89+
function BlogPost({ page }: { page: any }) {
90+
const MDX = page.data.body;
91+
92+
return (
93+
<article className="mx-auto max-w-4xl">
94+
<Link
95+
href="/blog"
96+
className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground mb-8 transition-colors"
97+
>
98+
<svg
99+
xmlns="http://www.w3.org/2000/svg"
100+
width="16"
101+
height="16"
102+
viewBox="0 0 24 24"
103+
fill="none"
104+
stroke="currentColor"
105+
strokeWidth="2"
106+
strokeLinecap="round"
107+
strokeLinejoin="round"
108+
className="mr-2"
109+
>
110+
<polyline points="15 18 9 12 15 6" />
111+
</svg>
112+
Back to Blog
113+
</Link>
114+
115+
<header className="mb-8">
116+
<h1 className="text-4xl font-bold tracking-tight sm:text-5xl mb-4">
117+
{page.data.title}
118+
</h1>
119+
120+
{page.data.description && (
121+
<p className="text-xl text-muted-foreground mb-4">
122+
{page.data.description}
123+
</p>
124+
)}
125+
126+
<div className="flex flex-wrap items-center gap-4 text-sm text-muted-foreground border-t pt-4">
127+
{page.data.date && (
128+
<time dateTime={page.data.date}>
129+
{new Date(page.data.date).toLocaleDateString('en-US', {
130+
year: 'numeric',
131+
month: 'long',
132+
day: 'numeric',
133+
})}
134+
</time>
135+
)}
136+
{page.data.authors && (
137+
<span>by {page.data.authors.join(', ')}</span>
138+
)}
139+
</div>
140+
141+
{page.data.tags && page.data.tags.length > 0 && (
142+
<div className="flex flex-wrap gap-2 mt-4">
143+
{page.data.tags.map((tag: string) => (
144+
<span
145+
key={tag}
146+
className="inline-flex items-center rounded-full bg-primary/10 px-3 py-1 text-xs font-medium text-primary"
147+
>
148+
{tag}
149+
</span>
150+
))}
151+
</div>
152+
)}
153+
</header>
154+
155+
<div className="prose prose-slate dark:prose-invert max-w-none">
156+
<MDX components={{ ...defaultMdxComponents }} />
157+
</div>
158+
159+
<footer className="mt-12 pt-8 border-t">
160+
<Link
161+
href="/blog"
162+
className="inline-flex items-center text-sm text-primary hover:underline"
163+
>
164+
<svg
165+
xmlns="http://www.w3.org/2000/svg"
166+
width="16"
167+
height="16"
168+
viewBox="0 0 24 24"
169+
fill="none"
170+
stroke="currentColor"
171+
strokeWidth="2"
172+
strokeLinecap="round"
173+
strokeLinejoin="round"
174+
className="mr-2"
175+
>
176+
<polyline points="15 18 9 12 15 6" />
177+
</svg>
178+
Back to Blog
179+
</Link>
180+
</footer>
181+
</article>
182+
);
183+
}
184+
185+
export default async function BlogPage({
10186
params,
11187
}: {
12188
params: { slug?: string[] };
13189
}) {
190+
// If no slug, show blog listing
191+
if (!params.slug || params.slug.length === 0) {
192+
return (
193+
<HomeLayout {...baseOptions}>
194+
<main className="container py-12 md:py-24">
195+
<BlogListing />
196+
</main>
197+
</HomeLayout>
198+
);
199+
}
200+
201+
// Otherwise, show individual blog post
14202
const page = blogSource.getPage(params.slug);
15203
if (!page) notFound();
16204

17-
const MDX = page.data.body;
18-
19205
return (
20206
<HomeLayout {...baseOptions}>
21207
<main className="container py-12 md:py-24">
22-
<article className="mx-auto max-w-4xl">
23-
<Link
24-
href="/blog"
25-
className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground mb-8 transition-colors"
26-
>
27-
<svg
28-
xmlns="http://www.w3.org/2000/svg"
29-
width="16"
30-
height="16"
31-
viewBox="0 0 24 24"
32-
fill="none"
33-
stroke="currentColor"
34-
strokeWidth="2"
35-
strokeLinecap="round"
36-
strokeLinejoin="round"
37-
className="mr-2"
38-
>
39-
<polyline points="15 18 9 12 15 6" />
40-
</svg>
41-
Back to Blog
42-
</Link>
43-
44-
<header className="mb-8">
45-
<h1 className="text-4xl font-bold tracking-tight sm:text-5xl mb-4">
46-
{page.data.title}
47-
</h1>
48-
49-
{page.data.description && (
50-
<p className="text-xl text-muted-foreground mb-4">
51-
{page.data.description}
52-
</p>
53-
)}
54-
55-
<div className="flex flex-wrap items-center gap-4 text-sm text-muted-foreground border-t pt-4">
56-
{page.data.date && (
57-
<time dateTime={page.data.date}>
58-
{new Date(page.data.date).toLocaleDateString('en-US', {
59-
year: 'numeric',
60-
month: 'long',
61-
day: 'numeric',
62-
})}
63-
</time>
64-
)}
65-
{page.data.authors && (
66-
<span>by {page.data.authors.join(', ')}</span>
67-
)}
68-
</div>
69-
70-
{page.data.tags && page.data.tags.length > 0 && (
71-
<div className="flex flex-wrap gap-2 mt-4">
72-
{page.data.tags.map((tag: string) => (
73-
<span
74-
key={tag}
75-
className="inline-flex items-center rounded-full bg-primary/10 px-3 py-1 text-xs font-medium text-primary"
76-
>
77-
{tag}
78-
</span>
79-
))}
80-
</div>
81-
)}
82-
</header>
83-
84-
<div className="prose prose-slate dark:prose-invert max-w-none">
85-
<MDX components={{ ...defaultMdxComponents }} />
86-
</div>
87-
88-
<footer className="mt-12 pt-8 border-t">
89-
<Link
90-
href="/blog"
91-
className="inline-flex items-center text-sm text-primary hover:underline"
92-
>
93-
<svg
94-
xmlns="http://www.w3.org/2000/svg"
95-
width="16"
96-
height="16"
97-
viewBox="0 0 24 24"
98-
fill="none"
99-
stroke="currentColor"
100-
strokeWidth="2"
101-
strokeLinecap="round"
102-
strokeLinejoin="round"
103-
className="mr-2"
104-
>
105-
<polyline points="15 18 9 12 15 6" />
106-
</svg>
107-
Back to Blog
108-
</Link>
109-
</footer>
110-
</article>
208+
<BlogPost page={page} />
111209
</main>
112210
</HomeLayout>
113211
);
@@ -118,6 +216,15 @@ export async function generateStaticParams() {
118216
}
119217

120218
export function generateMetadata({ params }: { params: { slug?: string[] } }): Metadata {
219+
// Default metadata for blog listing
220+
if (!params.slug || params.slug.length === 0) {
221+
return {
222+
title: 'Blog',
223+
description: 'Updates, tutorials, and insights about the standard protocol for AI software generation',
224+
};
225+
}
226+
227+
// Metadata for individual blog post
121228
const page = blogSource.getPage(params.slug);
122229
if (!page) notFound();
123230

@@ -126,3 +233,4 @@ export function generateMetadata({ params }: { params: { slug?: string[] } }): M
126233
description: page.data.description,
127234
};
128235
}
236+

0 commit comments

Comments
 (0)