import React, { CSSProperties } from 'react'; import { useNode, UserComponent } from '@craftjs/core'; import { cssPropsToString } from '../../utils/style-helpers'; import { CtaButton, CtasEditor, normalizeCtas, ctaInlineStyle, ctasToHtml } from './_cta-helpers'; import { AnchorIdField } from '../../ui/AnchorIdField'; import { escapeHtml, escapeAttr } from '../../utils/escape'; interface CallToActionProps { heading?: string; description?: string; ctas?: CtaButton[]; /** Legacy props kept for backward compat with saved projects. */ buttonText?: string; buttonHref?: string; secondaryButtonText?: string; secondaryButtonHref?: string; bgType?: 'color' | 'gradient' | 'image'; bgValue?: string; overlayColor?: string; overlayOpacity?: number; textColor?: string; buttonColor?: string; anchorId?: string; style?: CSSProperties; } const defaultGradient = 'linear-gradient(135deg, #2563eb 0%, #7c3aed 100%)'; export const CallToAction: UserComponent = ({ heading = 'Ready to Get Started?', description = 'Join thousands of satisfied users and start building your dream website today.', ctas, buttonText, buttonHref, secondaryButtonText, secondaryButtonHref, bgType = 'gradient', bgValue = defaultGradient, overlayColor = '#000000', overlayOpacity = 0, textColor = '#ffffff', buttonColor = '#ffffff', anchorId, style = {}, }) => { const { connectors: { connect, drag }, selected, } = useNode((node) => ({ selected: node.events.selected, })); const bgStyle: CSSProperties = {}; if (bgType === 'color') { bgStyle.backgroundColor = bgValue; } else if (bgType === 'gradient') { bgStyle.background = bgValue; } else if (bgType === 'image') { bgStyle.backgroundImage = `url(${bgValue})`; bgStyle.backgroundSize = 'cover'; bgStyle.backgroundPosition = 'center'; } const isButtonDark = buttonColor === '#ffffff' || buttonColor === '#f8fafc'; const buttonTextColor = isButtonDark ? '#18181b' : '#ffffff'; const effectiveCtas = normalizeCtas({ ctas, buttonText, buttonHref, secondaryButtonText, secondaryButtonHref }); const ctaDefaults = { primaryBg: buttonColor, primaryText: buttonTextColor, outlineText: textColor }; return (
{ if (ref) connect(drag(ref)); }} id={anchorId || undefined} style={{ position: 'relative', padding: '80px 20px', textAlign: 'center', outline: selected ? '2px solid #3b82f6' : 'none', ...bgStyle, ...style, }} > {/* Overlay */} {bgType === 'image' && overlayOpacity > 0 && (
)}

{heading}

{description}

{effectiveCtas.map((cta, i) => ( e.preventDefault()} style={ctaInlineStyle(cta, ctaDefaults)}> {cta.text} ))}
); }; /* ---------- Settings panel ---------- */ const CallToActionSettings: React.FC = () => { const { actions: { setProp }, props } = useNode((node) => ({ props: node.data.props as CallToActionProps, })); const gradientPresets = [ { label: 'Blue-Purple', value: 'linear-gradient(135deg, #2563eb 0%, #7c3aed 100%)' }, { label: 'Purple', value: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' }, { label: 'Teal', value: 'linear-gradient(135deg, #0d9488 0%, #0f766e 100%)' }, { label: 'Sunset', value: 'linear-gradient(135deg, #f97316 0%, #ec4899 100%)' }, { label: 'Dark', value: 'linear-gradient(135deg, #1e293b 0%, #0f172a 100%)' }, { label: 'Ocean', value: 'linear-gradient(135deg, #0ea5e9 0%, #6366f1 100%)' }, ]; const colorPresets = ['#2563eb', '#7c3aed', '#0d9488', '#18181b', '#0f172a', '#1e293b', '#dc2626', '#f97316']; const buttonColorPresets = ['#ffffff', '#18181b', '#3b82f6', '#10b981', '#ef4444', '#8b5cf6', '#f59e0b', '#ec4899']; const textColorPresets = ['#ffffff', '#f8fafc', '#e2e8f0', '#18181b', '#1e293b', '#fef3c7']; const inputStyle: CSSProperties = { width: '100%', padding: '4px 8px', background: '#27272a', color: '#e4e4e7', border: '1px solid #3f3f46', borderRadius: 4, fontSize: 12, }; const effectiveCtas = normalizeCtas(props); return (
setProp((p: CallToActionProps) => { p.heading = e.target.value; })} style={inputStyle} />