159 lines
6.4 KiB
TypeScript
159 lines
6.4 KiB
TypeScript
import React from 'react';
|
|
import { cn } from '@/lib/utils';
|
|
import { Section } from '../../store/usePageEditorStore';
|
|
|
|
|
|
|
|
interface ImageTextRendererProps {
|
|
section: Section;
|
|
className?: string;
|
|
}
|
|
|
|
const COLOR_SCHEMES: Record<string, { bg: string; text: string }> = {
|
|
default: { bg: '', text: 'text-gray-900' },
|
|
primary: { bg: 'wn-primary-bg', text: 'text-white' },
|
|
secondary: { bg: 'wn-secondary-bg', text: 'text-white' },
|
|
muted: { bg: 'bg-gray-50', text: 'text-gray-700' },
|
|
gradient: { bg: 'wn-gradient-bg', text: 'text-white' },
|
|
};
|
|
|
|
export function ImageTextRenderer({ section, className }: ImageTextRendererProps) {
|
|
const scheme = COLOR_SCHEMES[section.colorScheme || 'default'];
|
|
const layout = section.layoutVariant || 'image-left';
|
|
const isImageRight = layout === 'image-right';
|
|
|
|
const title = section.props?.title?.value || 'Section Title';
|
|
const text = section.props?.text?.value || 'Your descriptive text goes here. Edit this section to add your own content.';
|
|
const image = section.props?.image?.value;
|
|
|
|
const isDynamicTitle = section.props?.title?.type === 'dynamic';
|
|
const isDynamicText = section.props?.text?.type === 'dynamic';
|
|
const isDynamicImage = section.props?.image?.type === 'dynamic';
|
|
|
|
const cta_text = section.props?.cta_text?.value;
|
|
const cta_url = section.props?.cta_url?.value;
|
|
|
|
// Helper to get text styles (including font family)
|
|
const getTextStyles = (elementName: string) => {
|
|
const styles = section.elementStyles?.[elementName] || {};
|
|
return {
|
|
classNames: cn(
|
|
styles.fontSize,
|
|
styles.fontWeight,
|
|
{
|
|
'font-sans': styles.fontFamily === 'secondary',
|
|
'font-serif': styles.fontFamily === 'primary',
|
|
}
|
|
),
|
|
style: {
|
|
color: styles.color,
|
|
textAlign: styles.textAlign,
|
|
backgroundColor: styles.backgroundColor
|
|
}
|
|
};
|
|
};
|
|
|
|
const titleStyle = getTextStyles('title');
|
|
const textStyle = getTextStyles('text');
|
|
const imageStyle = section.elementStyles?.['image'] || {};
|
|
|
|
const buttonStyle = getTextStyles('button');
|
|
|
|
// Helper to get background style for dynamic schemes
|
|
const getBackgroundStyle = () => {
|
|
if (scheme.bg === 'wn-gradient-bg') {
|
|
return { backgroundImage: 'linear-gradient(135deg, var(--wn-gradient-start, #9333ea), var(--wn-gradient-end, #3b82f6))' };
|
|
}
|
|
if (scheme.bg === 'wn-primary-bg') {
|
|
return { backgroundColor: 'var(--wn-primary, #1a1a1a)' };
|
|
}
|
|
if (scheme.bg === 'wn-secondary-bg') {
|
|
return { backgroundColor: 'var(--wn-secondary, #6b7280)' };
|
|
}
|
|
return undefined;
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className={cn('py-12 px-4 md:py-20 md:px-8', !scheme.bg.startsWith('wn-') && scheme.bg, scheme.text, className)}
|
|
style={getBackgroundStyle()}
|
|
>
|
|
<div className={cn(
|
|
'max-w-6xl mx-auto flex items-center gap-12',
|
|
isImageRight ? 'flex-col md:flex-row-reverse' : 'flex-col md:flex-row',
|
|
'flex-wrap md:flex-nowrap'
|
|
)}>
|
|
{/* Image */}
|
|
<div className="w-full md:w-1/2" style={{ backgroundColor: imageStyle.backgroundColor }}>
|
|
{image ? (
|
|
<img
|
|
src={image}
|
|
alt={title}
|
|
className="w-full h-auto rounded-xl shadow-lg"
|
|
style={{
|
|
objectFit: imageStyle.objectFit,
|
|
width: imageStyle.width,
|
|
maxWidth: '100%',
|
|
height: imageStyle.height,
|
|
}}
|
|
/>
|
|
) : (
|
|
<div className="w-full h-64 md:h-80 bg-gray-200 rounded-xl flex items-center justify-center">
|
|
<span className="text-gray-400">
|
|
{isDynamicImage ? (
|
|
<span className="flex items-center gap-2">
|
|
<span className="text-orange-400">◆</span>
|
|
{section.props?.image?.source}
|
|
</span>
|
|
) : (
|
|
'Add Image'
|
|
)}
|
|
</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div className="w-full md:w-1/2 space-y-4">
|
|
<h2
|
|
className={cn(
|
|
"text-2xl md:text-3xl font-bold",
|
|
titleStyle.classNames
|
|
)}
|
|
style={titleStyle.style}
|
|
>
|
|
{isDynamicTitle && <span className="text-orange-400 mr-2">◆</span>}
|
|
{title}
|
|
</h2>
|
|
<p
|
|
className={cn(
|
|
"text-lg opacity-90 leading-relaxed",
|
|
textStyle.classNames
|
|
)}
|
|
style={textStyle.style}
|
|
>
|
|
{isDynamicText && <span className="text-orange-400 mr-2">◆</span>}
|
|
{text}
|
|
</p>
|
|
|
|
{cta_text && cta_url && (
|
|
<div className="pt-4">
|
|
<span
|
|
className={cn(
|
|
"inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2",
|
|
!buttonStyle.style?.backgroundColor && "bg-blue-600",
|
|
!buttonStyle.style?.color && "text-white",
|
|
buttonStyle.classNames
|
|
)}
|
|
style={buttonStyle.style}
|
|
>
|
|
{cta_text}
|
|
</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|