Fix button roundtrip in editor, alignment persistence, and test email rendering

This commit is contained in:
Dwindi Ramadhana
2026-01-17 13:10:50 +07:00
parent 0e9ace902d
commit 6d2136d3b5
61 changed files with 8287 additions and 866 deletions

View File

@@ -1,4 +1,5 @@
import { cn } from '@/lib/utils';
import * as LucideIcons from 'lucide-react';
interface FeatureItem {
title?: string;
@@ -12,6 +13,7 @@ interface FeatureGridSectionProps {
colorScheme?: string;
heading?: string;
items?: FeatureItem[];
elementStyles?: Record<string, any>;
}
export function FeatureGridSection({
@@ -20,13 +22,44 @@ export function FeatureGridSection({
colorScheme = 'default',
heading,
items = [],
}: FeatureGridSectionProps) {
features = [],
elementStyles,
styles,
}: FeatureGridSectionProps & { features?: FeatureItem[], styles?: Record<string, any> }) {
// Use items or features (priority to items if both exist, but usually only one comes from props)
const listItems = items.length > 0 ? items : features;
const gridCols = {
'grid-2': 'md:grid-cols-2',
'grid-3': 'md:grid-cols-3',
'grid-4': 'md:grid-cols-2 lg:grid-cols-4',
}[layout] || 'md:grid-cols-3';
// Helper to get text styles (including font family)
const getTextStyles = (elementName: string) => {
const styles = 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,
borderColor: styles.borderColor,
borderWidth: styles.borderWidth,
borderRadius: styles.borderRadius,
}
};
};
const headingStyle = getTextStyles('heading');
const featureItemStyle = getTextStyles('feature_item');
return (
<section
id={id}
@@ -34,42 +67,65 @@ export function FeatureGridSection({
'wn-section wn-feature-grid',
`wn-feature-grid--${layout}`,
`wn-scheme--${colorScheme}`,
'py-16 md:py-24',
'py-12 md:py-24',
{
'bg-white': colorScheme === 'default',
// 'bg-white': colorScheme === 'default', // Removed for global styling
'bg-muted': colorScheme === 'muted',
'bg-primary text-primary-foreground': colorScheme === 'primary',
}
)}
>
<div className="container mx-auto px-4">
<div className={cn(
"mx-auto px-4",
styles?.contentWidth === 'full' ? 'w-full' : 'container'
)}>
{heading && (
<h2 className="text-3xl md:text-4xl font-bold text-center mb-12">
<h2
className={cn(
"wn-features__heading text-center mb-12",
!elementStyles?.heading?.fontSize && "text-3xl md:text-4xl",
!elementStyles?.heading?.fontWeight && "font-bold",
headingStyle.classNames
)}
style={headingStyle.style}
>
{heading}
</h2>
)}
<div className={cn('grid gap-8', gridCols)}>
{items.map((item, index) => (
{listItems.map((item, index) => (
<div
key={index}
className={cn(
'wn-feature-grid__item',
'p-6 rounded-xl',
{
!featureItemStyle.style?.backgroundColor && {
'bg-white shadow-lg': colorScheme !== 'primary',
'bg-white/10': colorScheme === 'primary',
}
},
featureItemStyle.classNames
)}
style={featureItemStyle.style}
>
{item.icon && (
<span className="wn-feature-grid__icon text-4xl mb-4 block">
{item.icon}
</span>
)}
{item.icon && (() => {
const IconComponent = (LucideIcons as any)[item.icon];
if (!IconComponent) return null;
return (
<div className="wn-feature-grid__icon mb-4 inline-block p-3 rounded-full bg-primary/10 text-primary">
<IconComponent className="w-8 h-8" />
</div>
);
})()}
{item.title && (
<h3 className="wn-feature-grid__item-title text-xl font-semibold mb-3">
<h3
className={cn(
"wn-feature-grid__item-title mb-3",
!featureItemStyle.classNames && "text-xl font-semibold"
)}
style={{ color: featureItemStyle.style?.color }}
>
{item.title}
</h3>
)}
@@ -77,11 +133,13 @@ export function FeatureGridSection({
{item.description && (
<p className={cn(
'wn-feature-grid__item-desc',
{
!featureItemStyle.style?.color && {
'text-gray-600': colorScheme !== 'primary',
'text-white/80': colorScheme === 'primary',
}
)}>
)}
style={{ color: featureItemStyle.style?.color }}
>
{item.description}
</p>
)}