PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
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 / pricing-table / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/pricing-table/index.js

696 lines 44.0 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 useBlockProps = wp.blockEditor.useBlockProps;
9 var RichText = wp.blockEditor.RichText;
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
22 function buildTypoVars(a) {
23 var fn = getTypoCssVars();
24 if (!fn) return {};
25 var v = {};
26 Object.assign(v, fn(a.nameTypo || {}, '--bkbg-pt-nm-'));
27 Object.assign(v, fn(a.descTypo || {}, '--bkbg-pt-ds-'));
28 Object.assign(v, fn(a.priceTypo || {}, '--bkbg-pt-pr-'));
29 Object.assign(v, fn(a.featureTypo || {}, '--bkbg-pt-ft-'));
30 Object.assign(v, fn(a.btnTypo || {}, '--bkbg-pt-bt-'));
31 return v;
32 }
33
34 // ── CSS vars ──────────────────────────────────────────────────────────────
35 function buildWrapStyle(a) {
36 var shadow = a.cardStyle === 'shadow' ? '0 8px 32px rgba(0,0,0,0.10)' :
37 a.cardStyle === 'shadow-lg' ? '0 20px 60px rgba(0,0,0,0.16)' :
38 a.cardStyle === 'flat' ? 'none' : 'none';
39 return {
40 '--bkbg-pt-accent' : a.accentColor,
41 '--bkbg-pt-accent2' : a.accentColorSecondary,
42 '--bkbg-pt-card-bg' : a.cardBg,
43 '--bkbg-pt-card-border-color' : a.cardBorderColor,
44 '--bkbg-pt-card-border-w' : a.cardBorderWidth + 'px',
45 '--bkbg-pt-card-radius' : a.cardBorderRadius + 'px',
46 '--bkbg-pt-card-pad' : a.cardPaddingTop + 'px ' + a.cardPaddingRight + 'px ' + a.cardPaddingBottom + 'px ' + a.cardPaddingLeft + 'px',
47 '--bkbg-pt-card-shadow' : shadow,
48 '--bkbg-pt-plan-name-color' : a.planNameColor,
49 '--bkbg-pt-desc-color' : a.descriptionColor,
50 '--bkbg-pt-price-color' : a.priceColor,
51 '--bkbg-pt-currency-size' : a.currencySize + 'px',
52 '--bkbg-pt-period-size' : a.periodSize + 'px',
53 '--bkbg-pt-period-color' : a.periodColor,
54 '--bkbg-pt-subtext-size' : a.priceSubtextSize + 'px',
55 '--bkbg-pt-subtext-color' : a.priceSubtextColor,
56 '--bkbg-pt-feature-color' : a.featureColor,
57 '--bkbg-pt-feature-excl-color': a.featureExcludedColor,
58 '--bkbg-pt-feature-incl-icon-color': a.featureIncludedIconColor,
59 '--bkbg-pt-feature-excl-icon-color': a.featureExcludedIconColor,
60 '--bkbg-pt-feature-gap' : a.featureGap + 'px',
61 '--bkbg-pt-btn-bg' : a.btnBg,
62 '--bkbg-pt-btn-color' : a.btnColor,
63 '--bkbg-pt-btn-bg-hover' : a.btnBgHover,
64 '--bkbg-pt-btn-color-hover' : a.btnColorHover,
65 '--bkbg-pt-btn-border-color' : a.btnBorderColor,
66 '--bkbg-pt-btn-border-w' : a.btnBorderWidth + 'px',
67 '--bkbg-pt-btn-radius' : a.btnBorderRadius + 'px',
68 '--bkbg-pt-btn-pad-v' : a.btnPaddingV + 'px',
69 '--bkbg-pt-badge-bg' : a.badgeBg,
70 '--bkbg-pt-badge-color' : a.badgeColor,
71 '--bkbg-pt-badge-size' : a.badgeSize + 'px',
72 '--bkbg-pt-badge-radius' : a.badgeBorderRadius + 'px',
73 '--bkbg-pt-header-bg' : a.headerBg,
74 '--bkbg-pt-section-gap' : a.sectionGap + 'px'
75 };
76 }
77
78 // ── Color swatch ──────────────────────────────────────────────────────────
79 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
80 var isOpen = openKey === key;
81 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
82 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
83 el('div', { style: { position: 'relative', flexShrink: 0 } },
84 el('button', {
85 type: 'button',
86 title: value || 'none',
87 onClick: function () { setOpenKey(isOpen ? null : key); },
88 style: {
89 width: '28px', height: '28px', borderRadius: '4px',
90 border: isOpen ? '2px solid #007cba' : '2px solid #ddd',
91 cursor: 'pointer', padding: 0, display: 'block',
92 background: value || '#fff'
93 }
94 }),
95 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
96 el('div', { style: { padding: '8px' } },
97 el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange })
98 )
99 )
100 )
101 );
102 }
103
104 function updateFeature(features, index, field, value, setAttributes) {
105 var newFeatures = features.map(function (f, i) {
106 if (i !== index) return f;
107 var updated = {};
108 for (var k in f) { updated[k] = f[k]; }
109 updated[field] = value;
110 return updated;
111 });
112 setAttributes({ features: newFeatures });
113 }
114
115 // ── Register ──────────────────────────────────────────────────────────────
116 registerBlockType('blockenberg/pricing-table', {
117 title: __('Pricing Table', 'blockenberg'),
118 icon: 'products',
119 category: 'bkbg-marketing',
120 description: __('Pricing card with plan name, price, features list, and CTA button.', 'blockenberg'),
121
122 edit: function (props) {
123 var a = props.attributes;
124 var setAttributes = props.setAttributes;
125
126 var openColorKeyState = useState(null);
127 var openColorKey = openColorKeyState[0];
128 var setOpenColorKey = openColorKeyState[1];
129
130 function cc(key, label, attrKey) {
131 return renderColorControl(key, label, a[attrKey], function (val) {
132 var upd = {}; upd[attrKey] = val; setAttributes(upd);
133 }, openColorKey, setOpenColorKey);
134 }
135
136 function addFeature() {
137 setAttributes({
138 features: a.features.concat([{ text: __('New feature', 'blockenberg'), included: true, icon: 'dashicons-yes-alt' }])
139 });
140 }
141
142 function removeFeature(i) {
143 setAttributes({ features: a.features.filter(function (_, idx) { return idx !== i; }) });
144 }
145
146 function moveFeature(i, dir) {
147 var ni = i + dir;
148 if (ni < 0 || ni >= a.features.length) return;
149 var arr = a.features.slice();
150 var tmp = arr[i]; arr[i] = arr[ni]; arr[ni] = tmp;
151 setAttributes({ features: arr });
152 }
153
154 var cardClass = 'bkbg-pt-card bkbg-pt-style-' + a.cardStyle + (a.isPopular ? ' is-popular' : '') + ' bkbg-pt-header-' + a.headerStyle;
155 var blockProps = useBlockProps({ className: cardClass, style: Object.assign({}, buildWrapStyle(a), buildTypoVars(a)) });
156
157 // ── Inspector ─────────────────────────────────────────────────────
158 var inspector = el(InspectorControls, {},
159 // Plan Info
160 el(PanelBody, { title: __('Plan Info', 'blockenberg'), initialOpen: true },
161 el(TextControl, {
162 label: __('Plan Name', 'blockenberg'), value: a.planName,
163 onChange: function (v) { setAttributes({ planName: v }); }
164 }),
165 el(TextControl, {
166 label: __('Description', 'blockenberg'), value: a.planDescription,
167 onChange: function (v) { setAttributes({ planDescription: v }); }
168 }),
169 el(ToggleControl, {
170 label: __('Show Description', 'blockenberg'), checked: a.showDescription,
171 onChange: function (v) { setAttributes({ showDescription: v }); }
172 }),
173 el(ToggleControl, {
174 label: __('Mark as Popular', 'blockenberg'), checked: a.isPopular,
175 onChange: function (v) { setAttributes({ isPopular: v }); }
176 }),
177 a.isPopular && el(TextControl, {
178 label: __('Popular Badge Label', 'blockenberg'), value: a.popularLabel,
179 onChange: function (v) { setAttributes({ popularLabel: v }); }
180 })
181 ),
182
183 // Pricing
184 el(PanelBody, { title: __('Price', 'blockenberg'), initialOpen: false },
185 el(TextControl, {
186 label: __('Currency Symbol', 'blockenberg'), value: a.currency,
187 onChange: function (v) { setAttributes({ currency: v }); }
188 }),
189 el(SelectControl, {
190 label: __('Currency Position', 'blockenberg'), value: a.currencyPosition,
191 options: [{ label: __('Before', 'blockenberg'), value: 'before' }, { label: __('After', 'blockenberg'), value: 'after' }],
192 onChange: function (v) { setAttributes({ currencyPosition: v }); }
193 }),
194 el(TextControl, {
195 label: __('Price', 'blockenberg'), value: a.price,
196 onChange: function (v) { setAttributes({ price: v }); }
197 }),
198 el(TextControl, {
199 label: __('Period (e.g. /month)', 'blockenberg'), value: a.pricePeriod,
200 onChange: function (v) { setAttributes({ pricePeriod: v }); }
201 }),
202 el(TextControl, {
203 label: __('Price Subtext', 'blockenberg'), value: a.priceSubtext,
204 onChange: function (v) { setAttributes({ priceSubtext: v }); }
205 }),
206 el(ToggleControl, {
207 label: __('Show Price Subtext', 'blockenberg'), checked: a.showPriceSubtext,
208 onChange: function (v) { setAttributes({ showPriceSubtext: v }); }
209 })
210 ),
211
212 // Features
213 el(PanelBody, { title: __('Features', 'blockenberg'), initialOpen: false },
214 el(SelectControl, {
215 label: __('Feature List Style', 'blockenberg'), value: a.featureListStyle,
216 options: [
217 { label: __('Icons', 'blockenberg'), value: 'icon' },
218 { label: __('Bullet', 'blockenberg'), value: 'bullet' },
219 { label: __('Checkmark (CSS)', 'blockenberg'), value: 'check' },
220 { label: __('None', 'blockenberg'), value: 'none' }
221 ],
222 onChange: function (v) { setAttributes({ featureListStyle: v }); }
223 }),
224 el(ToggleControl, {
225 label: __('Show Divider between Features and Button', 'blockenberg'), checked: a.showFeatureDivider,
226 onChange: function (v) { setAttributes({ showFeatureDivider: v }); }
227 }),
228 el(RangeControl, {
229 label: __('Gap Between Features (px)', 'blockenberg'), value: a.featureGap, min: 4, max: 32,
230 onChange: function (v) { setAttributes({ featureGap: v }); }
231 }),
232 a.features.map(function (feat, i) {
233 return el('div', {
234 key: i,
235 style: { border: '1px solid #e0e0e0', borderRadius: '6px', padding: '10px', marginBottom: '8px', background: '#fafafa' }
236 },
237 el('div', { style: { display: 'flex', alignItems: 'center', gap: '4px', marginBottom: '8px' } },
238 el('span', { style: { fontSize: '11px', fontWeight: '600', flex: 1, color: feat.included ? '#15803d' : '#94a3b8' } },
239 (i + 1) + '. ' + (feat.included ? __('Included', 'blockenberg') : __('Excluded', 'blockenberg'))
240 ),
241 el(Button, { isSmall: true, variant: 'tertiary', onClick: function () { moveFeature(i, -1); }, disabled: i === 0 }, ''),
242 el(Button, { isSmall: true, variant: 'tertiary', onClick: function () { moveFeature(i, 1); }, disabled: i === a.features.length - 1 }, ''),
243 el(Button, { isSmall: true, isDestructive: true, variant: 'tertiary', onClick: function () { removeFeature(i); } }, '')
244 ),
245 el(TextControl, {
246 label: __('Feature Text', 'blockenberg'), value: feat.text,
247 onChange: function (v) { updateFeature(a.features, i, 'text', v, setAttributes); }
248 }),
249 el(ToggleControl, {
250 label: __('Included', 'blockenberg'), checked: feat.included,
251 onChange: function (v) {
252 updateFeature(a.features, i, 'included', v, setAttributes);
253 updateFeature(a.features, i, 'icon', v ? 'dashicons-yes-alt' : 'dashicons-no-alt', setAttributes);
254 }
255 })
256 );
257 }),
258 el(Button, { variant: 'secondary', onClick: addFeature, style: { width: '100%', justifyContent: 'center' } },
259 '+ ' + __('Add Feature', 'blockenberg')
260 )
261 ),
262
263 // Button
264 el(PanelBody, { title: __('Button', 'blockenberg'), initialOpen: false },
265 el(TextControl, {
266 label: __('Button Text', 'blockenberg'), value: a.buttonText,
267 onChange: function (v) { setAttributes({ buttonText: v }); }
268 }),
269 el(TextControl, {
270 label: __('Button URL', 'blockenberg'), value: a.buttonUrl,
271 onChange: function (v) { setAttributes({ buttonUrl: v }); }
272 }),
273 el(ToggleControl, {
274 label: __('Open in New Tab', 'blockenberg'), checked: a.buttonTarget,
275 onChange: function (v) { setAttributes({ buttonTarget: v }); }
276 }),
277 el(SelectControl, {
278 label: __('Button Width', 'blockenberg'), value: a.btnWidth,
279 options: [
280 { label: __('Full Width', 'blockenberg'), value: 'full' },
281 { label: __('Auto', 'blockenberg'), value: 'auto' }
282 ],
283 onChange: function (v) { setAttributes({ btnWidth: v }); }
284 }),
285 el(RangeControl, {
286 label: __('Vertical Padding (px)', 'blockenberg'), value: a.btnPaddingV, min: 8, max: 32,
287 onChange: function (v) { setAttributes({ btnPaddingV: v }); }
288 }),
289 el(RangeControl, {
290 label: __('Border Width (px)', 'blockenberg'), value: a.btnBorderWidth, min: 0, max: 6,
291 onChange: function (v) { setAttributes({ btnBorderWidth: v }); }
292 }),
293 el(RangeControl, {
294 label: __('Border Radius (px)', 'blockenberg'), value: a.btnBorderRadius, min: 0, max: 60,
295 onChange: function (v) { setAttributes({ btnBorderRadius: v }); }
296 }),
297 cc('btnBg', __('Button Background', 'blockenberg'), 'btnBg'),
298 cc('btnColor', __('Button Text Color', 'blockenberg'), 'btnColor'),
299 cc('btnBgHover', __('Button Hover Background', 'blockenberg'), 'btnBgHover'),
300 cc('btnColorHover', __('Button Hover Text Color', 'blockenberg'), 'btnColorHover'),
301 cc('btnBorderColor', __('Button Border Color', 'blockenberg'), 'btnBorderColor')
302 ),
303
304 // Card design
305 el(PanelBody, { title: __('Card Design', 'blockenberg'), initialOpen: false },
306 el(SelectControl, {
307 label: __('Card Style', 'blockenberg'), value: a.cardStyle,
308 options: [
309 { label: __('Shadow', 'blockenberg'), value: 'shadow' },
310 { label: __('Large Shadow', 'blockenberg'), value: 'shadow-lg' },
311 { label: __('Flat + Border', 'blockenberg'), value: 'flat' },
312 { label: __('Gradient Header', 'blockenberg'), value: 'gradient' },
313 { label: __('Colored Header', 'blockenberg'), value: 'colored-header' }
314 ],
315 onChange: function (v) { setAttributes({ cardStyle: v }); }
316 }),
317 (a.cardStyle === 'colored-header' || a.cardStyle === 'gradient') && el(SelectControl, {
318 label: __('Header Style', 'blockenberg'), value: a.headerStyle,
319 options: [
320 { label: __('Accent Color', 'blockenberg'), value: 'accent' },
321 { label: __('Dark', 'blockenberg'), value: 'dark' },
322 { label: __('Light', 'blockenberg'), value: 'light' }
323 ],
324 onChange: function (v) { setAttributes({ headerStyle: v }); }
325 }),
326 el(RangeControl, {
327 label: __('Border Radius (px)', 'blockenberg'), value: a.cardBorderRadius, min: 0, max: 40,
328 onChange: function (v) { setAttributes({ cardBorderRadius: v }); }
329 }),
330 el(RangeControl, {
331 label: __('Border Width (px)', 'blockenberg'), value: a.cardBorderWidth, min: 0, max: 6,
332 onChange: function (v) { setAttributes({ cardBorderWidth: v }); }
333 }),
334 el(RangeControl, {
335 label: __('Section Gap (px)', 'blockenberg'), value: a.sectionGap, min: 8, max: 60,
336 onChange: function (v) { setAttributes({ sectionGap: v }); }
337 }),
338 el(RangeControl, {
339 label: __('Padding Top (px)', 'blockenberg'), value: a.cardPaddingTop, min: 0, max: 80,
340 onChange: function (v) { setAttributes({ cardPaddingTop: v }); }
341 }),
342 el(RangeControl, {
343 label: __('Padding Right (px)', 'blockenberg'), value: a.cardPaddingRight, min: 0, max: 80,
344 onChange: function (v) { setAttributes({ cardPaddingRight: v }); }
345 }),
346 el(RangeControl, {
347 label: __('Padding Bottom (px)', 'blockenberg'), value: a.cardPaddingBottom, min: 0, max: 80,
348 onChange: function (v) { setAttributes({ cardPaddingBottom: v }); }
349 }),
350 el(RangeControl, {
351 label: __('Padding Left (px)', 'blockenberg'), value: a.cardPaddingLeft, min: 0, max: 80,
352 onChange: function (v) { setAttributes({ cardPaddingLeft: v }); }
353 }),
354 cc('accentColor', __('Accent Color', 'blockenberg'), 'accentColor'),
355 cc('accentColorSecondary', __('Accent Color 2 (gradient end)', 'blockenberg'), 'accentColorSecondary'),
356 cc('cardBg', __('Card Background', 'blockenberg'), 'cardBg'),
357 cc('cardBorderColor', __('Card Border Color', 'blockenberg'), 'cardBorderColor'),
358 cc('headerBg', __('Header Background', 'blockenberg'), 'headerBg')
359 ),
360
361 // Typography
362 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
363 (function () {
364 var TC = getTypoControl();
365 if (!TC) return el('p', null, 'Loading\u2026');
366 return el(Fragment, null,
367 el(TC, { label: 'Plan Name', value: a.nameTypo, onChange: function (v) { setAttributes({ nameTypo: v }); } }),
368 el(TC, { label: 'Description', value: a.descTypo, onChange: function (v) { setAttributes({ descTypo: v }); } }),
369 el(TC, { label: 'Price', value: a.priceTypo, onChange: function (v) { setAttributes({ priceTypo: v }); } }),
370 el(TC, { label: 'Feature', value: a.featureTypo, onChange: function (v) { setAttributes({ featureTypo: v }); } }),
371 el(TC, { label: 'Button', value: a.btnTypo, onChange: function (v) { setAttributes({ btnTypo: v }); } })
372 );
373 })(),
374 el(RangeControl, { label: __('Currency Size (px)', 'blockenberg'), value: a.currencySize, min: 12, max: 48, onChange: function (v) { setAttributes({ currencySize: v }); } }),
375 el(RangeControl, { label: __('Period Size (px)', 'blockenberg'), value: a.periodSize, min: 11, max: 24, onChange: function (v) { setAttributes({ periodSize: v }); } }),
376 el(RangeControl, { label: __('Subtext Size (px)', 'blockenberg'), value: a.priceSubtextSize, min: 10, max: 18, onChange: function (v) { setAttributes({ priceSubtextSize: v }); } }),
377 el(RangeControl, { label: __('Badge Size (px)', 'blockenberg'), value: a.badgeSize, min: 10, max: 18, onChange: function (v) { setAttributes({ badgeSize: v }); } }),
378 cc('planNameColor', __('Plan Name Color', 'blockenberg'), 'planNameColor'),
379 cc('descriptionColor', __('Description Color', 'blockenberg'), 'descriptionColor'),
380 cc('priceColor', __('Price Color', 'blockenberg'), 'priceColor'),
381 cc('periodColor', __('Period Color', 'blockenberg'), 'periodColor'),
382 cc('priceSubtextColor', __('Subtext Color', 'blockenberg'), 'priceSubtextColor'),
383 cc('featureColor', __('Feature (included) Color', 'blockenberg'), 'featureColor'),
384 cc('featureExcludedColor', __('Feature (excluded) Color', 'blockenberg'), 'featureExcludedColor'),
385 cc('featureIncludedIconColor', __('Included Icon Color', 'blockenberg'), 'featureIncludedIconColor'),
386 cc('featureExcludedIconColor', __('Excluded Icon Color', 'blockenberg'), 'featureExcludedIconColor')
387 ),
388
389 // Badge
390 el(PanelBody, { title: __('Popular Badge', 'blockenberg'), initialOpen: false },
391 el(RangeControl, { label: __('Border Radius (px)', 'blockenberg'), value: a.badgeBorderRadius, min: 0, max: 50, onChange: function (v) { setAttributes({ badgeBorderRadius: v }); } }),
392 cc('badgeBg', __('Badge Background', 'blockenberg'), 'badgeBg'),
393 cc('badgeColor', __('Badge Text Color', 'blockenberg'), 'badgeColor')
394 )
395 );
396
397 // ── Preview render ─────────────────────────────────────────────────
398 function renderFeatureIcon(feat) {
399 if (a.featureListStyle === 'none') return null;
400 if (a.featureListStyle === 'bullet') return el('span', { className: 'bkbg-pt-feat-bullet' });
401 if (a.featureListStyle === 'check') return el('span', { className: 'bkbg-pt-feat-check' + (feat.included ? ' is-included' : ' is-excluded') });
402 // dashicons
403 var icon = feat.included ? 'dashicons-yes-alt' : 'dashicons-no-alt';
404 return el('span', { className: 'dashicons ' + icon + ' bkbg-pt-feat-icon' + (feat.included ? ' is-included' : ' is-excluded') });
405 }
406
407 function renderPriceArea() {
408 var currencyEl = el('span', { className: 'bkbg-pt-currency' }, a.currency);
409 var priceEl = el('span', { className: 'bkbg-pt-price-amount' }, a.price);
410 var periodEl = el('span', { className: 'bkbg-pt-period' }, a.pricePeriod);
411 return el('div', { className: 'bkbg-pt-price-row' },
412 el('div', { className: 'bkbg-pt-price-main' },
413 a.currencyPosition === 'before' ? el(Fragment, {}, currencyEl, priceEl) : el(Fragment, {}, priceEl, currencyEl),
414 periodEl
415 ),
416 a.showPriceSubtext && a.priceSubtext && el('div', { className: 'bkbg-pt-subtext' }, a.priceSubtext)
417 );
418 }
419
420 var headerChildren = [
421 a.isPopular && el('div', { key: 'badge', className: 'bkbg-pt-badge' }, a.popularLabel),
422 el(RichText, {
423 key: 'name', tagName: 'div', className: 'bkbg-pt-plan-name',
424 value: a.planName, onChange: function (v) { setAttributes({ planName: v }); }
425 }),
426 a.showDescription && el(RichText, {
427 key: 'desc', tagName: 'div', className: 'bkbg-pt-description',
428 value: a.planDescription, onChange: function (v) { setAttributes({ planDescription: v }); },
429 placeholder: __('Plan description…', 'blockenberg')
430 })
431 ];
432
433 return el(Fragment, {},
434 inspector,
435 el('div', blockProps,
436 el('div', { className: 'bkbg-pt-header' }, headerChildren),
437 el('div', { className: 'bkbg-pt-pricing' }, renderPriceArea()),
438 el('ul', { className: 'bkbg-pt-features bkbg-pt-feat-style-' + a.featureListStyle },
439 a.features.map(function (feat, i) {
440 return el('li', { key: i, className: 'bkbg-pt-feat-item' + (feat.included ? ' is-included' : ' is-excluded') },
441 renderFeatureIcon(feat),
442 el('span', { className: 'bkbg-pt-feat-text' }, feat.text)
443 );
444 })
445 ),
446 a.showFeatureDivider && el('hr', { className: 'bkbg-pt-divider' }),
447 el('div', { className: 'bkbg-pt-cta' },
448 el('a', {
449 href: a.buttonUrl || '#',
450 className: 'bkbg-pt-btn bkbg-pt-btn-' + a.btnWidth,
451 onClick: function (e) { e.preventDefault(); }
452 }, a.buttonText)
453 )
454 )
455 );
456 },
457
458 // ── Save ─────────────────────────────────────────────────────────────
459 save: function (props) {
460 var a = props.attributes;
461 var cardClass = 'bkbg-pt-card bkbg-pt-style-' + a.cardStyle + (a.isPopular ? ' is-popular' : '') + ' bkbg-pt-header-' + a.headerStyle;
462
463 function saveFeatureIcon(feat) {
464 if (a.featureListStyle === 'none') return null;
465 if (a.featureListStyle === 'bullet') return el('span', { className: 'bkbg-pt-feat-bullet', 'aria-hidden': 'true' });
466 if (a.featureListStyle === 'check') return el('span', { className: 'bkbg-pt-feat-check' + (feat.included ? ' is-included' : ' is-excluded'), 'aria-hidden': 'true' });
467 var icon = feat.included ? 'dashicons-yes-alt' : 'dashicons-no-alt';
468 return el('span', { className: 'dashicons ' + icon + ' bkbg-pt-feat-icon' + (feat.included ? ' is-included' : ' is-excluded'), 'aria-hidden': 'true' });
469 }
470
471 var currencyEl = el('span', { className: 'bkbg-pt-currency' }, a.currency);
472 var priceEl = el('span', { className: 'bkbg-pt-price-amount' }, a.price);
473 var periodEl = el('span', { className: 'bkbg-pt-period' }, a.pricePeriod);
474
475 return el('div', wp.blockEditor.useBlockProps.save({ className: cardClass, style: Object.assign({}, buildWrapStyle(a), buildTypoVars(a)) }),
476 el('div', { className: 'bkbg-pt-header' },
477 a.isPopular && el('div', { className: 'bkbg-pt-badge' }, a.popularLabel),
478 el(RichText.Content, { tagName: 'div', className: 'bkbg-pt-plan-name', value: a.planName }),
479 a.showDescription && el(RichText.Content, { tagName: 'div', className: 'bkbg-pt-description', value: a.planDescription })
480 ),
481 el('div', { className: 'bkbg-pt-pricing' },
482 el('div', { className: 'bkbg-pt-price-row' },
483 el('div', { className: 'bkbg-pt-price-main' },
484 a.currencyPosition === 'before' ? el(Fragment, {}, currencyEl, priceEl) : el(Fragment, {}, priceEl, currencyEl),
485 periodEl
486 ),
487 a.showPriceSubtext && a.priceSubtext && el('div', { className: 'bkbg-pt-subtext' }, a.priceSubtext)
488 )
489 ),
490 el('ul', { className: 'bkbg-pt-features bkbg-pt-feat-style-' + a.featureListStyle },
491 a.features.map(function (feat, i) {
492 return el('li', { key: i, className: 'bkbg-pt-feat-item' + (feat.included ? ' is-included' : ' is-excluded') },
493 saveFeatureIcon(feat),
494 el('span', { className: 'bkbg-pt-feat-text' }, feat.text)
495 );
496 })
497 ),
498 a.showFeatureDivider && el('hr', { className: 'bkbg-pt-divider' }),
499 el('div', { className: 'bkbg-pt-cta' },
500 el('a', {
501 href: a.buttonUrl || '#',
502 className: 'bkbg-pt-btn bkbg-pt-btn-' + a.btnWidth,
503 target: a.buttonTarget ? '_blank' : undefined,
504 rel: a.buttonTarget ? 'noopener noreferrer' : undefined
505 }, a.buttonText)
506 )
507 );
508 },
509
510 deprecated: [{
511 attributes: {
512 planName: { type: "string", default: "Professional" },
513 planDescription: { type: "string", default: "Perfect for growing teams and projects" },
514 currency: { type: "string", default: "$" },
515 currencyPosition: { type: "string", default: "before" },
516 price: { type: "string", default: "49" },
517 pricePeriod: { type: "string", default: "/month" },
518 priceSubtext: { type: "string", default: "Billed annually" },
519 features: { type: "array", default: [
520 { text: "Unlimited projects", included: true, icon: "dashicons-yes-alt" },
521 { text: "Advanced analytics", included: true, icon: "dashicons-yes-alt" },
522 { text: "Priority support", included: true, icon: "dashicons-yes-alt" },
523 { text: "Custom integrations", included: true, icon: "dashicons-yes-alt" },
524 { text: "White label exports", included: false, icon: "dashicons-no-alt" },
525 { text: "Dedicated manager", included: false, icon: "dashicons-no-alt" }
526 ]},
527 buttonText: { type: "string", default: "Get Started" },
528 buttonUrl: { type: "string", default: "#" },
529 buttonTarget: { type: "boolean", default: false },
530 isPopular: { type: "boolean", default: true },
531 popularLabel: { type: "string", default: "Most Popular" },
532 cardStyle: { type: "string", default: "shadow" },
533 layout: { type: "string", default: "vertical" },
534 iconStyle: { type: "string", default: "dashicons" },
535 showDescription: { type: "boolean", default: true },
536 showPriceSubtext: { type: "boolean", default: true },
537 showFeatureDivider: { type: "boolean", default: true },
538 featureListStyle: { type: "string", default: "icon" },
539 accentColor: { type: "string", default: "#2563eb" },
540 accentColorSecondary: { type: "string", default: "#1e40af" },
541 cardBg: { type: "string", default: "#ffffff" },
542 cardBorderColor: { type: "string", default: "#e2e8f0" },
543 cardBorderWidth: { type: "number", default: 2 },
544 cardBorderRadius: { type: "number", default: 16 },
545 cardPaddingTop: { type: "number", default: 36 },
546 cardPaddingRight: { type: "number", default: 32 },
547 cardPaddingBottom: { type: "number", default: 36 },
548 cardPaddingLeft: { type: "number", default: 32 },
549 planNameSize: { type: "number", default: 20 },
550 planNameWeight: { type: "string", default: "700" },
551 planNameColor: { type: "string", default: "#0f172a" },
552 descriptionSize: { type: "number", default: 14 },
553 descriptionColor: { type: "string", default: "#64748b" },
554 priceSize: { type: "number", default: 52 },
555 priceColor: { type: "string", default: "#0f172a" },
556 currencySize: { type: "number", default: 24 },
557 periodSize: { type: "number", default: 16 },
558 periodColor: { type: "string", default: "#64748b" },
559 priceSubtextSize: { type: "number", default: 13 },
560 priceSubtextColor: { type: "string", default: "#94a3b8" },
561 featureSize: { type: "number", default: 15 },
562 featureColor: { type: "string", default: "#334155" },
563 featureExcludedColor: { type: "string", default: "#94a3b8" },
564 featureIncludedIconColor: { type: "string", default: "#22c55e" },
565 featureExcludedIconColor: { type: "string", default: "#cbd5e1" },
566 featureGap: { type: "number", default: 12 },
567 btnBg: { type: "string", default: "#2563eb" },
568 btnColor: { type: "string", default: "#ffffff" },
569 btnBgHover: { type: "string", default: "#1d4ed8" },
570 btnColorHover: { type: "string", default: "#ffffff" },
571 btnBorderColor: { type: "string", default: "#2563eb" },
572 btnBorderWidth: { type: "number", default: 2 },
573 btnBorderRadius: { type: "number", default: 8 },
574 btnFontSize: { type: "number", default: 16 },
575 btnFontWeight: { type: "string", default: "600" },
576 btnPaddingV: { type: "number", default: 14 },
577 btnWidth: { type: "string", default: "full" },
578 badgeBg: { type: "string", default: "#2563eb" },
579 badgeColor: { type: "string", default: "#ffffff" },
580 badgeSize: { type: "number", default: 12 },
581 badgeBorderRadius: { type: "number", default: 50 },
582 headerBg: { type: "string", default: "transparent" },
583 headerStyle: { type: "string", default: "default" },
584 sectionGap: { type: "number", default: 24 }
585 },
586 save: function (props) {
587 var a = props.attributes;
588 function oldBuildWrapStyle(a) {
589 var shadow = a.cardStyle === 'shadow' ? '0 8px 32px rgba(0,0,0,0.10)' :
590 a.cardStyle === 'shadow-lg' ? '0 20px 60px rgba(0,0,0,0.16)' :
591 a.cardStyle === 'flat' ? 'none' : 'none';
592 return {
593 '--bkbg-pt-accent': a.accentColor,
594 '--bkbg-pt-accent2': a.accentColorSecondary,
595 '--bkbg-pt-card-bg': a.cardBg,
596 '--bkbg-pt-card-border-color': a.cardBorderColor,
597 '--bkbg-pt-card-border-w': a.cardBorderWidth + 'px',
598 '--bkbg-pt-card-radius': a.cardBorderRadius + 'px',
599 '--bkbg-pt-card-pad': a.cardPaddingTop + 'px ' + a.cardPaddingRight + 'px ' + a.cardPaddingBottom + 'px ' + a.cardPaddingLeft + 'px',
600 '--bkbg-pt-card-shadow': shadow,
601 '--bkbg-pt-plan-name-size': a.planNameSize + 'px',
602 '--bkbg-pt-plan-name-weight': a.planNameWeight,
603 '--bkbg-pt-plan-name-color': a.planNameColor,
604 '--bkbg-pt-desc-size': a.descriptionSize + 'px',
605 '--bkbg-pt-desc-color': a.descriptionColor,
606 '--bkbg-pt-price-size': a.priceSize + 'px',
607 '--bkbg-pt-price-color': a.priceColor,
608 '--bkbg-pt-currency-size': a.currencySize + 'px',
609 '--bkbg-pt-period-size': a.periodSize + 'px',
610 '--bkbg-pt-period-color': a.periodColor,
611 '--bkbg-pt-subtext-size': a.priceSubtextSize + 'px',
612 '--bkbg-pt-subtext-color': a.priceSubtextColor,
613 '--bkbg-pt-feature-size': a.featureSize + 'px',
614 '--bkbg-pt-feature-color': a.featureColor,
615 '--bkbg-pt-feature-excl-color': a.featureExcludedColor,
616 '--bkbg-pt-feature-incl-icon-color': a.featureIncludedIconColor,
617 '--bkbg-pt-feature-excl-icon-color': a.featureExcludedIconColor,
618 '--bkbg-pt-feature-gap': a.featureGap + 'px',
619 '--bkbg-pt-btn-bg': a.btnBg,
620 '--bkbg-pt-btn-color': a.btnColor,
621 '--bkbg-pt-btn-bg-hover': a.btnBgHover,
622 '--bkbg-pt-btn-color-hover': a.btnColorHover,
623 '--bkbg-pt-btn-border-color': a.btnBorderColor,
624 '--bkbg-pt-btn-border-w': a.btnBorderWidth + 'px',
625 '--bkbg-pt-btn-radius': a.btnBorderRadius + 'px',
626 '--bkbg-pt-btn-font-size': a.btnFontSize + 'px',
627 '--bkbg-pt-btn-font-weight': a.btnFontWeight,
628 '--bkbg-pt-btn-pad-v': a.btnPaddingV + 'px',
629 '--bkbg-pt-badge-bg': a.badgeBg,
630 '--bkbg-pt-badge-color': a.badgeColor,
631 '--bkbg-pt-badge-size': a.badgeSize + 'px',
632 '--bkbg-pt-badge-radius': a.badgeBorderRadius + 'px',
633 '--bkbg-pt-header-bg': a.headerBg,
634 '--bkbg-pt-section-gap': a.sectionGap + 'px'
635 };
636 }
637 var cardClass = 'bkbg-pt-card bkbg-pt-style-' + a.cardStyle + (a.isPopular ? ' is-popular' : '') + ' bkbg-pt-header-' + a.headerStyle;
638 function saveFeatureIcon(feat) {
639 if (a.featureListStyle === 'none') return null;
640 if (a.featureListStyle === 'bullet') return el('span', { className: 'bkbg-pt-feat-bullet', 'aria-hidden': 'true' });
641 if (a.featureListStyle === 'check') return el('span', { className: 'bkbg-pt-feat-check' + (feat.included ? ' is-included' : ' is-excluded'), 'aria-hidden': 'true' });
642 var icon = feat.included ? 'dashicons-yes-alt' : 'dashicons-no-alt';
643 return el('span', { className: 'dashicons ' + icon + ' bkbg-pt-feat-icon' + (feat.included ? ' is-included' : ' is-excluded'), 'aria-hidden': 'true' });
644 }
645 var currencyEl = el('span', { className: 'bkbg-pt-currency' }, a.currency);
646 var priceEl = el('span', { className: 'bkbg-pt-price-amount' }, a.price);
647 var periodEl = el('span', { className: 'bkbg-pt-period' }, a.pricePeriod);
648 return el('div', wp.blockEditor.useBlockProps.save({ className: cardClass, style: oldBuildWrapStyle(a) }),
649 el('div', { className: 'bkbg-pt-header' },
650 a.isPopular && el('div', { className: 'bkbg-pt-badge' }, a.popularLabel),
651 el(RichText.Content, { tagName: 'div', className: 'bkbg-pt-plan-name', value: a.planName }),
652 a.showDescription && el(RichText.Content, { tagName: 'div', className: 'bkbg-pt-description', value: a.planDescription })
653 ),
654 el('div', { className: 'bkbg-pt-pricing' },
655 el('div', { className: 'bkbg-pt-price-row' },
656 el('div', { className: 'bkbg-pt-price-main' },
657 a.currencyPosition === 'before' ? el(Fragment, {}, currencyEl, priceEl) : el(Fragment, {}, priceEl, currencyEl),
658 periodEl
659 ),
660 a.showPriceSubtext && a.priceSubtext && el('div', { className: 'bkbg-pt-subtext' }, a.priceSubtext)
661 )
662 ),
663 el('ul', { className: 'bkbg-pt-features bkbg-pt-feat-style-' + a.featureListStyle },
664 a.features.map(function (feat, i) {
665 return el('li', { key: i, className: 'bkbg-pt-feat-item' + (feat.included ? ' is-included' : ' is-excluded') },
666 saveFeatureIcon(feat),
667 el('span', { className: 'bkbg-pt-feat-text' }, feat.text)
668 );
669 })
670 ),
671 a.showFeatureDivider && el('hr', { className: 'bkbg-pt-divider' }),
672 el('div', { className: 'bkbg-pt-cta' },
673 el('a', {
674 href: a.buttonUrl || '#',
675 className: 'bkbg-pt-btn bkbg-pt-btn-' + a.btnWidth,
676 target: a.buttonTarget ? '_blank' : undefined,
677 rel: a.buttonTarget ? 'noopener noreferrer' : undefined
678 }, a.buttonText)
679 )
680 );
681 },
682 migrate: function (attrs) {
683 var n = Object.assign({}, attrs);
684 n.nameTypo = { sizeDesktop: attrs.planNameSize || 20, weight: attrs.planNameWeight || '700' };
685 n.descTypo = { sizeDesktop: attrs.descriptionSize || 14 };
686 n.priceTypo = { sizeDesktop: attrs.priceSize || 52 };
687 n.featureTypo = { sizeDesktop: attrs.featureSize || 15 };
688 n.btnTypo = { sizeDesktop: attrs.btnFontSize || 16, weight: attrs.btnFontWeight || '600' };
689 delete n.planNameSize; delete n.planNameWeight; delete n.descriptionSize;
690 delete n.priceSize; delete n.featureSize; delete n.btnFontSize; delete n.btnFontWeight;
691 return n;
692 }
693 }]
694 });
695 }() );
696