From f2687c936efaf9b6dc20a48000b60a3694d5e91c Mon Sep 17 00:00:00 2001 From: Khairul Date: Mon, 24 Aug 2026 09:35:08 +0800 Subject: [PATCH] fix(footer): sync catalog stats with templates.json (#11) Drive footer + StatsBar counts from getTemplatesData() so hardcoded extensions (8) stop drifting from the live CPA catalog. --- src/app/layout.tsx | 8 ++++++-- src/app/page.tsx | 12 +++++++++--- src/components/layout-shell.tsx | 25 ++++++++++++++++++++----- src/components/stats-bar.tsx | 21 ++++++++++++++++++--- src/lib/data.ts | 15 +++++++++++++++ 5 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 2a2e918..4c378c6 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,7 @@ import { Inter, Space_Grotesk } from 'next/font/google'; import type React from 'react'; import '@/app/globals.css'; import { LayoutShell } from '@/components/layout-shell'; +import { catalogStatsFrom, getTemplatesData } from '@/lib/data'; import { jsonLdScript, organizationJsonLd, websiteJsonLd } from '@/lib/seo'; const siteUrl = 'https://create-awesome-python-app.vercel.app'; @@ -91,7 +92,10 @@ const spaceGrotesk = Space_Grotesk({ weight: ['400', '500', '600', '700'], }); -export default function RootLayout({ children }: { children: React.ReactNode }) { +export default async function RootLayout({ children }: { children: React.ReactNode }) { + const catalog = await getTemplatesData(); + const stats = catalogStatsFrom(catalog); + return ( @@ -105,7 +109,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) }), }} /> - {children} + {children} ); diff --git a/src/app/page.tsx b/src/app/page.tsx index 487469f..ded0d21 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -17,12 +17,14 @@ import { TemplateCategories } from '@/components/template-categories'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; import { DISCORD_INVITE_URL } from '@/lib/community'; -import { getTemplatesData } from '@/lib/data'; +import { catalogStatsFrom, getTemplatesData } from '@/lib/data'; const PRIMARY_COMMAND = 'uvx create-awesome-python-app my-app'; export default async function Home() { - const { templates, categories } = await getTemplatesData(); + const catalog = await getTemplatesData(); + const { templates, categories } = catalog; + const stats = catalogStatsFrom(catalog); const flagshipTemplate = templates.find((t) => t.slug === 'fastapi-starter'); const otherTemplates = templates.filter((t) => t.slug !== 'fastapi-starter'); @@ -72,7 +74,11 @@ export default async function Home() { sideVisual={} /> - + diff --git a/src/components/layout-shell.tsx b/src/components/layout-shell.tsx index e10e838..a73d201 100644 --- a/src/components/layout-shell.tsx +++ b/src/components/layout-shell.tsx @@ -8,7 +8,19 @@ import { PerformanceProvider } from '@/components/performance-provider'; import { SiteHeader } from '@/components/site-header'; import { ThemeProvider } from '@/components/theme-provider'; -export function LayoutShell({ children }: { children: ReactNode }) { +type CatalogStats = { + templates: number; + extensions: number; + categories: number; +}; + +export function LayoutShell({ + children, + stats = { templates: 5, extensions: 12, categories: 9 }, +}: { + children: ReactNode; + stats?: CatalogStats; +}) { const [open, setOpen] = useState(false); return ( @@ -26,19 +38,22 @@ export function LayoutShell({ children }: { children: ReactNode }) { {children}