From a8251142a1b86c371c54379fd817e6d53e3076ed Mon Sep 17 00:00:00 2001
From: Justin Levine <20596508+justinlevinedotme@users.noreply.github.com>
Date: Mon, 30 Mar 2026 13:13:17 -0700
Subject: [PATCH] fix(docs): restore components page, fix nav links, fix repo
logo
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Add dedicated /docs/page.tsx with component card grid (lost in Fumadocs migration)
- Convert [[...slug]] to [...slug] to avoid catch-all conflict
- Fix mobile nav Releases link (/docs/changelog → /docs/releases)
- Remove Releases from desktop navbar
- Fix README logo path (./public/ → ./apps/docs/public/)
---
README.md | 2 +-
.../docs/{[[...slug]] => [...slug]}/page.tsx | 13 +-
apps/docs/app/docs/layout.tsx | 3 -
apps/docs/app/docs/page.tsx | 124 ++++++++++++++++++
apps/docs/lib/docs.ts | 2 +-
5 files changed, 134 insertions(+), 10 deletions(-)
rename apps/docs/app/docs/{[[...slug]] => [...slug]}/page.tsx (92%)
create mode 100644 apps/docs/app/docs/page.tsx
diff --git a/README.md b/README.md
index 720dd16..ccc2fcd 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
+
diff --git a/apps/docs/app/docs/[[...slug]]/page.tsx b/apps/docs/app/docs/[...slug]/page.tsx
similarity index 92%
rename from apps/docs/app/docs/[[...slug]]/page.tsx
rename to apps/docs/app/docs/[...slug]/page.tsx
index 77d5c01..8e1a874 100644
--- a/apps/docs/app/docs/[[...slug]]/page.tsx
+++ b/apps/docs/app/docs/[...slug]/page.tsx
@@ -9,10 +9,10 @@ import { generateComponentPrompt } from "@/lib/prompts"
import { getRegistryItem } from "@/lib/registry"
export default async function Page(props: {
- params: Promise<{ slug?: string[] }>
+ params: Promise<{ slug: string[] }>
}) {
const params = await props.params
- const slug = params.slug ?? []
+ const slug = params.slug
const page = source.getPage(slug)
if (!page) notFound()
@@ -101,14 +101,17 @@ export default async function Page(props: {
}
export function generateStaticParams() {
- return source.generateParams()
+ // Filter out the root page — it's handled by the dedicated /docs/page.tsx
+ return source.generateParams().filter(
+ (p: { slug: string[] }) => p.slug.length > 0
+ )
}
export async function generateMetadata(props: {
- params: Promise<{ slug?: string[] }>
+ params: Promise<{ slug: string[] }>
}): Promise {
const params = await props.params
- const slug = params.slug ?? []
+ const slug = params.slug
const page = source.getPage(slug)
if (!page) notFound()
diff --git a/apps/docs/app/docs/layout.tsx b/apps/docs/app/docs/layout.tsx
index ca55c7d..08ccdad 100644
--- a/apps/docs/app/docs/layout.tsx
+++ b/apps/docs/app/docs/layout.tsx
@@ -44,9 +44,6 @@ export default function DocsLayout({ children }: { children: ReactNode }) {
-
diff --git a/apps/docs/app/docs/page.tsx b/apps/docs/app/docs/page.tsx
new file mode 100644
index 0000000..449b829
--- /dev/null
+++ b/apps/docs/app/docs/page.tsx
@@ -0,0 +1,124 @@
+import type { Metadata } from "next"
+import { readdirSync } from "node:fs"
+import { join } from "node:path"
+import Link from "next/link"
+import { docsNav, getActiveBadge } from "@/lib/docs"
+import { getRegistryItem } from "@/lib/registry"
+import { ThemeImage } from "@/components/docs/theme-image"
+
+export const metadata: Metadata = {
+ title: "Components — jal-co/ui",
+ description:
+ "Browse all jalco ui components. Polished, composable building blocks for React and Next.js.",
+}
+
+const PREVIEWS_DIR = join(process.cwd(), "public/previews")
+const previewFiles = (() => {
+ try {
+ return readdirSync(PREVIEWS_DIR)
+ } catch {
+ return []
+ }
+})()
+const availableImages = new Set(
+ previewFiles
+ .filter((f) => f.endsWith("-dark.png"))
+ .map((f) => f.replace("-dark.png", ""))
+)
+const availableVideos = new Set(
+ previewFiles
+ .filter((f) => f.endsWith("-dark.webm"))
+ .map((f) => f.replace("-dark.webm", ""))
+)
+
+function getComponentDescription(href: string): string | null {
+ const slug = href.split("/").pop()
+ if (!slug) return null
+ const item = getRegistryItem(slug)
+ return item?.description ?? null
+}
+
+function getSlug(href: string): string {
+ return href.split("/").pop() ?? ""
+}
+
+export default function DocsPage() {
+ const componentGroups = docsNav.filter(
+ (group) => group.title !== "Getting Started"
+ )
+
+ const totalCount = componentGroups.reduce(
+ (sum, group) => sum + group.items.filter((i) => !i.bundledIn).length,
+ 0
+ )
+
+ return (
+
+
+
Components
+
+ {totalCount} polished, composable components ready to install and
+ adapt.
+
+
+
+
+ {componentGroups.map((group) => (
+
+
+ {group.title}
+
+
+
+ {group.items
+ .filter((item) => !item.bundledIn)
+ .map((item) => {
+ const description = getComponentDescription(item.href)
+ const badge = getActiveBadge(item)
+ const slug = getSlug(item.href)
+ const hasImage = availableImages.has(slug)
+ const hasVideo = availableVideos.has(slug)
+
+ return (
+
+ {hasImage && (
+
+
+
+ )}
+
+
+
+
+ {item.title}
+
+ {badge && (
+
+ {badge}
+
+ )}
+
+ {description && (
+
+ {description}
+
+ )}
+
+
+ )
+ })}
+
+
+ ))}
+
+
+ )
+}
diff --git a/apps/docs/lib/docs.ts b/apps/docs/lib/docs.ts
index 643c961..09f446e 100644
--- a/apps/docs/lib/docs.ts
+++ b/apps/docs/lib/docs.ts
@@ -33,7 +33,7 @@ export const docsNav: NavGroup[] = [
title: "Getting Started",
items: [
{ title: "Components", href: "/docs" },
- { title: "Releases", href: "/docs/changelog" },
+ { title: "Releases", href: "/docs/releases" },
{ title: "Installation", href: "/docs/installation" },
{ title: "Color Themes", href: "/docs/themes" },
{ title: "llms.txt", href: "/llms.txt" },