Skip to content

Commit 5c9bfdd

Browse files
authored
Merge pull request #10 from objectstack-ai/docs/data-sources-blog
feat(docs): data-source / existing-system extension docs, homepage card, and blog
2 parents a4c100d + a78e1b7 commit 5c9bfdd

93 files changed

Lines changed: 10968 additions & 33 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/docs/app/[lang]/blog/[[...slug]]/page.tsx

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,41 @@ interface BlogPostData {
1818

1919
const components = getMDXComponents() as any;
2020

21+
// Locale-aware UI strings for the blog chrome. Post bodies are translated
22+
// via per-locale MDX files; these are the surrounding labels.
23+
const BLOG_UI: Record<
24+
string,
25+
{ title: string; subtitle: string; by: string; back: string; empty: string; dateLocale: string }
26+
> = {
27+
en: { title: 'Blog', subtitle: 'Insights, updates, and best practices from the ObjectStack team.', by: 'By', back: 'Back to Blog', empty: 'No blog posts yet. Check back soon!', dateLocale: 'en-US' },
28+
'zh-Hans': { title: '博客', subtitle: '来自 ObjectStack 团队的洞见、更新与最佳实践。', by: '作者', back: '返回博客', empty: '还没有博客文章,敬请期待!', dateLocale: 'zh-CN' },
29+
ja: { title: 'ブログ', subtitle: 'ObjectStack チームによる知見、アップデート、ベストプラクティス。', by: '著者', back: 'ブログに戻る', empty: 'まだ記事がありません。近日公開予定です!', dateLocale: 'ja-JP' },
30+
de: { title: 'Blog', subtitle: 'Einblicke, Neuigkeiten und Best Practices vom ObjectStack-Team.', by: 'Von', back: 'Zurück zum Blog', empty: 'Noch keine Beiträge. Schau bald wieder vorbei!', dateLocale: 'de-DE' },
31+
es: { title: 'Blog', subtitle: 'Ideas, novedades y buenas prácticas del equipo de ObjectStack.', by: 'Por', back: 'Volver al blog', empty: 'Aún no hay publicaciones. ¡Vuelve pronto!', dateLocale: 'es-ES' },
32+
fr: { title: 'Blog', subtitle: 'Analyses, actualités et bonnes pratiques de l’équipe ObjectStack.', by: 'Par', back: 'Retour au blog', empty: 'Pas encore d’articles. Revenez bientôt !', dateLocale: 'fr-FR' },
33+
ko: { title: '블로그', subtitle: 'ObjectStack 팀의 인사이트, 업데이트, 모범 사례.', by: '작성자', back: '블로그로 돌아가기', empty: '아직 게시글이 없습니다. 곧 다시 확인해 주세요!', dateLocale: 'ko-KR' },
34+
};
35+
2136
export default async function BlogPage({
2237
params,
2338
}: {
2439
params: Promise<{ lang: string; slug?: string[] }>;
2540
}) {
2641
const { slug, lang } = await params;
2742

43+
const ui = BLOG_UI[lang] ?? BLOG_UI.en;
44+
2845
// If no slug, show blog index
2946
if (!slug || slug.length === 0) {
30-
const posts = blog.getPages();
47+
const posts = blog.getPages(lang);
3148

3249
return (
3350
<HomeLayout {...baseOptions(lang)}>
3451
<main className="container max-w-5xl mx-auto px-4 py-16">
3552
<div className="mb-12">
36-
<h1 className="text-4xl font-bold mb-4">Blog</h1>
53+
<h1 className="text-4xl font-bold mb-4">{ui.title}</h1>
3754
<p className="text-lg text-fd-foreground/80">
38-
Insights, updates, and best practices from the ObjectStack team.
55+
{ui.subtitle}
3956
</p>
4057
</div>
4158

@@ -62,15 +79,15 @@ export default async function BlogPage({
6279
<div className="flex items-center gap-4 text-sm text-fd-foreground/70">
6380
{postData.date && (
6481
<time dateTime={postData.date}>
65-
{new Date(postData.date).toLocaleDateString('en-US', {
82+
{new Date(postData.date).toLocaleDateString(ui.dateLocale, {
6683
year: 'numeric',
6784
month: 'long',
6885
day: 'numeric',
6986
})}
7087
</time>
7188
)}
7289
{postData.author && (
73-
<span>By {postData.author}</span>
90+
<span>{ui.by} {postData.author}</span>
7491
)}
7592
</div>
7693

@@ -93,7 +110,7 @@ export default async function BlogPage({
93110

94111
{posts.length === 0 && (
95112
<div className="text-center py-12">
96-
<p className="text-fd-foreground/70">No blog posts yet. Check back soon!</p>
113+
<p className="text-fd-foreground/70">{ui.empty}</p>
97114
</div>
98115
)}
99116
</main>
@@ -102,8 +119,8 @@ export default async function BlogPage({
102119
}
103120

104121
// Show individual blog post
105-
const page = blog.getPage(slug);
106-
122+
const page = blog.getPage(slug, lang);
123+
107124
if (!page) {
108125
notFound();
109126
}
@@ -114,12 +131,12 @@ export default async function BlogPage({
114131
return (
115132
<HomeLayout {...baseOptions(lang)}>
116133
<main className="container max-w-4xl mx-auto px-4 py-16">
117-
<Link
118-
href="/blog"
134+
<Link
135+
href={lang === 'en' ? '/blog' : `/${lang}/blog`}
119136
className="inline-flex items-center gap-2 text-sm text-fd-foreground/70 hover:text-fd-foreground mb-8 transition-colors"
120137
>
121138
<ArrowLeft className="w-4 h-4" />
122-
Back to Blog
139+
{ui.back}
123140
</Link>
124141

125142
<article className="prose prose-neutral dark:prose-invert max-w-none">
@@ -135,15 +152,15 @@ export default async function BlogPage({
135152
<div className="flex items-center gap-4 text-sm text-fd-foreground/70">
136153
{pageData.date && (
137154
<time dateTime={pageData.date}>
138-
{new Date(pageData.date).toLocaleDateString('en-US', {
155+
{new Date(pageData.date).toLocaleDateString(ui.dateLocale, {
139156
year: 'numeric',
140157
month: 'long',
141158
day: 'numeric',
142159
})}
143160
</time>
144161
)}
145162
{pageData.author && (
146-
<span>By {pageData.author}</span>
163+
<span>{ui.by} {pageData.author}</span>
147164
)}
148165
</div>
149166

@@ -168,28 +185,26 @@ export default async function BlogPage({
168185
);
169186
}
170187

171-
export async function generateStaticParams() {
172-
return blog.getPages().map((page) => ({
173-
slug: page.slugs,
174-
}));
188+
export function generateStaticParams() {
189+
return blog.generateParams();
175190
}
176191

177192
export async function generateMetadata({
178193
params,
179194
}: {
180-
params: Promise<{ slug?: string[] }>;
195+
params: Promise<{ lang: string; slug?: string[] }>;
181196
}) {
182-
const { slug } = await params;
183-
197+
const { slug, lang } = await params;
198+
184199
// If no slug, return default metadata for blog index
185200
if (!slug || slug.length === 0) {
186201
return {
187202
title: 'Blog',
188203
description: 'Insights, updates, and best practices from the ObjectStack team.',
189204
};
190205
}
191-
192-
const page = blog.getPage(slug);
206+
207+
const page = blog.getPage(slug, lang);
193208

194209
if (!page) {
195210
notFound();

apps/docs/app/[lang]/layout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const LANGUAGE_NAMES: Record<string, string> = {
1010
de: 'Deutsch',
1111
es: 'Español',
1212
fr: 'Français',
13+
ko: '한국어',
1314
};
1415

1516
export default async function LanguageLayout({

apps/docs/app/[lang]/page.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Link from 'next/link';
2-
import { Server, Container, ShieldOff, KeyRound, Lock, LineChart, Wrench, ShieldCheck, Briefcase, Ship, Boxes, WifiOff, ArrowRight } from 'lucide-react';
2+
import { Server, Container, ShieldOff, KeyRound, Lock, LineChart, Wrench, ShieldCheck, Briefcase, Ship, Boxes, WifiOff, ArrowRight, Database } from 'lucide-react';
33
import { HomeLayout } from 'fumadocs-ui/layouts/home';
44
import { baseOptions } from '@/lib/layout.shared';
55
import { getHomepageTranslations } from '@/lib/homepage-i18n';
@@ -36,6 +36,13 @@ export default async function HomePage({
3636
];
3737

3838
const features = [
39+
{
40+
key: 'connectSystems',
41+
icon: Database,
42+
href: '/docs/configure/data-sources',
43+
title: t.features.connectSystems.title,
44+
description: t.features.connectSystems.description,
45+
},
3946
{
4047
key: 'selfHosted',
4148
icon: Server,

0 commit comments

Comments
 (0)