import React, { CSSProperties, useState } from 'react'; import { useNode, UserComponent } from '@craftjs/core'; import { cssPropsToString } from '../../utils/style-helpers'; interface Testimonial { quote: string; name: string; title: string; rating: number; } interface TestimonialsProps { testimonials?: Testimonial[]; layout?: 'grid' | 'single'; columns?: number; style?: CSSProperties; cardBg?: string; starColor?: string; } const defaultTestimonials: Testimonial[] = [ { quote: 'This product has completely transformed our workflow. Highly recommended for any team.', name: 'Sarah Johnson', title: 'Marketing Director', rating: 5 }, { quote: 'Outstanding support and an incredibly intuitive interface. We saw results from day one.', name: 'Michael Chen', title: 'CTO, TechStart', rating: 5 }, { quote: 'The best investment we have made this year. Simple, powerful, and reliable.', name: 'Emily Rodriguez', title: 'Founder, DesignLab', rating: 4 }, ]; function renderStars(count: number, color: string): React.ReactNode { return (
{[1, 2, 3, 4, 5].map((i) => ( ))}
); } function starsHtml(count: number, color: string): string { const stars = [1, 2, 3, 4, 5].map((i) => `` ).join(''); return `
${stars}
`; } export const Testimonials: UserComponent = ({ testimonials = defaultTestimonials, layout = 'grid', columns = 3, style = {}, cardBg = '#f8fafc', starColor = '#f59e0b', }) => { const { connectors: { connect, drag }, selected, } = useNode((node) => ({ selected: node.events.selected, })); const [currentIndex, setCurrentIndex] = useState(0); const cardStyle: CSSProperties = { backgroundColor: cardBg, borderRadius: '12px', padding: '32px 24px', textAlign: 'center', border: '1px solid #e2e8f0', }; const renderCard = (t: Testimonial, i: number) => (
{renderStars(t.rating, starColor)}

“{t.quote}”

{t.name}
{t.title}
); const items = testimonials.length > 0 ? testimonials : defaultTestimonials; return (
{ if (ref) connect(drag(ref)); }} style={{ padding: '80px 20px', backgroundColor: '#ffffff', outline: selected ? '2px solid #3b82f6' : 'none', ...style, }} >
{layout === 'grid' ? (
{items.map((t, i) => renderCard(t, i))}
) : (
{renderCard(items[currentIndex] || items[0], currentIndex)} {items.length > 1 && (
{items.map((_, i) => (
setCurrentIndex(i)} style={{ width: 8, height: 8, borderRadius: '50%', cursor: 'pointer', backgroundColor: i === currentIndex ? '#3b82f6' : '#d1d5db', }} /> ))}
)}
)}
); }; /* ---------- Settings panel ---------- */ const TestimonialsSettings: React.FC = () => { const { actions: { setProp }, props } = useNode((node) => ({ props: node.data.props as TestimonialsProps, })); const items = props.testimonials || defaultTestimonials; const labelStyle: CSSProperties = { fontSize: 11, color: '#a1a1aa', display: 'block', marginBottom: 6 }; const inputStyle: CSSProperties = { width: '100%', padding: '3px 6px', background: '#27272a', color: '#e4e4e7', border: '1px solid #3f3f46', borderRadius: 4, fontSize: 11, }; const updateTestimonial = (index: number, field: keyof Testimonial, value: string | number) => { setProp((p: TestimonialsProps) => { const updated = [...(p.testimonials || defaultTestimonials)]; updated[index] = { ...updated[index], [field]: value }; p.testimonials = updated; }); }; const addTestimonial = () => { setProp((p: TestimonialsProps) => { p.testimonials = [...(p.testimonials || defaultTestimonials), { quote: 'Great experience!', name: 'New Person', title: 'Role', rating: 5 }]; }); }; const removeTestimonial = (index: number) => { setProp((p: TestimonialsProps) => { const updated = [...(p.testimonials || defaultTestimonials)]; updated.splice(index, 1); p.testimonials = updated; }); }; const bgPresets = ['#ffffff', '#f8fafc', '#f1f5f9', '#18181b', '#0f172a']; const cardBgPresets = ['#f8fafc', '#ffffff', '#f1f5f9', '#e2e8f0', '#27272a', '#1e293b']; const starColorPresets = ['#f59e0b', '#eab308', '#ef4444', '#3b82f6', '#10b981', '#8b5cf6']; return (
{/* Layout */}
{/* Columns (only for grid) */} {props.layout === 'grid' && (
{[1, 2, 3, 4].map((n) => ( ))}
)} {/* Section background */}
{bgPresets.map((c) => (
{/* Card background */}
{cardBgPresets.map((c) => (
{/* Star color */}
{starColorPresets.map((c) => (
{/* Testimonials list */}
{items.map((t, i) => (
updateTestimonial(i, 'name', e.target.value)} placeholder="Name" style={{ ...inputStyle, flex: 1 }} />
updateTestimonial(i, 'title', e.target.value)} placeholder="Title/Role" style={inputStyle} />