diff --git a/vibn-frontend/app/api/design-systems/[id]/showcase/route.ts b/vibn-frontend/app/api/design-systems/[id]/showcase/route.ts new file mode 100644 index 0000000..b608ebb --- /dev/null +++ b/vibn-frontend/app/api/design-systems/[id]/showcase/route.ts @@ -0,0 +1,51 @@ +import { NextResponse } from "next/server"; +import fs from "fs"; +import path from "path"; +import { renderDesignSystemShowcase } from "@/lib/scaffold/open-design/design-system-showcase"; + +export async function GET( + request: Request, + { params }: { params: Promise<{ id: string }> } +) { + const { id } = await params; + + if (!id || id.includes("..") || id.includes("/")) { + return new NextResponse("Invalid design system ID", { status: 400 }); + } + + const systemPath = path.join( + process.cwd(), + "lib", + "scaffold", + "open-design", + "design-systems", + id + ); + + const mdPath = path.join(systemPath, "DESIGN.md"); + + try { + if (!fs.existsSync(systemPath)) { + return new NextResponse(`Design system not found for ${id}`, { status: 404 }); + } + + if (!fs.existsSync(mdPath)) { + return new NextResponse(`DESIGN.md not found for ${id}`, { status: 404 }); + } + + const rawMarkdown = await fs.promises.readFile(mdPath, "utf-8"); + const html = renderDesignSystemShowcase(id, rawMarkdown); + + return new NextResponse(html, { + status: 200, + headers: { + "Content-Type": "text/html; charset=utf-8", + "X-Frame-Options": "SAMEORIGIN", + }, + }); + } catch (err: any) { + return new NextResponse(`Error loading showcase: ${err.message}`, { + status: 500, + }); + } +} diff --git a/vibn-frontend/components/project/design-system-explorer.tsx b/vibn-frontend/components/project/design-system-explorer.tsx index ddfb159..b95a0fe 100644 --- a/vibn-frontend/components/project/design-system-explorer.tsx +++ b/vibn-frontend/components/project/design-system-explorer.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { useParams } from "next/navigation"; -import { Loader2, Check, Search, Eye, Sparkles, LayoutTemplate } from "lucide-react"; +import { Loader2, Check, Search, Eye, Sparkles, LayoutTemplate, Palette } from "lucide-react"; import { toast } from "sonner"; import { STARTER_KITS } from "@/lib/design-kits/registry"; import { DEFAULT_DESIGN_KIT_ID } from "@/lib/design-kits/types"; @@ -13,6 +13,7 @@ export function DesignSystemExplorer() { const [activeKitId, setActiveKitId] = useState(DEFAULT_DESIGN_KIT_ID); const [previewKitId, setPreviewKitId] = useState(DEFAULT_DESIGN_KIT_ID); + const [previewMode, setPreviewMode] = useState<"showcase" | "tokens">("showcase"); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [search, setSearch] = useState(""); @@ -113,7 +114,12 @@ export function DesignSystemExplorer() { return ( @@ -156,14 +162,34 @@ export function DesignSystemExplorer() {
{/* Top Action Bar */}
-
- - - Previewing: {previewKit.name} - {!previewKit.hasPreview && ( - Rules Only +
+
+ + + {previewKit.name} + +
+ +
+ + {previewKit.hasPreview && ( + )} - +
- {previewKit.id}.design.preview + {previewKit.id}.{previewMode}.preview