| 1 |
( function () { |
| 2 |
var el = wp.element.createElement; |
| 3 |
var __ = wp.i18n.__; |
| 4 |
var registerBlockType = wp.blocks.registerBlockType; |
| 5 |
var InspectorControls = wp.blockEditor.InspectorControls; |
| 6 |
var useBlockProps = wp.blockEditor.useBlockProps; |
| 7 |
var RichText = wp.blockEditor.RichText; |
| 8 |
var PanelColorSettings = wp.blockEditor.PanelColorSettings; |
| 9 |
var PanelBody = wp.components.PanelBody; |
| 10 |
var ToggleControl = wp.components.ToggleControl; |
| 11 |
var RangeControl = wp.components.RangeControl; |
| 12 |
var SelectControl = wp.components.SelectControl; |
| 13 |
var TextControl = wp.components.TextControl; |
| 14 |
var Button = wp.components.Button; |
| 15 |
|
| 16 |
var _tc, _tv; |
| 17 |
function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); } |
| 18 |
function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); } |
| 19 |
|
| 20 |
var BADGE_STYLES = { |
| 21 |
hot: { bg: '#fef2f2', color: '#b91c1c', icon: '🔥' }, |
| 22 |
sale: { bg: '#fef9c3', color: '#854d0e', icon: '💸' }, |
| 23 |
limited: { bg: '#fff7ed', color: '#c2410c', icon: '⏳' }, |
| 24 |
new: { bg: '#f0fdf4', color: '#15803d', icon: '✨' } |
| 25 |
}; |
| 26 |
|
| 27 |
registerBlockType('blockenberg/offer-card', { |
| 28 |
edit: function (props) { |
| 29 |
var attr = props.attributes; |
| 30 |
var setAttr = props.setAttributes; |
| 31 |
var blockProps = (function () { |
| 32 |
var bp = useBlockProps({ className: 'bkbg-ofr-editor bkbg-ofr-wrap' }); |
| 33 |
var _tvf = getTypoCssVars(); |
| 34 |
var s = {}; |
| 35 |
if (_tvf) { |
| 36 |
Object.assign(s, _tvf(attr.headingTypo, '--bkbg-ofr-hd-')); |
| 37 |
Object.assign(s, _tvf(attr.descTypo, '--bkbg-ofr-ds-')); |
| 38 |
Object.assign(s, _tvf(attr.ctaTypo, '--bkbg-ofr-ct-')); |
| 39 |
} |
| 40 |
bp.style = Object.assign(s, bp.style || {}); |
| 41 |
return bp; |
| 42 |
}()); |
| 43 |
|
| 44 |
var isBanner = attr.layout === 'banner'; |
| 45 |
var isMinimal = attr.layout === 'minimal'; |
| 46 |
|
| 47 |
function updateInclude(idx, val) { |
| 48 |
var next = attr.includes.map(function (it, i) { return i === idx ? { text: val } : it; }); |
| 49 |
setAttr({ includes: next }); |
| 50 |
} |
| 51 |
|
| 52 |
var bs = BADGE_STYLES[attr.badgeStyle] || BADGE_STYLES.hot; |
| 53 |
|
| 54 |
var card = el('div', { |
| 55 |
style: { |
| 56 |
background: attr.cardBg, |
| 57 |
border: '1px solid ' + attr.borderColor, |
| 58 |
borderRadius: attr.borderRadius + 'px', |
| 59 |
padding: '32px', |
| 60 |
maxWidth: attr.maxWidth + 'px', |
| 61 |
margin: '0 auto', |
| 62 |
boxShadow: isMinimal ? 'none' : '0 4px 32px rgba(0,0,0,0.08)', |
| 63 |
display: isBanner ? 'flex' : 'block', |
| 64 |
gap: isBanner ? '40px' : undefined, |
| 65 |
alignItems: isBanner ? 'center' : undefined |
| 66 |
} |
| 67 |
}, |
| 68 |
/* Left / top section */ |
| 69 |
el('div', { style: { flex: isBanner ? '1' : undefined } }, |
| 70 |
attr.showBadge && el('div', { style: { marginBottom: '16px' } }, |
| 71 |
el('span', { style: { background: attr.badgeBg, color: attr.badgeColor, fontSize: '12px', fontWeight: '700', padding: '5px 14px', borderRadius: '999px' } }, |
| 72 |
el(RichText, { tagName: 'span', value: attr.badge, onChange: function (v) { setAttr({ badge: v }); } }) |
| 73 |
) |
| 74 |
), |
| 75 |
el(RichText, { |
| 76 |
tagName: 'h3', value: attr.heading, |
| 77 |
className: 'bkbg-ofr-heading', |
| 78 |
style: { color: attr.headingColor, margin: '0 0 10px' }, |
| 79 |
onChange: function (v) { setAttr({ heading: v }); } |
| 80 |
}), |
| 81 |
el(RichText, { |
| 82 |
tagName: 'p', value: attr.description, |
| 83 |
className: 'bkbg-ofr-desc', |
| 84 |
style: { color: attr.descColor, margin: '0 0 20px' }, |
| 85 |
onChange: function (v) { setAttr({ description: v }); } |
| 86 |
}), |
| 87 |
attr.showPrice && el('div', { style: { display: 'flex', alignItems: 'baseline', gap: '10px', marginBottom: '20px' } }, |
| 88 |
el('span', { style: { fontSize: '40px', fontWeight: '800', color: attr.priceColor } }, attr.currency + attr.salePrice), |
| 89 |
attr.originalPrice && el('span', { style: { fontSize: '20px', color: attr.strikethroughColor, textDecoration: 'line-through' } }, attr.currency + attr.originalPrice) |
| 90 |
), |
| 91 |
attr.showCountdown && el('div', { className: 'bkbg-ofr-countdown-preview', style: { display: 'flex', gap: '8px', marginBottom: '24px', flexWrap: 'wrap' } }, |
| 92 |
['HH', 'MM', 'SS'].map(function (lbl, i) { |
| 93 |
return el('div', { key: i, style: { background: '#111827', color: '#fff', borderRadius: '8px', padding: '8px 14px', textAlign: 'center', minWidth: '60px' } }, |
| 94 |
el('div', { style: { fontSize: '22px', fontWeight: '700', lineHeight: 1 } }, '00'), |
| 95 |
el('div', { style: { fontSize: '10px', opacity: 0.6, marginTop: '2px', textTransform: 'uppercase' } }, lbl) |
| 96 |
); |
| 97 |
}), |
| 98 |
el('div', { style: { flex: 1, display: 'flex', alignItems: 'center' } }, |
| 99 |
el(TextControl, { label: __('Countdown end (ISO date)', 'blockenberg'), value: attr.countdownEnd, placeholder: '2025-12-31T23:59:00', onChange: function (v) { setAttr({ countdownEnd: v }); }, __nextHasNoMarginBottom: true }) |
| 100 |
) |
| 101 |
) |
| 102 |
), |
| 103 |
/* Right / bottom section */ |
| 104 |
el('div', { style: { flex: isBanner ? '0 0 300px' : undefined } }, |
| 105 |
attr.showIncludes && el('ul', { style: { listStyle: 'none', margin: '0 0 20px', padding: 0 } }, |
| 106 |
attr.includes.map(function (item, idx) { |
| 107 |
return el('li', { key: idx, style: { display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '10px', fontSize: '15px', color: attr.includeColor } }, |
| 108 |
el('span', { style: { color: attr.checkColor, fontSize: '16px', fontWeight: '700', flexShrink: 0 } }, '✓'), |
| 109 |
el(TextControl, { |
| 110 |
value: item.text, |
| 111 |
onChange: function (v) { updateInclude(idx, v); }, |
| 112 |
style: { margin: 0, flex: 1 }, |
| 113 |
__nextHasNoMarginBottom: true |
| 114 |
}), |
| 115 |
el(Button, { isSmall: true, isDestructive: true, onClick: function () { setAttr({ includes: attr.includes.filter(function (_, i) { return i !== idx; }) }); } }, '✕') |
| 116 |
); |
| 117 |
}), |
| 118 |
el(Button, { isSecondary: true, isSmall: true, onClick: function () { setAttr({ includes: attr.includes.concat([{ text: 'New benefit' }]) }); } }, '+ Add item') |
| 119 |
), |
| 120 |
el('a', { |
| 121 |
href: '#editor', |
| 122 |
className: 'bkbg-ofr-cta', |
| 123 |
style: { display: 'block', background: attr.ctaBg, color: attr.ctaColor, padding: '16px', borderRadius: '8px', textAlign: 'center', textDecoration: 'none' } |
| 124 |
}, attr.ctaLabel), |
| 125 |
attr.showDisclaimer && el(RichText, { |
| 126 |
tagName: 'p', value: attr.disclaimer, |
| 127 |
style: { fontSize: '12px', color: attr.disclaimerColor, textAlign: 'center', marginTop: '12px', marginBottom: 0 }, |
| 128 |
onChange: function (v) { setAttr({ disclaimer: v }); } |
| 129 |
}) |
| 130 |
) |
| 131 |
); |
| 132 |
|
| 133 |
var controls = el(InspectorControls, {}, |
| 134 |
el(PanelBody, { title: __('Badge & Pricing', 'blockenberg'), initialOpen: true }, |
| 135 |
el(ToggleControl, { label: __('Show Badge', 'blockenberg'), checked: attr.showBadge, onChange: function (v) { setAttr({ showBadge: v }); }, __nextHasNoMarginBottom: true }), |
| 136 |
attr.showBadge && el(SelectControl, { |
| 137 |
label: __('Badge Style', 'blockenberg'), value: attr.badgeStyle, |
| 138 |
options: [{ label: '🔥 Hot', value: 'hot' }, { label: '💸 Sale', value: 'sale' }, { label: '⏳ Limited', value: 'limited' }, { label: '✨ New', value: 'new' }], |
| 139 |
onChange: function (v) { setAttr({ badgeStyle: v }); }, __nextHasNoMarginBottom: true |
| 140 |
}), |
| 141 |
el(ToggleControl, { label: __('Show Price', 'blockenberg'), checked: attr.showPrice, onChange: function (v) { setAttr({ showPrice: v }); }, __nextHasNoMarginBottom: true }), |
| 142 |
attr.showPrice && el(TextControl, { label: __('Currency Symbol', 'blockenberg'), value: attr.currency, onChange: function (v) { setAttr({ currency: v }); }, __nextHasNoMarginBottom: true }), |
| 143 |
attr.showPrice && el(TextControl, { label: __('Sale Price', 'blockenberg'), value: attr.salePrice, onChange: function (v) { setAttr({ salePrice: v }); }, __nextHasNoMarginBottom: true }), |
| 144 |
attr.showPrice && el(TextControl, { label: __('Original Price (strikethrough)', 'blockenberg'), value: attr.originalPrice, onChange: function (v) { setAttr({ originalPrice: v }); }, __nextHasNoMarginBottom: true }), |
| 145 |
el(ToggleControl, { label: __('Show Countdown Timer', 'blockenberg'), checked: attr.showCountdown, onChange: function (v) { setAttr({ showCountdown: v }); }, __nextHasNoMarginBottom: true }), |
| 146 |
el(ToggleControl, { label: __('Show Includes List', 'blockenberg'), checked: attr.showIncludes, onChange: function (v) { setAttr({ showIncludes: v }); }, __nextHasNoMarginBottom: true }), |
| 147 |
el(TextControl, { label: __('CTA Label', 'blockenberg'), value: attr.ctaLabel, onChange: function (v) { setAttr({ ctaLabel: v }); }, __nextHasNoMarginBottom: true }), |
| 148 |
el(TextControl, { label: __('CTA URL', 'blockenberg'), value: attr.ctaUrl, onChange: function (v) { setAttr({ ctaUrl: v }); }, __nextHasNoMarginBottom: true }), |
| 149 |
el(ToggleControl, { label: __('Open CTA in new tab', 'blockenberg'), checked: attr.ctaOpenNewTab, onChange: function (v) { setAttr({ ctaOpenNewTab: v }); }, __nextHasNoMarginBottom: true }), |
| 150 |
el(ToggleControl, { label: __('Show Disclaimer', 'blockenberg'), checked: attr.showDisclaimer, onChange: function (v) { setAttr({ showDisclaimer: v }); }, __nextHasNoMarginBottom: true }) |
| 151 |
), |
| 152 |
el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: false }, |
| 153 |
el(SelectControl, { |
| 154 |
label: __('Card Layout', 'blockenberg'), value: attr.layout, |
| 155 |
options: [{ label: 'Card (stacked)', value: 'card' }, { label: 'Banner (side-by-side)', value: 'banner' }, { label: 'Minimal', value: 'minimal' }], |
| 156 |
onChange: function (v) { setAttr({ layout: v }); }, __nextHasNoMarginBottom: true |
| 157 |
}), |
| 158 |
el(RangeControl, { label: __('Border Radius (px)', 'blockenberg'), value: attr.borderRadius, min: 0, max: 32, onChange: function (v) { setAttr({ borderRadius: v }); }, __nextHasNoMarginBottom: true }), |
| 159 |
el(RangeControl, { label: __('Max Width (px)', 'blockenberg'), value: attr.maxWidth, min: 300, max: 1400, onChange: function (v) { setAttr({ maxWidth: v }); }, __nextHasNoMarginBottom: true }), |
| 160 |
el(RangeControl, { label: __('Padding Top (px)', 'blockenberg'), value: attr.paddingTop, min: 0, max: 160, onChange: function (v) { setAttr({ paddingTop: v }); }, __nextHasNoMarginBottom: true }), |
| 161 |
el(RangeControl, { label: __('Padding Bottom (px)', 'blockenberg'), value: attr.paddingBottom, min: 0, max: 160, onChange: function (v) { setAttr({ paddingBottom: v }); }, __nextHasNoMarginBottom: true }) |
| 162 |
), |
| 163 |
el(PanelColorSettings, { |
| 164 |
title: __('Colors', 'blockenberg'), initialOpen: false, |
| 165 |
colorSettings: [ |
| 166 |
{ label: __('Section BG', 'blockenberg'), value: attr.bgColor, onChange: function (v) { setAttr({ bgColor: v || '#ffffff' }); } }, |
| 167 |
{ label: __('Card BG', 'blockenberg'), value: attr.cardBg, onChange: function (v) { setAttr({ cardBg: v || '#ffffff' }); } }, |
| 168 |
{ label: __('Border', 'blockenberg'), value: attr.borderColor, onChange: function (v) { setAttr({ borderColor: v || '#e5e7eb' }); } }, |
| 169 |
{ label: __('Accent', 'blockenberg'), value: attr.accentColor, onChange: function (v) { setAttr({ accentColor: v || '#7c3aed' }); } }, |
| 170 |
{ label: __('Badge BG', 'blockenberg'), value: attr.badgeBg, onChange: function (v) { setAttr({ badgeBg: v || '#fef2f2' }); } }, |
| 171 |
{ label: __('Badge Text', 'blockenberg'), value: attr.badgeColor, onChange: function (v) { setAttr({ badgeColor: v || '#b91c1c' }); } }, |
| 172 |
{ label: __('Heading', 'blockenberg'), value: attr.headingColor, onChange: function (v) { setAttr({ headingColor: v || '#111827' }); } }, |
| 173 |
{ label: __('Description', 'blockenberg'), value: attr.descColor, onChange: function (v) { setAttr({ descColor: v || '#6b7280' }); } }, |
| 174 |
{ label: __('Sale Price', 'blockenberg'), value: attr.priceColor, onChange: function (v) { setAttr({ priceColor: v || '#111827' }); } }, |
| 175 |
{ label: __('Strikethrough', 'blockenberg'), value: attr.strikethroughColor, onChange: function (v) { setAttr({ strikethroughColor: v || '#9ca3af' }); } }, |
| 176 |
{ label: __('CTA BG', 'blockenberg'), value: attr.ctaBg, onChange: function (v) { setAttr({ ctaBg: v || '#7c3aed' }); } }, |
| 177 |
{ label: __('CTA Text', 'blockenberg'), value: attr.ctaColor, onChange: function (v) { setAttr({ ctaColor: v || '#ffffff' }); } }, |
| 178 |
{ label: __('Checkmark', 'blockenberg'), value: attr.checkColor, onChange: function (v) { setAttr({ checkColor: v || '#16a34a' }); } } |
| 179 |
] |
| 180 |
}), |
| 181 |
el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false }, |
| 182 |
el(getTypoControl(), { label: __('Heading'), value: attr.headingTypo, onChange: function (v) { setAttr({ headingTypo: v }); } }), |
| 183 |
el(getTypoControl(), { label: __('Description'), value: attr.descTypo, onChange: function (v) { setAttr({ descTypo: v }); } }), |
| 184 |
el(getTypoControl(), { label: __('CTA Button'), value: attr.ctaTypo, onChange: function (v) { setAttr({ ctaTypo: v }); } }) |
| 185 |
) |
| 186 |
); |
| 187 |
|
| 188 |
return el('div', blockProps, controls, |
| 189 |
el('div', { style: { background: attr.bgColor, paddingTop: attr.paddingTop + 'px', paddingBottom: attr.paddingBottom + 'px' } }, card) |
| 190 |
); |
| 191 |
}, |
| 192 |
|
| 193 |
save: function (props) { |
| 194 |
return el('div', wp.blockEditor.useBlockProps.save(), |
| 195 |
el('div', { className: 'bkbg-ofr-app', 'data-opts': JSON.stringify(props.attributes) }) |
| 196 |
); |
| 197 |
} |
| 198 |
}); |
| 199 |
}() ); |
| 200 |
|