diff --git a/src/components/quickstart/TemplateCard.tsx b/src/components/quickstart/TemplateCard.tsx
index 788d1b4d..7b0c79fe 100644
--- a/src/components/quickstart/TemplateCard.tsx
+++ b/src/components/quickstart/TemplateCard.tsx
@@ -1,6 +1,5 @@
"use client";
-import { Node, Edge } from "@xyflow/react";
import { TemplateCategory } from "@/types/quickstart";
interface TemplateCardProps {
@@ -14,11 +13,9 @@ interface TemplateCardProps {
};
nodeCount: number;
previewImage?: string;
- workflow?: { nodes: Node[]; edges: Edge[] };
- isLoading: boolean;
+ isLoading?: boolean;
onClick: () => void;
- onPreviewClick?: () => void;
- disabled: boolean;
+ disabled?: boolean;
}
const CATEGORY_LABELS: Record = {
@@ -39,16 +36,14 @@ export function TemplateCard({
template,
nodeCount,
previewImage,
- workflow,
- isLoading,
+ isLoading = false,
onClick,
- onPreviewClick,
- disabled,
+ disabled = false,
}: TemplateCardProps) {
return (
{/* Metadata row */}
-
+
{/* Node count badge */}
{nodeCount} nodes
@@ -176,18 +136,6 @@ export function TemplateCard({
{CATEGORY_LABELS[template.category]}
-
- {/* Tags */}
-
- {template.tags.slice(0, 4).map((tag) => (
-
- {tag}
-
- ))}
-
);
}
diff --git a/src/components/quickstart/TemplateDetailModal.tsx b/src/components/quickstart/TemplateDetailModal.tsx
new file mode 100644
index 00000000..d16f0049
--- /dev/null
+++ b/src/components/quickstart/TemplateDetailModal.tsx
@@ -0,0 +1,224 @@
+"use client";
+
+import { useEffect, useCallback } from "react";
+import { Node, Edge } from "@xyflow/react";
+import { TemplateCategory } from "@/types/quickstart";
+import { WorkflowPreview } from "./WorkflowPreview";
+
+interface TemplateDetailModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+ onUseWorkflow: () => void;
+ isLoading: boolean;
+ template: {
+ id: string;
+ name: string;
+ description: string;
+ category: TemplateCategory;
+ tags: string[];
+ };
+ nodeCount: number;
+ workflow: { nodes: Node[]; edges: Edge[] };
+}
+
+const CATEGORY_LABELS: Record
= {
+ product: "Product",
+ style: "Style",
+ composition: "Composition",
+ community: "Community",
+};
+
+const CATEGORY_COLORS: Record = {
+ product: "bg-blue-500/20 text-blue-300 border-blue-500/30",
+ style: "bg-purple-500/20 text-purple-300 border-purple-500/30",
+ composition: "bg-green-500/20 text-green-300 border-green-500/30",
+ community: "bg-amber-500/20 text-amber-300 border-amber-500/30",
+};
+
+export function TemplateDetailModal({
+ isOpen,
+ onClose,
+ onUseWorkflow,
+ isLoading,
+ template,
+ nodeCount,
+ workflow,
+}: TemplateDetailModalProps) {
+ // Handle escape key to close
+ const handleKeyDown = useCallback(
+ (e: KeyboardEvent) => {
+ if (e.key === "Escape" && !isLoading) {
+ onClose();
+ }
+ },
+ [onClose, isLoading]
+ );
+
+ useEffect(() => {
+ if (isOpen) {
+ document.addEventListener("keydown", handleKeyDown);
+ return () => document.removeEventListener("keydown", handleKeyDown);
+ }
+ }, [isOpen, handleKeyDown]);
+
+ if (!isOpen) return null;
+
+ return (
+
+ {/* Backdrop */}
+
+
+ {/* Modal */}
+
e.stopPropagation()}
+ >
+ {/* Header */}
+
+
+
+
+ {template.name}
+
+
+ {CATEGORY_LABELS[template.category]}
+
+
+
+ {template.description}
+
+
+
+
+
+ {/* Workflow Preview */}
+
+
+ {/* Footer */}
+
+
+ {/* Metadata */}
+
+
+
+
{nodeCount} nodes
+
+
+ {/* Tags */}
+
+ {template.tags.map((tag) => (
+
+ {tag}
+
+ ))}
+
+
+
+ {/* Actions */}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/quickstart/TemplateExplorerView.tsx b/src/components/quickstart/TemplateExplorerView.tsx
index a56e3f1b..deed8740 100644
--- a/src/components/quickstart/TemplateExplorerView.tsx
+++ b/src/components/quickstart/TemplateExplorerView.tsx
@@ -5,7 +5,7 @@ import { WorkflowFile } from "@/store/workflowStore";
import { getAllPresets, PRESET_TEMPLATES, getTemplateContent } from "@/lib/quickstart/templates";
import { QuickstartBackButton } from "./QuickstartBackButton";
import { TemplateCard } from "./TemplateCard";
-import { WorkflowPreviewModal } from "./WorkflowPreviewModal";
+import { TemplateDetailModal } from "./TemplateDetailModal";
import { CommunityWorkflowMeta, TemplateCategory, TemplateMetadata } from "@/types/quickstart";
interface TemplateExplorerViewProps {
@@ -31,7 +31,7 @@ export function TemplateExplorerView({
const [isLoadingList, setIsLoadingList] = useState(true);
const [loadingWorkflowId, setLoadingWorkflowId] = useState(null);
const [error, setError] = useState(null);
- const [previewTemplateId, setPreviewTemplateId] = useState(null);
+ const [selectedTemplateId, setSelectedTemplateId] = useState(null);
// Filter state
const [searchQuery, setSearchQuery] = useState("");
@@ -420,10 +420,7 @@ export function TemplateExplorerView({
template={preset}
nodeCount={presetMetadata[preset.id]?.nodeCount ?? 0}
previewImage={previewImages[preset.id]}
- workflow={presetWorkflows[preset.id]}
- isLoading={loadingWorkflowId === preset.id}
- onClick={() => handlePresetSelect(preset.id)}
- onPreviewClick={() => setPreviewTemplateId(preset.id)}
+ onClick={() => setSelectedTemplateId(preset.id)}
disabled={isLoading}
/>
))}
@@ -597,13 +594,18 @@ export function TemplateExplorerView({
- {/* Workflow Preview Modal */}
- {previewTemplateId && presetWorkflows[previewTemplateId] && (
- setPreviewTemplateId(null)}
- templateName={presets.find((p) => p.id === previewTemplateId)?.name || "Template"}
- workflow={presetWorkflows[previewTemplateId]}
+ onClose={() => setSelectedTemplateId(null)}
+ onUseWorkflow={() => {
+ handlePresetSelect(selectedTemplateId);
+ }}
+ isLoading={loadingWorkflowId === selectedTemplateId}
+ template={presets.find((p) => p.id === selectedTemplateId)!}
+ nodeCount={presetMetadata[selectedTemplateId]?.nodeCount ?? 0}
+ workflow={presetWorkflows[selectedTemplateId]}
/>
)}