feat(ui): add showcase toggle and runtime renderer to design explorer

This commit is contained in:
2026-05-15 14:09:27 -07:00
parent b4821b3eba
commit f3b957ace2
3 changed files with 968 additions and 14 deletions

View File

@@ -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<string>(DEFAULT_DESIGN_KIT_ID);
const [previewKitId, setPreviewKitId] = useState<string>(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 (
<button
key={kit.id}
onClick={() => setPreviewKitId(kit.id)}
onClick={() => {
setPreviewKitId(kit.id);
if (!kit.hasPreview && previewMode === "tokens") {
setPreviewMode("showcase"); // force showcase if no raw tokens gallery
}
}}
className={`w-full text-left p-3 rounded-lg flex items-start gap-3 transition-colors group relative ${
isSelected ? 'bg-indigo-50/80 ring-1 ring-indigo-500/30' : 'hover:bg-zinc-50'
}`}
@@ -137,8 +143,8 @@ export function DesignSystemExplorer() {
</div>
{/* Visual Indicator if it has an HTML preview */}
{kit.hasPreview && (
<div className="absolute right-3 top-3.5 text-zinc-300 group-hover:text-indigo-400 transition-colors" title="Visual Preview Available">
<LayoutTemplate className="w-3.5 h-3.5" />
<div className="absolute right-3 top-3.5 text-zinc-300 group-hover:text-indigo-400 transition-colors" title="Detailed Token Gallery Available">
<Palette className="w-3.5 h-3.5" />
</div>
)}
</button>
@@ -156,14 +162,34 @@ export function DesignSystemExplorer() {
<div className="flex-1 flex flex-col h-full bg-zinc-100 overflow-hidden relative">
{/* Top Action Bar */}
<div className="h-14 flex-shrink-0 bg-white border-b border-zinc-200 px-6 flex items-center justify-between shadow-sm z-10">
<div className="flex items-center gap-3 min-w-0">
<Eye className="w-4 h-4 text-zinc-400" />
<span className="text-sm font-medium text-zinc-900 truncate flex items-center gap-2">
Previewing: {previewKit.name}
{!previewKit.hasPreview && (
<span className="px-2 py-0.5 rounded-full bg-zinc-100 text-zinc-500 text-[10px] font-mono tracking-wide uppercase border border-zinc-200">Rules Only</span>
<div className="flex items-center gap-6 min-w-0">
<div className="flex items-center gap-2">
<Eye className="w-4 h-4 text-zinc-400" />
<span className="text-sm font-medium text-zinc-900 truncate">
{previewKit.name}
</span>
</div>
<div className="flex bg-zinc-100 p-0.5 rounded-lg border border-zinc-200">
<button
onClick={() => setPreviewMode("showcase")}
className={`px-3 py-1 text-xs font-medium rounded-md transition-colors ${
previewMode === "showcase" ? 'bg-white text-zinc-900 shadow-sm' : 'text-zinc-500 hover:text-zinc-700'
}`}
>
Showcase
</button>
{previewKit.hasPreview && (
<button
onClick={() => setPreviewMode("tokens")}
className={`px-3 py-1 text-xs font-medium rounded-md transition-colors ${
previewMode === "tokens" ? 'bg-white text-zinc-900 shadow-sm' : 'text-zinc-500 hover:text-zinc-700'
}`}
>
Raw Tokens
</button>
)}
</span>
</div>
</div>
<button
@@ -189,13 +215,13 @@ export function DesignSystemExplorer() {
<div className="w-2.5 h-2.5 rounded-full bg-green-400/80"></div>
</div>
<div className="mx-auto bg-white px-3 py-0.5 rounded-md border border-zinc-200 text-[10px] text-zinc-400 font-mono shadow-sm">
{previewKit.id}.design.preview
{previewKit.id}.{previewMode}.preview
</div>
</div>
<iframe
key={previewKit.id} // Forces iframe to remount
src={`/api/design-systems/${previewKit.id}/preview`}
key={`${previewKit.id}-${previewMode}`} // Forces iframe to remount on change
src={previewMode === "showcase" ? `/api/design-systems/${previewKit.id}/showcase` : `/api/design-systems/${previewKit.id}/preview`}
className="flex-1 w-full h-full bg-zinc-50"
sandbox="allow-scripts allow-same-origin"
/>