Browse Source

refactor(25-02): simplify to single thumbnail image

- Remove carousel animation, use single static preview image
- Simplify TemplateCard props from previewImages[] to previewImage
- Ready for future GIF replacement
handoff-20260429-1057
shrimbly 6 months ago
parent
commit
aab4c96677
  1. 52
      src/components/quickstart/TemplateCard.tsx
  2. 11
      src/components/quickstart/TemplateExplorerView.tsx

52
src/components/quickstart/TemplateCard.tsx

@ -1,6 +1,5 @@
"use client"; "use client";
import { useState, useEffect } from "react";
import { TemplateCategory } from "@/types/quickstart"; import { TemplateCategory } from "@/types/quickstart";
interface TemplateCardProps { interface TemplateCardProps {
@ -13,7 +12,7 @@ interface TemplateCardProps {
tags: string[]; tags: string[];
}; };
nodeCount: number; nodeCount: number;
previewImages?: string[]; previewImage?: string;
isLoading: boolean; isLoading: boolean;
onClick: () => void; onClick: () => void;
disabled: boolean; disabled: boolean;
@ -36,31 +35,11 @@ const CATEGORY_COLORS: Record<TemplateCategory, string> = {
export function TemplateCard({ export function TemplateCard({
template, template,
nodeCount, nodeCount,
previewImages = [], previewImage,
isLoading, isLoading,
onClick, onClick,
disabled, disabled,
}: TemplateCardProps) { }: TemplateCardProps) {
const [currentImageIndex, setCurrentImageIndex] = useState(0);
const [isTransitioning, setIsTransitioning] = useState(false);
// Cycle through preview images
useEffect(() => {
if (previewImages.length <= 1) return;
const interval = setInterval(() => {
setIsTransitioning(true);
setTimeout(() => {
setCurrentImageIndex((prev) => (prev + 1) % previewImages.length);
setIsTransitioning(false);
}, 300); // Fade out duration
}, 2500); // Time between transitions
return () => clearInterval(interval);
}, [previewImages.length]);
const hasImages = previewImages.length > 0;
return ( return (
<button <button
onClick={onClick} onClick={onClick}
@ -108,32 +87,13 @@ export function TemplateCard({
/> />
</svg> </svg>
</div> </div>
) : hasImages ? ( ) : previewImage ? (
<> /* eslint-disable-next-line @next/next/no-img-element */
{/* eslint-disable-next-line @next/next/no-img-element */}
<img <img
src={previewImages[currentImageIndex]} src={previewImage}
alt={`${template.name} preview`} alt={`${template.name} preview`}
className={` className="w-full h-full object-cover"
w-full h-full object-cover transition-opacity duration-300
${isTransitioning ? "opacity-0" : "opacity-100"}
`}
/> />
{/* Image indicator dots */}
{previewImages.length > 1 && (
<div className="absolute bottom-2 left-1/2 -translate-x-1/2 flex gap-1">
{previewImages.map((_, idx) => (
<div
key={idx}
className={`
w-1.5 h-1.5 rounded-full transition-colors
${idx === currentImageIndex ? "bg-white" : "bg-white/40"}
`}
/>
))}
</div>
)}
</>
) : ( ) : (
<div className="absolute inset-0 flex items-center justify-center"> <div className="absolute inset-0 flex items-center justify-center">
<svg <svg

11
src/components/quickstart/TemplateExplorerView.tsx

@ -69,15 +69,14 @@ export function TemplateExplorerView({
return metadata; return metadata;
}, []); }, []);
// Get preview images for each template (from the "full" content level) // Get preview image for each template (first image from "full" content level)
const previewImages = useMemo(() => { const previewImages = useMemo(() => {
const images: Record<string, string[]> = {}; const images: Record<string, string | undefined> = {};
PRESET_TEMPLATES.forEach((template) => { PRESET_TEMPLATES.forEach((template) => {
const content = getTemplateContent(template.id, "full"); const content = getTemplateContent(template.id, "full");
if (content?.images) { if (content?.images) {
images[template.id] = Object.values(content.images).map((img) => img.url); const imageUrls = Object.values(content.images).map((img) => img.url);
} else { images[template.id] = imageUrls[0];
images[template.id] = [];
} }
}); });
return images; return images;
@ -406,7 +405,7 @@ export function TemplateExplorerView({
key={preset.id} key={preset.id}
template={preset} template={preset}
nodeCount={presetMetadata[preset.id]?.nodeCount ?? 0} nodeCount={presetMetadata[preset.id]?.nodeCount ?? 0}
previewImages={previewImages[preset.id]} previewImage={previewImages[preset.id]}
isLoading={loadingWorkflowId === preset.id} isLoading={loadingWorkflowId === preset.id}
onClick={() => handlePresetSelect(preset.id)} onClick={() => handlePresetSelect(preset.id)}
disabled={isLoading} disabled={isLoading}

Loading…
Cancel
Save