PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.12
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.12
2.0.14 2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / price-calculator / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.12, at blocks/price-calculator/index.js

550 lines 44.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = wp.element.createElement;
3 var Fragment = wp.element.Fragment;
4 var useState = wp.element.useState;
5 var __ = wp.i18n.__;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var RichText = wp.blockEditor.RichText;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var PanelBody = wp.components.PanelBody;
11 var Button = wp.components.Button;
12 var ToggleControl = wp.components.ToggleControl;
13 var RangeControl = wp.components.RangeControl;
14 var SelectControl = wp.components.SelectControl;
15 var TextControl = wp.components.TextControl;
16 var ColorPicker = wp.components.ColorPicker;
17 var Popover = wp.components.Popover;
18
19 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
20 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
21 var IP = function () { return window.bkbgIconPicker; };
22
23 var CURRENCY_POS_OPTIONS = [
24 { label: __('Before ($9)', 'blockenberg'), value: 'before' },
25 { label: __('After (9€)', 'blockenberg'), value: 'after' },
26 ];
27
28 function makeId() { return 'pc' + Math.random().toString(36).substr(2, 5); }
29
30 function buildWrapStyle(a) {
31 return {
32 '--bkbg-pc-accent': a.accentColor,
33 '--bkbg-pc-slider-track': a.sliderTrack,
34 '--bkbg-pc-slider-fill': a.sliderFill,
35 '--bkbg-pc-slider-thumb': a.sliderThumb,
36 '--bkbg-pc-card-bg': a.cardBg,
37 '--bkbg-pc-card-border': a.cardBorder,
38 '--bkbg-pc-price-bg': a.priceBg,
39 '--bkbg-pc-price-border': a.priceBorder,
40 '--bkbg-pc-btn-bg': a.btnBg,
41 '--bkbg-pc-btn-color': a.btnColor,
42 '--bkbg-pc-title-color': a.titleColor,
43 '--bkbg-pc-sub-color': a.subtitleColor,
44 '--bkbg-pc-label-color': a.labelColor,
45 '--bkbg-pc-price-color': a.priceColor,
46 '--bkbg-pc-price-accent': a.priceAccent,
47 '--bkbg-pc-card-r': a.cardRadius + 'px',
48 '--bkbg-pc-card-pad': a.cardPadding + 'px',
49 '--bkbg-pc-btn-r': a.btnRadius + 'px',
50 paddingTop: a.paddingTop + 'px',
51 paddingBottom: a.paddingBottom + 'px',
52 backgroundColor: a.bgColor || undefined,
53 };
54 }
55
56 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
57 var isOpen = openKey === key;
58 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
59 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
60 el('div', { style: { position: 'relative', flexShrink: 0 } },
61 el('button', { type: 'button', onClick: function () { setOpenKey(isOpen ? null : key); }, style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#ccc' } }),
62 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
63 el('div', { style: { padding: '8px' } },
64 el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange })
65 )
66 )
67 )
68 );
69 }
70
71 /* ── Compute price from current state ───────────────────────────── */
72 function calcPrice(a, sliderValues, addonChecked, isAnnual) {
73 var base = a.basePrice || 0;
74 var total = base;
75 a.sliders.forEach(function (sl) {
76 var val = sliderValues[sl.id] !== undefined ? sliderValues[sl.id] : sl.value;
77 total += val * sl.pricePerUnit;
78 });
79 a.addons.forEach(function (ad) {
80 if (addonChecked[ad.id]) total += ad.price;
81 });
82 if (isAnnual && a.annualDiscount > 0) {
83 total = total * (1 - a.annualDiscount / 100);
84 }
85 return total;
86 }
87
88 function formatPrice(a, val) {
89 var num = val.toFixed(2).replace(/\.00$/, '');
90 return a.currencyPos === 'before'
91 ? a.currency + num
92 : num + a.currency;
93 }
94
95 /* ── Slider row ─────────────────────────────────────────────────── */
96 function SliderRow(props) {
97 var sl = props.sl;
98 var val = props.val;
99 var onChangeVal = props.onChangeVal;
100 var a = props.a;
101 var pct = ((val - sl.min) / (sl.max - sl.min)) * 100;
102
103 return el('div', { className: 'bkbg-pc-slider-row', style: { marginBottom: '22px' } },
104 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' } },
105 el('div', { style: { display: 'flex', alignItems: 'center', gap: '6px' } },
106 sl.icon && el('span', { className: 'bkbg-pc-slider-icon', style: { fontSize: '16px' } }, (sl.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(sl.iconType, sl.icon, sl.iconDashicon, sl.iconImageUrl, sl.iconDashiconColor) : sl.icon),
107 el('span', { className: 'bkbg-pc-slider-label' }, sl.label)
108 ),
109 el('span', { className: 'bkbg-pc-slider-val' }, val + ' ' + sl.unit)
110 ),
111 el('div', { className: 'bkbg-pc-slider-track-wrap', style: { position: 'relative', height: '6px', borderRadius: '99px', background: a.sliderTrack } },
112 el('div', { className: 'bkbg-pc-slider-fill', style: { position: 'absolute', left: 0, top: 0, height: '100%', width: pct + '%', background: a.sliderFill, borderRadius: '99px', pointerEvents: 'none' } }),
113 el('input', { type: 'range', min: sl.min, max: sl.max, step: sl.step, value: val, 'data-slider-id': sl.id,
114 onChange: function (e) { onChangeVal(parseFloat(e.target.value)); },
115 className: 'bkbg-pc-range',
116 style: { position: 'absolute', inset: 0, width: '100%', opacity: 0, cursor: 'pointer', height: '6px', margin: 0 }
117 })
118 )
119 );
120 }
121
122 /* ── Addon row ──────────────────────────────────────────────────── */
123 function AddonRow(props) {
124 var ad = props.ad;
125 var checked = props.checked;
126 var onToggle = props.onToggle;
127 var a = props.a;
128
129 return el('label', { className: 'bkbg-pc-addon', 'data-addon-id': ad.id, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '10px', padding: '12px 16px', borderRadius: '10px', border: '1.5px solid ' + (checked ? a.accentColor : a.cardBorder), cursor: 'pointer', marginBottom: '8px', background: checked ? 'rgba(108,63,181,0.05)' : 'transparent', transition: 'all 0.15s' } },
130 el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
131 el('input', { type: 'checkbox', checked: checked, onChange: onToggle, 'data-addon-id': ad.id, style: { accentColor: a.accentColor, width: '16px', height: '16px' } }),
132 ad.icon && el('span', { className: 'bkbg-pc-addon-icon', style: { fontSize: '16px' } }, (ad.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(ad.iconType, ad.icon, ad.iconDashicon, ad.iconImageUrl, ad.iconDashiconColor) : ad.icon),
133 el('span', { className: 'bkbg-pc-addon-label' }, ad.label)
134 ),
135 el('span', { className: 'bkbg-pc-addon-price' },
136 '+' + formatPrice(a, ad.price) + '/mo'
137 )
138 );
139 }
140
141 registerBlockType('blockenberg/price-calculator', {
142 title: __('Price Calculator', 'blockenberg'),
143 icon: 'calculator',
144 category: 'bkbg-calculators',
145
146 edit: function (props) {
147 var a = props.attributes;
148 var setAttributes = props.setAttributes;
149
150 var openColorKeyState = useState(null);
151 var openColorKey = openColorKeyState[0];
152 var setOpenColorKey = openColorKeyState[1];
153
154 /* Interactive preview state */
155 var isAnnualState = useState(false);
156 var isAnnual = isAnnualState[0];
157 var setIsAnnual = isAnnualState[1];
158
159 var initSliders = {};
160 a.sliders.forEach(function (sl) { initSliders[sl.id] = sl.value; });
161 var sliderValsState = useState(initSliders);
162 var sliderVals = sliderValsState[0];
163 var setSliderVals = sliderValsState[1];
164
165 var initAddons = {};
166 a.addons.forEach(function (ad) { initAddons[ad.id] = ad.checked; });
167 var addonCheckedState = useState(initAddons);
168 var addonChecked = addonCheckedState[0];
169 var setAddonChecked = addonCheckedState[1];
170
171 var blockProps = useBlockProps((function () {
172 var _tvFn = getTypoCssVars();
173 var s = buildWrapStyle(a);
174 if (_tvFn) {
175 Object.assign(s, _tvFn(a.titleTypo, '--bkbg-pc-tt-'));
176 Object.assign(s, _tvFn(a.subtitleTypo, '--bkbg-pc-st-'));
177 Object.assign(s, _tvFn(a.priceTypo, '--bkbg-pc-pr-'));
178 Object.assign(s, _tvFn(a.labelTypo, '--bkbg-pc-lb-'));
179 }
180 return { style: s };
181 })());
182
183 var price = calcPrice(a, sliderVals, addonChecked, isAnnual);
184 var priceStr = formatPrice(a, price);
185 var priceNote = isAnnual ? a.priceNoteAnnual : a.priceNote;
186
187 function cc(key, label, attrKey) {
188 return renderColorControl(key, label, a[attrKey], function (val) {
189 var upd = {}; upd[attrKey] = val; setAttributes(upd);
190 }, openColorKey, setOpenColorKey);
191 }
192
193 function updateSlider(id, key, val) {
194 setAttributes({ sliders: a.sliders.map(function (sl) {
195 if (sl.id !== id) return sl;
196 var u = Object.assign({}, sl); u[key] = val; return u;
197 }) });
198 /* Also reset preview value if key was 'value' */
199 if (key === 'value') {
200 var nv = {}; nv[id] = val;
201 setSliderVals(Object.assign({}, sliderVals, nv));
202 }
203 }
204
205 function updateAddon(id, key, val) {
206 setAttributes({ addons: a.addons.map(function (ad) {
207 if (ad.id !== id) return ad;
208 var u = Object.assign({}, ad); u[key] = val; return u;
209 }) });
210 }
211
212 return el(Fragment, null,
213 el(InspectorControls, null,
214 el(PanelBody, { title: __('Sliders', 'blockenberg'), initialOpen: true },
215 a.sliders.map(function (sl) {
216 return el('div', { key: sl.id, style: { border: '1px solid #e0e0e0', borderRadius: '8px', padding: '10px', marginBottom: '10px' } },
217 el(TextControl, { label: __('Label', 'blockenberg'), value: sl.label, onChange: function (v) { updateSlider(sl.id, 'label', v); } }),
218 el(TextControl, { label: __('Unit', 'blockenberg'), value: sl.unit, onChange: function (v) { updateSlider(sl.id, 'unit', v); } }),
219 el(IP().IconPickerControl, {
220 iconType: sl.iconType || 'custom-char',
221 customChar: sl.icon,
222 dashicon: sl.iconDashicon || '',
223 imageUrl: sl.iconImageUrl || '',
224 onChangeType: function (v) { updateSlider(sl.id, 'iconType', v); },
225 onChangeChar: function (v) { updateSlider(sl.id, 'icon', v); },
226 onChangeDashicon: function (v) { updateSlider(sl.id, 'iconDashicon', v); },
227 onChangeImageUrl: function (v) { updateSlider(sl.id, 'iconImageUrl', v); }
228 }),
229 el('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px' } },
230 el(TextControl, { label: __('Min', 'blockenberg'), type: 'number', value: String(sl.min), onChange: function (v) { updateSlider(sl.id, 'min', parseFloat(v)||0); } }),
231 el(TextControl, { label: __('Max', 'blockenberg'), type: 'number', value: String(sl.max), onChange: function (v) { updateSlider(sl.id, 'max', parseFloat(v)||100); } }),
232 el(TextControl, { label: __('Step', 'blockenberg'), type: 'number', value: String(sl.step), onChange: function (v) { updateSlider(sl.id, 'step', parseFloat(v)||1); } }),
233 el(TextControl, { label: __('Default', 'blockenberg'), type: 'number', value: String(sl.value), onChange: function (v) { updateSlider(sl.id, 'value', parseFloat(v)||0); } })
234 ),
235 el(TextControl, { label: __('Price per unit ($/unit)', 'blockenberg'), type: 'number', value: String(sl.pricePerUnit), onChange: function (v) { updateSlider(sl.id, 'pricePerUnit', parseFloat(v)||0); } }),
236 el(Button, { isDestructive: true, variant: 'tertiary', size: 'compact', onClick: function () { setAttributes({ sliders: a.sliders.filter(function (s) { return s.id !== sl.id; }) }); } }, __('Remove', 'blockenberg'))
237 );
238 }),
239 el(Button, { variant: 'secondary', onClick: function () { setAttributes({ sliders: a.sliders.concat([{ id: makeId(), label: __('New Slider', 'blockenberg'), unit: 'units', min: 1, max: 100, step: 1, value: 10, pricePerUnit: 1, icon: '📦', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '' }]) }); }, style: { width: '100%', justifyContent: 'center' } }, '+ ' + __('Add Slider', 'blockenberg'))
240 ),
241 el(PanelBody, { title: __('Add-ons', 'blockenberg'), initialOpen: false },
242 a.addons.map(function (ad) {
243 return el('div', { key: ad.id, style: { border: '1px solid #e0e0e0', borderRadius: '8px', padding: '10px', marginBottom: '10px' } },
244 el(TextControl, { label: __('Label', 'blockenberg'), value: ad.label, onChange: function (v) { updateAddon(ad.id, 'label', v); } }),
245 el(IP().IconPickerControl, {
246 iconType: ad.iconType || 'custom-char',
247 customChar: ad.icon,
248 dashicon: ad.iconDashicon || '',
249 imageUrl: ad.iconImageUrl || '',
250 onChangeType: function (v) { updateAddon(ad.id, 'iconType', v); },
251 onChangeChar: function (v) { updateAddon(ad.id, 'icon', v); },
252 onChangeDashicon: function (v) { updateAddon(ad.id, 'iconDashicon', v); },
253 onChangeImageUrl: function (v) { updateAddon(ad.id, 'iconImageUrl', v); }
254 }),
255 el(TextControl, { label: __('Monthly price ($)', 'blockenberg'), type: 'number', value: String(ad.price), onChange: function (v) { updateAddon(ad.id, 'price', parseFloat(v)||0); } }),
256 el(ToggleControl, { label: __('Checked by default', 'blockenberg'), checked: ad.checked, onChange: function (v) { updateAddon(ad.id, 'checked', v); }, __nextHasNoMarginBottom: true }),
257 el(Button, { isDestructive: true, variant: 'tertiary', size: 'compact', onClick: function () { setAttributes({ addons: a.addons.filter(function (x) { return x.id !== ad.id; }) }); } }, __('Remove', 'blockenberg'))
258 );
259 }),
260 el(Button, { variant: 'secondary', onClick: function () { setAttributes({ addons: a.addons.concat([{ id: makeId(), label: __('New Add-on', 'blockenberg'), price: 9, checked: false, icon: '✨', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '' }]) }); }, style: { width: '100%', justifyContent: 'center' } }, '+ ' + __('Add Add-on', 'blockenberg'))
261 ),
262 el(PanelBody, { title: __('Pricing Settings', 'blockenberg'), initialOpen: false },
263 el(TextControl, { label: __('Base price ($)', 'blockenberg'), type: 'number', value: String(a.basePrice), onChange: function (v) { setAttributes({ basePrice: parseFloat(v)||0 }); } }),
264 el(TextControl, { label: __('Currency symbol', 'blockenberg'), value: a.currency, onChange: function (v) { setAttributes({ currency: v }); } }),
265 el(SelectControl, { label: __('Symbol position', 'blockenberg'), value: a.currencyPos, options: CURRENCY_POS_OPTIONS, onChange: function (v) { setAttributes({ currencyPos: v }); } }),
266 el(ToggleControl, { label: __('Show billing toggle (monthly/annual)', 'blockenberg'), checked: a.billingToggle, onChange: function (v) { setAttributes({ billingToggle: v }); }, __nextHasNoMarginBottom: true }),
267 a.billingToggle && el(RangeControl, { label: __('Annual discount %', 'blockenberg'), value: a.annualDiscount, min: 5, max: 50, onChange: function (v) { setAttributes({ annualDiscount: v }); } }),
268 el(TextControl, { label: __('Price note (monthly)', 'blockenberg'), value: a.priceNote, onChange: function (v) { setAttributes({ priceNote: v }); } }),
269 a.billingToggle && el(TextControl, { label: __('Price note (annual)', 'blockenberg'), value: a.priceNoteAnnual, onChange: function (v) { setAttributes({ priceNoteAnnual: v }); } })
270 ),
271 el(PanelBody, { title: __('CTA Button', 'blockenberg'), initialOpen: false },
272 el(TextControl, { label: __('Button label', 'blockenberg'), value: a.ctaLabel, onChange: function (v) { setAttributes({ ctaLabel: v }); } }),
273 el(TextControl, { label: __('Button URL', 'blockenberg'), value: a.ctaUrl, onChange: function (v) { setAttributes({ ctaUrl: v }); } }),
274 el(ToggleControl, { label: __('Open in new tab', 'blockenberg'), checked: a.ctaNewTab, onChange: function (v) { setAttributes({ ctaNewTab: v }); }, __nextHasNoMarginBottom: true })
275 ),
276 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: false },
277 el(RangeControl, { label: __('Max width (px)', 'blockenberg'), value: a.maxWidth, min: 400, max: 900, onChange: function (v) { setAttributes({ maxWidth: v }); } }),
278 el(RangeControl, { label: __('Card radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 32, onChange: function (v) { setAttributes({ cardRadius: v }); } }),
279 el(RangeControl, { label: __('Card padding (px)', 'blockenberg'), value: a.cardPadding, min: 16, max: 64, onChange: function (v) { setAttributes({ cardPadding: v }); } }),
280 el(RangeControl, { label: __('Button radius (px)','blockenberg'), value: a.btnRadius, min: 0, max: 99, onChange: function (v) { setAttributes({ btnRadius: v }); } })
281 ),
282 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
283 (function () {
284 var TC = getTypoControl();
285 if (!TC) return el('p', null, 'Loading…');
286 return el(Fragment, null,
287 el(TC, { label: __('Title', 'blockenberg'), value: a.titleTypo, onChange: function (v) { setAttributes({ titleTypo: v }); } }),
288 el(TC, { label: __('Subtitle', 'blockenberg'), value: a.subtitleTypo, onChange: function (v) { setAttributes({ subtitleTypo: v }); } }),
289 el(TC, { label: __('Price', 'blockenberg'), value: a.priceTypo, onChange: function (v) { setAttributes({ priceTypo: v }); } }),
290 el(TC, { label: __('Labels', 'blockenberg'), value: a.labelTypo, onChange: function (v) { setAttributes({ labelTypo: v }); } })
291 );
292 })()
293 ),
294 el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false },
295 cc('accentColor', __('Accent', 'blockenberg'), 'accentColor'),
296 cc('titleColor', __('Title', 'blockenberg'), 'titleColor'),
297 cc('subtitleColor', __('Subtitle', 'blockenberg'), 'subtitleColor'),
298 cc('labelColor', __('Labels', 'blockenberg'), 'labelColor'),
299 cc('priceColor', __('Price text', 'blockenberg'), 'priceColor'),
300 cc('priceAccent', __('Price accent', 'blockenberg'), 'priceAccent'),
301 cc('sliderTrack', __('Slider track', 'blockenberg'), 'sliderTrack'),
302 cc('sliderFill', __('Slider fill', 'blockenberg'), 'sliderFill'),
303 cc('cardBg', __('Card background', 'blockenberg'), 'cardBg'),
304 cc('cardBorder', __('Card border', 'blockenberg'), 'cardBorder'),
305 cc('priceBg', __('Price box bg', 'blockenberg'), 'priceBg'),
306 cc('priceBorder', __('Price box border', 'blockenberg'), 'priceBorder'),
307 cc('btnBg', __('Button background','blockenberg'), 'btnBg'),
308 cc('btnColor', __('Button text', 'blockenberg'), 'btnColor'),
309 cc('bgColor', __('Section bg', 'blockenberg'), 'bgColor')
310 ),
311 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
312 el(RangeControl, { label: __('Padding top', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
313 el(RangeControl, { label: __('Padding bottom', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
314 )
315 ),
316
317 el('div', blockProps,
318 el('div', { className: 'bkbg-pc-outer', style: { maxWidth: a.maxWidth + 'px', margin: '0 auto' } },
319 el('div', { className: 'bkbg-pc-card', style: { background: a.cardBg, border: '1px solid ' + a.cardBorder, borderRadius: a.cardRadius + 'px', padding: a.cardPadding + 'px', boxSizing: 'border-box' } },
320 /* Header */
321 el('div', { className: 'bkbg-pc-header', style: { marginBottom: '28px', textAlign: 'center' } },
322 el(RichText, { tagName: 'h2', className: 'bkbg-pc-title', value: a.title, onChange: function (v) { setAttributes({ title: v }); }, placeholder: __('Calculate Your Price', 'blockenberg'), style: { color: a.titleColor, margin: '0 0 8px' } }),
323 el(RichText, { tagName: 'p', className: 'bkbg-pc-subtitle', value: a.subtitle, onChange: function (v) { setAttributes({ subtitle: v }); }, placeholder: __('Subtitle…', 'blockenberg'), style: { color: a.subtitleColor, margin: 0 } })
324 ),
325 /* Billing toggle */
326 a.billingToggle && el('div', { className: 'bkbg-pc-billing-row', style: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '12px', marginBottom: '28px' } },
327 el('span', { className: 'bkbg-pc-billing-label', style: { color: isAnnual ? a.labelColor : a.accentColor } }, __('Monthly', 'blockenberg')),
328 el('button', { type: 'button', className: 'bkbg-pc-toggle-btn', onClick: function () { setIsAnnual(!isAnnual); },
329 style: { width: '42px', height: '24px', borderRadius: '99px', border: 'none', background: isAnnual ? a.accentColor : '#d1d5db', cursor: 'pointer', position: 'relative', transition: 'background 0.2s', padding: 0 } },
330 el('span', { style: { position: 'absolute', top: '3px', left: isAnnual ? '21px' : '3px', width: '18px', height: '18px', borderRadius: '50%', background: '#fff', transition: 'left 0.2s', display: 'block' } })
331 ),
332 el('span', { className: 'bkbg-pc-billing-label', style: { color: isAnnual ? a.accentColor : a.labelColor } },
333 __('Annual', 'blockenberg'),
334 a.annualDiscount > 0 && el('span', { style: { marginLeft: '6px', background: '#dcfce7', color: '#16a34a', fontSize: '11px', fontWeight: 700, padding: '2px 8px', borderRadius: '99px' } }, '-' + a.annualDiscount + '%')
335 )
336 ),
337 /* Sliders */
338 el('div', { className: 'bkbg-pc-sliders', style: { marginBottom: '24px' } },
339 a.sliders.map(function (sl) {
340 return el(SliderRow, { key: sl.id, sl: sl, a: a,
341 val: sliderVals[sl.id] !== undefined ? sliderVals[sl.id] : sl.value,
342 onChangeVal: function (v) { var nv = {}; nv[sl.id] = v; setSliderVals(Object.assign({}, sliderVals, nv)); }
343 });
344 })
345 ),
346 /* Add-ons */
347 a.addons.length > 0 && el('div', { className: 'bkbg-pc-addons', style: { marginBottom: '28px' } },
348 el('p', { className: 'bkbg-pc-addons-label', style: { color: a.labelColor, margin: '0 0 10px' } }, __('Add-ons', 'blockenberg')),
349 a.addons.map(function (ad) {
350 return el(AddonRow, { key: ad.id, ad: ad, a: a,
351 checked: addonChecked[ad.id] !== undefined ? addonChecked[ad.id] : ad.checked,
352 onToggle: function () { var nv = {}; nv[ad.id] = !addonChecked[ad.id]; setAddonChecked(Object.assign({}, addonChecked, nv)); }
353 });
354 })
355 ),
356 /* Price display */
357 el('div', { className: 'bkbg-pc-price-box', style: { background: a.priceBg, border: '1px solid ' + a.priceBorder, borderRadius: '12px', padding: '24px', textAlign: 'center', marginBottom: '20px' } },
358 el('div', { className: 'bkbg-pc-price', style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'center', gap: '2px', lineHeight: 1 } },
359 a.currencyPos === 'before' && el('span', { style: { fontSize: '24px', fontWeight: 900, color: a.priceAccent, marginTop: '6px' } }, a.currency),
360 el('span', { className: 'bkbg-pc-price-val', style: { color: a.priceColor } }, price.toFixed(2).replace(/\.00$/, '')),
361 a.currencyPos === 'after' && el('span', { style: { fontSize: '24px', fontWeight: 900, color: a.priceAccent, marginTop: '6px' } }, a.currency)
362 ),
363 el('p', { className: 'bkbg-pc-price-note', style: { fontSize: '13px', color: a.subtitleColor, margin: '6px 0 0' } }, priceNote)
364 ),
365 /* CTA */
366 el('a', { href: a.ctaUrl, className: 'bkbg-pc-cta-btn', style: { display: 'block', padding: '16px 28px', borderRadius: a.btnRadius + 'px', border: 'none', background: a.btnBg, color: a.btnColor, fontFamily: 'inherit', fontSize: '16px', fontWeight: 800, cursor: 'pointer', textAlign: 'center', textDecoration: 'none', lineHeight: 1 } }, a.ctaLabel)
367 )
368 )
369 )
370 );
371 },
372
373 deprecated: [{
374 attributes: {"title":{"type":"string","default":"Calculate Your Price"},"subtitle":{"type":"string","default":"Adjust the sliders to see your custom quote instantly."},"currency":{"type":"string","default":"$"},"currencyPos":{"type":"string","default":"before"},"billingToggle":{"type":"boolean","default":true},"annualDiscount":{"type":"number","default":20},"sliders":{"type":"array","default":[{"id":"sl1","label":"Team Members","unit":"users","min":1,"max":50,"step":1,"value":5,"pricePerUnit":12,"icon":"\ud83d\udc65"},{"id":"sl2","label":"Storage","unit":"GB","min":10,"max":1000,"step":10,"value":100,"pricePerUnit":0.05,"icon":"\ud83d\udcbe"},{"id":"sl3","label":"API Calls / month","unit":"k calls","min":10,"max":500,"step":10,"value":50,"pricePerUnit":0.01,"icon":"\u26a1"}]},"addons":{"type":"array","default":[{"id":"a1","label":"Priority Support","price":29,"checked":false,"icon":"\ud83c\udfa7"},{"id":"a2","label":"Advanced Analytics","price":19,"checked":false,"icon":"\ud83d\udcca"},{"id":"a3","label":"SSO / SAML","price":49,"checked":false,"icon":"\ud83d\udd10"}]},"basePrice":{"type":"number","default":0},"ctaLabel":{"type":"string","default":"Get Started"},"ctaUrl":{"type":"string","default":"#"},"ctaNewTab":{"type":"boolean","default":false},"priceNote":{"type":"string","default":"per month, billed monthly"},"priceNoteAnnual":{"type":"string","default":"per month, billed annually"},"maxWidth":{"type":"number","default":720},"cardRadius":{"type":"number","default":20},"cardPadding":{"type":"number","default":40},"sliderRadius":{"type":"number","default":99},"btnRadius":{"type":"number","default":10},"accentColor":{"type":"string","default":"#6c3fb5"},"sliderTrack":{"type":"string","default":"#e5e7eb"},"sliderFill":{"type":"string","default":"#6c3fb5"},"sliderThumb":{"type":"string","default":"#6c3fb5"},"cardBg":{"type":"string","default":"#ffffff"},"cardBorder":{"type":"string","default":"#e5e7eb"},"priceBg":{"type":"string","default":"#f9fafb"},"priceBorder":{"type":"string","default":"#e5e7eb"},"btnBg":{"type":"string","default":"#6c3fb5"},"btnColor":{"type":"string","default":"#ffffff"},"titleColor":{"type":"string","default":"#111827"},"subtitleColor":{"type":"string","default":"#6b7280"},"labelColor":{"type":"string","default":"#374151"},"priceColor":{"type":"string","default":"#111827"},"priceAccent":{"type":"string","default":"#6c3fb5"},"titleSize":{"type":"number","default":26},"subtitleSize":{"type":"number","default":15},"priceSize":{"type":"number","default":52},"labelSize":{"type":"number","default":14},"bgColor":{"type":"string","default":""},"paddingTop":{"type":"number","default":64},"paddingBottom":{"type":"number","default":64},"titleFontWeight":{"type":"string","default":"700"},"subtitleFontWeight":{"type":"string","default":"400"}},
375 save: function (props) {
376 var a = props.attributes;
377 function oldBuildWrapStyle(a) {
378 return {
379 '--bkbg-pc-accent': a.accentColor,
380 '--bkbg-pc-slider-track': a.sliderTrack,
381 '--bkbg-pc-slider-fill': a.sliderFill,
382 '--bkbg-pc-slider-thumb': a.sliderThumb,
383 '--bkbg-pc-card-bg': a.cardBg,
384 '--bkbg-pc-card-border': a.cardBorder,
385 '--bkbg-pc-price-bg': a.priceBg,
386 '--bkbg-pc-price-border': a.priceBorder,
387 '--bkbg-pc-btn-bg': a.btnBg,
388 '--bkbg-pc-btn-color': a.btnColor,
389 '--bkbg-pc-title-color': a.titleColor,
390 '--bkbg-pc-sub-color': a.subtitleColor,
391 '--bkbg-pc-label-color': a.labelColor,
392 '--bkbg-pc-price-color': a.priceColor,
393 '--bkbg-pc-price-accent': a.priceAccent,
394 '--bkbg-pc-card-r': a.cardRadius + 'px',
395 '--bkbg-pc-card-pad': a.cardPadding + 'px',
396 '--bkbg-pc-btn-r': a.btnRadius + 'px',
397 '--bkbg-pc-title-sz': a.titleSize + 'px',
398 '--bkbg-pc-sub-sz': a.subtitleSize + 'px',
399 '--bkbg-pc-price-sz': a.priceSize + 'px',
400 '--bkbg-pc-label-sz': a.labelSize + 'px',
401 paddingTop: a.paddingTop + 'px',
402 paddingBottom: a.paddingBottom + 'px',
403 backgroundColor: a.bgColor || undefined,
404 };
405 }
406 return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-pc-wrapper', style: oldBuildWrapStyle(a) }),
407 el('div', { className: 'bkbg-pc-outer', style: { maxWidth: a.maxWidth + 'px', margin: '0 auto' } },
408 el('div', { className: 'bkbg-pc-card',
409 'data-currency': a.currency,
410 'data-currency-pos': a.currencyPos,
411 'data-annual-discount': a.annualDiscount,
412 'data-base-price': a.basePrice,
413 style: { background: a.cardBg, border: '1px solid ' + a.cardBorder, borderRadius: a.cardRadius + 'px', padding: a.cardPadding + 'px', boxSizing: 'border-box' } },
414 el('div', { className: 'bkbg-pc-header' },
415 el(RichText.Content, { tagName: 'h2', className: 'bkbg-pc-title', value: a.title }),
416 el(RichText.Content, { tagName: 'p', className: 'bkbg-pc-subtitle', value: a.subtitle })
417 ),
418 a.billingToggle && el('div', { className: 'bkbg-pc-billing-row' },
419 el('span', { className: 'bkbg-pc-billing-label is-monthly' }, __('Monthly', 'blockenberg')),
420 el('button', { type: 'button', className: 'bkbg-pc-toggle-btn', 'aria-pressed': 'false', 'aria-label': __('Toggle billing period', 'blockenberg') },
421 el('span', { className: 'bkbg-pc-toggle-thumb' })
422 ),
423 el('span', { className: 'bkbg-pc-billing-label is-annual' },
424 __('Annual', 'blockenberg'),
425 a.annualDiscount > 0 && el('span', { className: 'bkbg-pc-discount-badge' }, '-' + a.annualDiscount + '%')
426 )
427 ),
428 el('div', { className: 'bkbg-pc-sliders' },
429 a.sliders.map(function (sl) {
430 return el('div', { key: sl.id, className: 'bkbg-pc-slider-row', 'data-slider-id': sl.id, 'data-price-per-unit': sl.pricePerUnit },
431 el('div', { className: 'bkbg-pc-slider-header' },
432 el('div', { className: 'bkbg-pc-slider-label-wrap' },
433 sl.icon && el('span', { className: 'bkbg-pc-slider-icon', 'aria-hidden': 'true' }, sl.icon),
434 el('span', { className: 'bkbg-pc-slider-label' }, sl.label)
435 ),
436 el('span', { className: 'bkbg-pc-slider-val' }, sl.value + ' ' + sl.unit)
437 ),
438 el('div', { className: 'bkbg-pc-slider-track-wrap' },
439 el('div', { className: 'bkbg-pc-slider-fill' }),
440 el('input', { type: 'range', min: sl.min, max: sl.max, step: sl.step, defaultValue: sl.value, 'data-unit': sl.unit, className: 'bkbg-pc-range', 'aria-label': sl.label })
441 )
442 );
443 })
444 ),
445 a.addons.length > 0 && el('div', { className: 'bkbg-pc-addons' },
446 el('p', { className: 'bkbg-pc-addons-label' }, __('Add-ons', 'blockenberg')),
447 a.addons.map(function (ad) {
448 return el('label', { key: ad.id, className: 'bkbg-pc-addon', 'data-addon-id': ad.id, 'data-price': ad.price },
449 el('div', { className: 'bkbg-pc-addon-left' },
450 el('input', { type: 'checkbox', defaultChecked: ad.checked, className: 'bkbg-pc-addon-cb', 'data-addon-id': ad.id }),
451 ad.icon && el('span', { className: 'bkbg-pc-addon-icon', 'aria-hidden': 'true' }, ad.icon),
452 el('span', { className: 'bkbg-pc-addon-label' }, ad.label)
453 ),
454 el('span', { className: 'bkbg-pc-addon-price' }, '+' + a.currency + ad.price + '/mo')
455 );
456 })
457 ),
458 el('div', { className: 'bkbg-pc-price-box' },
459 el('div', { className: 'bkbg-pc-price' },
460 a.currencyPos === 'before' && el('span', { className: 'bkbg-pc-currency' }, a.currency),
461 el('span', { className: 'bkbg-pc-price-val' }, '0'),
462 a.currencyPos === 'after' && el('span', { className: 'bkbg-pc-currency' }, a.currency)
463 ),
464 el('p', { className: 'bkbg-pc-price-note', 'data-monthly': a.priceNote, 'data-annual': a.priceNoteAnnual }, a.priceNote)
465 ),
466 el('a', { href: a.ctaUrl, className: 'bkbg-pc-cta-btn', target: a.ctaNewTab ? '_blank' : undefined, rel: a.ctaNewTab ? 'noopener noreferrer' : undefined }, a.ctaLabel)
467 )
468 )
469 );
470 }
471 }],
472
473 save: function (props) {
474 var a = props.attributes;
475 var _tvFn = getTypoCssVars();
476 var saveStyle = buildWrapStyle(a);
477 if (_tvFn) {
478 Object.assign(saveStyle, _tvFn(a.titleTypo, '--bkbg-pc-tt-'));
479 Object.assign(saveStyle, _tvFn(a.subtitleTypo, '--bkbg-pc-st-'));
480 Object.assign(saveStyle, _tvFn(a.priceTypo, '--bkbg-pc-pr-'));
481 Object.assign(saveStyle, _tvFn(a.labelTypo, '--bkbg-pc-lb-'));
482 }
483 return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-pc-wrapper', style: saveStyle }),
484 el('div', { className: 'bkbg-pc-outer', style: { maxWidth: a.maxWidth + 'px', margin: '0 auto' } },
485 el('div', { className: 'bkbg-pc-card',
486 'data-currency': a.currency,
487 'data-currency-pos': a.currencyPos,
488 'data-annual-discount': a.annualDiscount,
489 'data-base-price': a.basePrice,
490 style: { background: a.cardBg, border: '1px solid ' + a.cardBorder, borderRadius: a.cardRadius + 'px', padding: a.cardPadding + 'px', boxSizing: 'border-box' } },
491 el('div', { className: 'bkbg-pc-header' },
492 el(RichText.Content, { tagName: 'h2', className: 'bkbg-pc-title', value: a.title }),
493 el(RichText.Content, { tagName: 'p', className: 'bkbg-pc-subtitle', value: a.subtitle })
494 ),
495 a.billingToggle && el('div', { className: 'bkbg-pc-billing-row' },
496 el('span', { className: 'bkbg-pc-billing-label is-monthly' }, __('Monthly', 'blockenberg')),
497 el('button', { type: 'button', className: 'bkbg-pc-toggle-btn', 'aria-pressed': 'false', 'aria-label': __('Toggle billing period', 'blockenberg') },
498 el('span', { className: 'bkbg-pc-toggle-thumb' })
499 ),
500 el('span', { className: 'bkbg-pc-billing-label is-annual' },
501 __('Annual', 'blockenberg'),
502 a.annualDiscount > 0 && el('span', { className: 'bkbg-pc-discount-badge' }, '-' + a.annualDiscount + '%')
503 )
504 ),
505 el('div', { className: 'bkbg-pc-sliders' },
506 a.sliders.map(function (sl) {
507 return el('div', { key: sl.id, className: 'bkbg-pc-slider-row', 'data-slider-id': sl.id, 'data-price-per-unit': sl.pricePerUnit },
508 el('div', { className: 'bkbg-pc-slider-header' },
509 el('div', { className: 'bkbg-pc-slider-label-wrap' },
510 sl.icon && el('span', { className: 'bkbg-pc-slider-icon', 'aria-hidden': 'true' }, (sl.iconType || 'custom-char') !== 'custom-char' ? IP().buildSaveIcon(sl.iconType, sl.icon, sl.iconDashicon, sl.iconImageUrl, sl.iconDashiconColor) : sl.icon),
511 el('span', { className: 'bkbg-pc-slider-label' }, sl.label)
512 ),
513 el('span', { className: 'bkbg-pc-slider-val' }, sl.value + ' ' + sl.unit)
514 ),
515 el('div', { className: 'bkbg-pc-slider-track-wrap' },
516 el('div', { className: 'bkbg-pc-slider-fill' }),
517 el('input', { type: 'range', min: sl.min, max: sl.max, step: sl.step, defaultValue: sl.value, 'data-unit': sl.unit, className: 'bkbg-pc-range', 'aria-label': sl.label })
518 )
519 );
520 })
521 ),
522 a.addons.length > 0 && el('div', { className: 'bkbg-pc-addons' },
523 el('p', { className: 'bkbg-pc-addons-label' }, __('Add-ons', 'blockenberg')),
524 a.addons.map(function (ad) {
525 return el('label', { key: ad.id, className: 'bkbg-pc-addon', 'data-addon-id': ad.id, 'data-price': ad.price },
526 el('div', { className: 'bkbg-pc-addon-left' },
527 el('input', { type: 'checkbox', defaultChecked: ad.checked, className: 'bkbg-pc-addon-cb', 'data-addon-id': ad.id }),
528 ad.icon && el('span', { className: 'bkbg-pc-addon-icon', 'aria-hidden': 'true' }, (ad.iconType || 'custom-char') !== 'custom-char' ? IP().buildSaveIcon(ad.iconType, ad.icon, ad.iconDashicon, ad.iconImageUrl, ad.iconDashiconColor) : ad.icon),
529 el('span', { className: 'bkbg-pc-addon-label' }, ad.label)
530 ),
531 el('span', { className: 'bkbg-pc-addon-price' }, '+' + a.currency + ad.price + '/mo')
532 );
533 })
534 ),
535 el('div', { className: 'bkbg-pc-price-box' },
536 el('div', { className: 'bkbg-pc-price' },
537 a.currencyPos === 'before' && el('span', { className: 'bkbg-pc-currency' }, a.currency),
538 el('span', { className: 'bkbg-pc-price-val' }, '0'),
539 a.currencyPos === 'after' && el('span', { className: 'bkbg-pc-currency' }, a.currency)
540 ),
541 el('p', { className: 'bkbg-pc-price-note', 'data-monthly': a.priceNote, 'data-annual': a.priceNoteAnnual }, a.priceNote)
542 ),
543 el('a', { href: a.ctaUrl, className: 'bkbg-pc-cta-btn', target: a.ctaNewTab ? '_blank' : undefined, rel: a.ctaNewTab ? 'noopener noreferrer' : undefined }, a.ctaLabel)
544 )
545 )
546 );
547 }
548 });
549 }() );
550