PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.14
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.14
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 / verdict-box / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.14, at blocks/verdict-box/index.js

383 lines 24.4 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 __ = wp.i18n.__;
5 var registerBlockType = wp.blocks.registerBlockType;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var useBlockProps = wp.blockEditor.useBlockProps;
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 // Resolve the shared components lazily without defining globals for each block.
17 function _tc(label, key, attrs, setA) {
18 var Control = window.bkbgTypographyControl;
19 return Control ? el(Control, {
20 label: label,
21 value: attrs[key] || {},
22 onChange: function (value) { var update = {}; update[key] = value; setA(update); }
23 }) : null;
24 }
25 function _tvf(vars, key, attrs, prefix) {
26 var cssVars = window.bkbgTypoCssVars;
27 if (cssVars) Object.assign(vars, cssVars(attrs[key] || {}, prefix));
28 return vars;
29 }
30 function getTypoControl(label, key, attrs, setA) { return _tc(label, key, attrs, setA); }
31 function getTypoCssVars(attrs) {
32 var v = {};
33 _tvf(v, 'nameTypo', attrs, '--bkvb-nm-');
34 _tvf(v, 'bodyTypo', attrs, '--bkvb-bd-');
35 _tvf(v, 'taglineTypo', attrs, '--bkvb-tl-');
36 _tvf(v, 'scoreTypo', attrs, '--bkvb-sc-');
37 _tvf(v, 'prosConsLabelTypo', attrs, '--bkvb-pl-');
38 _tvf(v, 'ctaTypo', attrs, '--bkvb-ct-');
39 return v;
40 }
41
42 var BADGE_OPTIONS = [
43 { label: '⭐ Recommended', value: 'recommended' },
44 { label: '💰 Best Value', value: 'best-value' },
45 { label: '🏆 Top Pick', value: 'top-pick' },
46 { label: '�
47 Award Winner',value: 'award-winner' },
48 { label: '👎 Skip It', value: 'skip' },
49 { label: '(None)', value: 'none' }
50 ];
51
52 function badgeLabel(badge) {
53 if (badge === 'recommended') return '⭐ Recommended';
54 if (badge === 'best-value') return '💰 Best Value';
55 if (badge === 'top-pick') return '🏆 Top Pick';
56 if (badge === 'award-winner') return '�
57 Award Winner';
58 if (badge === 'skip') return '👎 Skip It';
59 return '';
60 }
61
62 function badgeColors(badge) {
63 if (badge === 'skip') return { bg: '#fee2e2', color: '#991b1b' };
64 if (badge === 'best-value') return { bg: '#dcfce7', color: '#14532d' };
65 if (badge === 'top-pick') return { bg: '#eff6ff', color: '#1e40af' };
66 if (badge === 'award-winner') return { bg: '#fef9c3', color: '#713f12' };
67 return { bg: '#fbbf24', color: '#451a03' }; /* recommended / default */
68 }
69
70 /* ── ES5 update helpers ──────────────────────────── */
71 function updateList(list, idx, val) {
72 return list.map(function (item, i) { return i === idx ? val : item; });
73 }
74 function removeItem(list, idx) { return list.filter(function (_, i) { return i !== idx; }); }
75 function addItem(list) { return list.concat(['New item']); }
76
77 /* score fill percentage for progress-bar style */
78 function scoreFill(score, max) { return Math.min(100, Math.max(0, (score / max) * 100)); }
79
80 registerBlockType('blockenberg/verdict-box', {
81 edit: function (props) {
82 var a = props.attributes;
83 var set = props.setAttributes;
84 var blockProps = useBlockProps((function () {
85 var s = getTypoCssVars(a);
86 return { className: 'bkbg-vb-editor', style: s };
87 })());
88
89 function renderScore() {
90 var pct = scoreFill(a.overallScore, a.scoreMax);
91 if (a.scoreDisplay === 'circle') {
92 return el('div', {
93 className: 'bkbg-vb-score-circle',
94 style: {
95 width: '80px', height: '80px', borderRadius: '50%',
96 background: a.scoreCircleBg, color: a.scoreCircleColor,
97 display: 'flex', flexDirection: 'column', alignItems: 'center',
98 justifyContent: 'center', flexShrink: 0
99 }
100 },
101 el('span', { style: { fontSize: '26px', fontWeight: 800, lineHeight: 1 } }, a.overallScore.toFixed(1)),
102 el('span', { style: { fontSize: '11px', opacity: '.8' } }, '/' + a.scoreMax)
103 );
104 }
105 if (a.scoreDisplay === 'bar') {
106 return el('div', { style: { minWidth: '120px', flexShrink: 0 } },
107 el('div', { style: { fontSize: '28px', fontWeight: 800, color: a.scoreCircleBg, lineHeight: 1 } }, a.overallScore.toFixed(1)),
108 el('div', { style: { fontSize: '11px', color: a.headerColor, opacity: '.7', marginBottom: '6px' } }, '/ ' + a.scoreMax),
109 el('div', { style: { height: '6px', borderRadius: '3px', background: 'rgba(255,255,255,.25)', overflow: 'hidden' } },
110 el('div', { style: { height: '100%', width: pct + '%', background: a.scoreCircleBg, borderRadius: '3px' } })
111 )
112 );
113 }
114 /* numeric only */
115 return el('div', { style: { flexShrink: 0 } },
116 el('span', { style: { fontSize: '36px', fontWeight: 900, color: a.scoreCircleBg, lineHeight: 1 } }, a.overallScore.toFixed(1)),
117 el('span', { style: { fontSize: '18px', color: a.headerColor, opacity: '.7' } }, '/' + a.scoreMax)
118 );
119 }
120
121 function renderPreview() {
122 var bCol = a.badge !== 'none' ? badgeColors(a.badge) : null;
123 return el('div', {
124 className: 'bkbg-vb-block',
125 style: {
126 background: a.bgColor,
127 border: '1px solid ' + a.borderColor,
128 borderRadius: a.borderRadius + 'px',
129 overflow: 'hidden', boxSizing: 'border-box'
130 }
131 },
132 /* Header */
133 el('div', {
134 className: 'bkbg-vb-header',
135 style: {
136 background: a.headerBg, color: a.headerColor,
137 padding: '20px 24px', display: 'flex',
138 alignItems: 'center', gap: '20px', flexWrap: 'wrap'
139 }
140 },
141 renderScore(),
142 el('div', { style: { flex: 1 } },
143 el('h3', { className: 'bkbg-vb-product-name', style: { color: a.headerColor } }, a.productName),
144 a.showTagline && a.productTagline && el('div', { style: { fontSize: '13px', opacity: '.75', marginBottom: '8px' } }, a.productTagline),
145 a.badge !== 'none' && bCol && el('span', {
146 style: {
147 display: 'inline-block', padding: '4px 12px', borderRadius: '100px',
148 fontSize: '12px', fontWeight: 700, background: bCol.bg, color: bCol.color
149 }
150 }, badgeLabel(a.badge))
151 ),
152 el('div', {
153 style: { textAlign: 'right', flexShrink: 0 }
154 },
155 el('div', { style: { fontSize: '11px', opacity: '.6', textTransform: 'uppercase', letterSpacing: '.08em' } }, a.scoreLabel)
156 )
157 ),
158 /* Pros & Cons */
159 el('div', {
160 className: 'bkbg-vb-proscons',
161 style: { display: 'flex', flexWrap: 'wrap', gap: a.layout === 'split' ? '0' : '0' }
162 },
163 /* Pros */
164 el('div', {
165 className: 'bkbg-vb-pros',
166 style: {
167 flex: 1, minWidth: '220px',
168 background: a.prosBg,
169 borderRight: '1px solid ' + a.borderColor,
170 padding: '18px 22px'
171 }
172 },
173 el('div', { style: { fontWeight: 700, fontSize: '14px', color: a.prosColor, marginBottom: '12px' } }, a.prosLabel),
174 el('ul', { style: { margin: 0, padding: 0, listStyle: 'none' } },
175 a.pros.map(function (pro, idx) {
176 return el('li', {
177 key: idx,
178 style: { display: 'flex', gap: '8px', marginBottom: '8px', color: a.prosColor, alignItems: 'flex-start' }
179 },
180 el('span', { style: { color: a.prosIconColor, flexShrink: 0, marginTop: '1px' } }, '✓'),
181 el('span', { style: { lineHeight: 1.5 } }, pro)
182 );
183 })
184 )
185 ),
186 /* Cons */
187 el('div', {
188 className: 'bkbg-vb-cons',
189 style: {
190 flex: 1, minWidth: '220px',
191 background: a.consBg,
192 padding: '18px 22px'
193 }
194 },
195 el('div', { style: { fontWeight: 700, fontSize: '14px', color: a.consColor, marginBottom: '12px' } }, a.consLabel),
196 el('ul', { style: { margin: 0, padding: 0, listStyle: 'none' } },
197 a.cons.map(function (con, idx) {
198 return el('li', {
199 key: idx,
200 style: { display: 'flex', gap: '8px', marginBottom: '8px', color: a.consColor, alignItems: 'flex-start' }
201 },
202 el('span', { style: { color: a.consIconColor, flexShrink: 0, marginTop: '1px' } }, '✗'),
203 el('span', { style: { lineHeight: 1.5 } }, con)
204 );
205 })
206 )
207 )
208 ),
209 /* Verdict */
210 a.showVerdict && a.verdictText && el('div', {
211 className: 'bkbg-vb-verdict',
212 style: {
213 background: a.verdictBg, borderTop: '1px solid ' + a.verdictBorderColor,
214 padding: '16px 24px', display: 'flex', gap: '12px', alignItems: 'flex-start'
215 }
216 },
217 el('span', { style: { fontSize: '18px', flexShrink: 0 } }, '💬'),
218 el('p', { style: { margin: 0, color: a.verdictColor, lineHeight: 1.65 } }, a.verdictText)
219 ),
220 /* CTAs */
221 (a.showCta || a.showSecondaryCta) && el('div', {
222 className: 'bkbg-vb-ctas',
223 style: { padding: '16px 24px', borderTop: '1px solid ' + a.borderColor, display: 'flex', gap: '12px', flexWrap: 'wrap' }
224 },
225 a.showCta && a.ctaText && el('a', {
226 href: a.ctaUrl || '#', target: '_blank',
227 className: 'bkbg-vb-cta-primary',
228 style: {
229 display: 'inline-block', padding: '12px 24px',
230 background: a.ctaBg, color: a.ctaColor,
231 borderRadius: (a.borderRadius - 4) + 'px',
232 fontWeight: 700, fontSize: '15px',
233 textDecoration: 'none'
234 }
235 }, a.ctaText),
236 a.showSecondaryCta && a.ctaSecondaryText && el('a', {
237 href: a.ctaSecondaryUrl || '#', target: '_blank',
238 className: 'bkbg-vb-cta-secondary',
239 style: {
240 display: 'inline-block', padding: '12px 24px',
241 border: '2px solid ' + a.ctaSecondaryColor,
242 color: a.ctaSecondaryColor,
243 borderRadius: (a.borderRadius - 4) + 'px',
244 fontWeight: 700, fontSize: '15px',
245 textDecoration: 'none', background: 'transparent'
246 }
247 }, a.ctaSecondaryText)
248 )
249 );
250 }
251
252 var inspector = el(InspectorControls, {},
253 /* Product Info */
254 el(PanelBody, { title: 'Product Info', initialOpen: true },
255 el(TextControl, { __nextHasNoMarginBottom: true, label: 'Product Name', value: a.productName, onChange: function (v) { set({ productName: v }); } }),
256 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Tagline', checked: a.showTagline, onChange: function (v) { set({ showTagline: v }); } }),
257 a.showTagline && el(TextControl, { __nextHasNoMarginBottom: true, label: 'Tagline', value: a.productTagline, onChange: function (v) { set({ productTagline: v }); } }),
258 el('div', { style: { marginBottom: 8, fontWeight: 600, fontSize: 12 } }, 'Score'),
259 el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Overall Score', value: a.overallScore, min: 0, max: a.scoreMax, step: 0.1, onChange: function (v) { set({ overallScore: v }); } }),
260 el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Score Max', value: a.scoreMax, min: 5, max: 100, onChange: function (v) { set({ scoreMax: v }); } }),
261 el(TextControl, { __nextHasNoMarginBottom: true, label: 'Score Label', value: a.scoreLabel, onChange: function (v) { set({ scoreLabel: v }); } }),
262 el(SelectControl, { __nextHasNoMarginBottom: true, label: 'Score Display', value: a.scoreDisplay, options: [{ label: 'Circle', value: 'circle' }, { label: 'Progress Bar', value: 'bar' }, { label: 'Numeric Only', value: 'numeric' }], onChange: function (v) { set({ scoreDisplay: v }); } }),
263 el(SelectControl, { __nextHasNoMarginBottom: true, label: 'Verdict Badge', value: a.badge, options: BADGE_OPTIONS, onChange: function (v) { set({ badge: v }); } })
264 ),
265 /* Pros */
266 el(PanelBody, { title: 'Pros (' + a.pros.length + ')', initialOpen: true },
267 el(TextControl, { __nextHasNoMarginBottom: true, label: 'Pros Label', value: a.prosLabel, onChange: function (v) { set({ prosLabel: v }); } }),
268 a.pros.map(function (pro, idx) {
269 return el('div', {
270 key: idx,
271 style: { display: 'flex', gap: 6, marginBottom: 6, alignItems: 'center' }
272 },
273 el('input', {
274 type: 'text', value: pro,
275 style: { flex: 1, fontSize: 12, padding: '5px 7px', border: '1px solid #ddd', borderRadius: 4 },
276 onChange: function (e) { set({ pros: updateList(a.pros, idx, e.target.value) }); }
277 }),
278 el(Button, { isSmall: true, isDestructive: true, onClick: function () { set({ pros: removeItem(a.pros, idx) }); } }, '✕')
279 );
280 }),
281 el(Button, { variant: 'secondary', style: { width: '100%', justifyContent: 'center', marginTop: 4 }, onClick: function () { set({ pros: addItem(a.pros) }); } }, '+ Add Pro')
282 ),
283 /* Cons */
284 el(PanelBody, { title: 'Cons (' + a.cons.length + ')', initialOpen: true },
285 el(TextControl, { __nextHasNoMarginBottom: true, label: 'Cons Label', value: a.consLabel, onChange: function (v) { set({ consLabel: v }); } }),
286 a.cons.map(function (con, idx) {
287 return el('div', {
288 key: idx,
289 style: { display: 'flex', gap: 6, marginBottom: 6, alignItems: 'center' }
290 },
291 el('input', {
292 type: 'text', value: con,
293 style: { flex: 1, fontSize: 12, padding: '5px 7px', border: '1px solid #ddd', borderRadius: 4 },
294 onChange: function (e) { set({ cons: updateList(a.cons, idx, e.target.value) }); }
295 }),
296 el(Button, { isSmall: true, isDestructive: true, onClick: function () { set({ cons: removeItem(a.cons, idx) }); } }, '✕')
297 );
298 }),
299 el(Button, { variant: 'secondary', style: { width: '100%', justifyContent: 'center', marginTop: 4 }, onClick: function () { set({ cons: addItem(a.cons) }); } }, '+ Add Con')
300 ),
301 /* Verdict & CTAs */
302 el(PanelBody, { title: 'Verdict & CTAs', initialOpen: false },
303 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Verdict Text', checked: a.showVerdict, onChange: function (v) { set({ showVerdict: v }); } }),
304 a.showVerdict && el('div', { style: { marginBottom: 8 } },
305 el('label', { style: { fontSize: 11, fontWeight: 600, display: 'block', marginBottom: 4 } }, 'Verdict Text'),
306 el('textarea', {
307 value: a.verdictText, rows: 4,
308 style: { width: '100%', fontSize: 12, padding: '5px 7px', border: '1px solid #ddd', borderRadius: 4, boxSizing: 'border-box', fontFamily: 'inherit' },
309 onChange: function (e) { set({ verdictText: e.target.value }); }
310 })
311 ),
312 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Primary CTA', checked: a.showCta, onChange: function (v) { set({ showCta: v }); } }),
313 a.showCta && el(TextControl, { __nextHasNoMarginBottom: true, label: 'CTA Text', value: a.ctaText, onChange: function (v) { set({ ctaText: v }); } }),
314 a.showCta && el(TextControl, { __nextHasNoMarginBottom: true, label: 'CTA URL', value: a.ctaUrl, onChange: function (v) { set({ ctaUrl: v }); } }),
315 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Secondary CTA', checked: a.showSecondaryCta, onChange: function (v) { set({ showSecondaryCta: v }); } }),
316 a.showSecondaryCta && el(TextControl, { __nextHasNoMarginBottom: true, label: 'Secondary CTA Text', value: a.ctaSecondaryText, onChange: function (v) { set({ ctaSecondaryText: v }); } }),
317 a.showSecondaryCta && el(TextControl, { __nextHasNoMarginBottom: true, label: 'Secondary CTA URL', value: a.ctaSecondaryUrl, onChange: function (v) { set({ ctaSecondaryUrl: v }); } })
318 ),
319 /* Display */
320 el(PanelBody, { title: 'Display', initialOpen: false },
321 el(SelectControl, { __nextHasNoMarginBottom: true, label: 'Layout', value: a.layout, options: [{ label: 'Split (side by side)', value: 'split' }, { label: 'Stacked', value: 'stacked' }], onChange: function (v) { set({ layout: v }); } }),
322 el(RangeControl, { __nextHasNoMarginBottom: true, label: 'Border Radius', value: a.borderRadius, min: 0, max: 24, onChange: function (v) { set({ borderRadius: v }); } })
323 ),
324 /* Colors */
325
326 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
327 getTypoControl(__('Product Name', 'blockenberg'), 'nameTypo', a, set),
328 getTypoControl(__('Body Text', 'blockenberg'), 'bodyTypo', a, set),
329 getTypoControl(__('Tagline', 'blockenberg'), 'taglineTypo', a, set),
330 getTypoControl(__('Score', 'blockenberg'), 'scoreTypo', a, set),
331 getTypoControl(__('Pros/Cons Label', 'blockenberg'), 'prosConsLabelTypo', a, set),
332 getTypoControl(__('CTA Button', 'blockenberg'), 'ctaTypo', a, set)
333 ),
334 el(PanelColorSettings, {
335 title: 'Header & Score Colors', initialOpen: false,
336 colorSettings: [
337 { label: 'Header Background', value: a.headerBg, onChange: function (v) { set({ headerBg: v || '#0f172a' }); } },
338 { label: 'Header Text', value: a.headerColor, onChange: function (v) { set({ headerColor: v || '#ffffff' }); } },
339 { label: 'Score Circle Background', value: a.scoreCircleBg, onChange: function (v) { set({ scoreCircleBg: v || '#6366f1' }); } },
340 { label: 'Score Circle Text', value: a.scoreCircleColor, onChange: function (v) { set({ scoreCircleColor: v || '#ffffff' }); } },
341 { label: 'Block Background', value: a.bgColor, onChange: function (v) { set({ bgColor: v || '#ffffff' }); } },
342 { label: 'Border Color', value: a.borderColor, onChange: function (v) { set({ borderColor: v || '#e2e8f0' }); } }
343 ]
344 }),
345 el(PanelColorSettings, {
346 title: 'Pros & Cons Colors', initialOpen: false,
347 colorSettings: [
348 { label: 'Pros Background', value: a.prosBg, onChange: function (v) { set({ prosBg: v || '#f0fdf4' }); } },
349 { label: 'Pros Text Color', value: a.prosColor, onChange: function (v) { set({ prosColor: v || '#14532d' }); } },
350 { label: 'Pros Icon Color', value: a.prosIconColor, onChange: function (v) { set({ prosIconColor: v || '#22c55e' }); } },
351 { label: 'Cons Background', value: a.consBg, onChange: function (v) { set({ consBg: v || '#fef2f2' }); } },
352 { label: 'Cons Text Color', value: a.consColor, onChange: function (v) { set({ consColor: v || '#7f1d1d' }); } },
353 { label: 'Cons Icon Color', value: a.consIconColor, onChange: function (v) { set({ consIconColor: v || '#ef4444' }); } }
354 ]
355 }),
356 el(PanelColorSettings, {
357 title: 'Verdict & CTA Colors', initialOpen: false,
358 colorSettings: [
359 { label: 'Verdict Background', value: a.verdictBg, onChange: function (v) { set({ verdictBg: v || '#f8fafc' }); } },
360 { label: 'Verdict Text Color', value: a.verdictColor, onChange: function (v) { set({ verdictColor: v || '#374151' }); } },
361 { label: 'CTA Background', value: a.ctaBg, onChange: function (v) { set({ ctaBg: v || '#6366f1' }); } },
362 { label: 'CTA Text Color', value: a.ctaColor, onChange: function (v) { set({ ctaColor: v || '#ffffff' }); } },
363 { label: 'Secondary CTA Color', value: a.ctaSecondaryColor, onChange: function (v) { set({ ctaSecondaryColor: v || '#6366f1' }); } }
364 ]
365 })
366 );
367
368 return el(Fragment, {}, inspector, el('div', blockProps, renderPreview()));
369 },
370
371 save: function (props) {
372 var a = props.attributes;
373 var blockProps = wp.blockEditor.useBlockProps.save((function () { var _tv = getTypoCssVars(a); return { style: _tv }; })());
374 return el('div', blockProps,
375 el('div', {
376 className: 'bkbg-verdict-box-app',
377 'data-opts': JSON.stringify(props.attributes)
378 })
379 );
380 }
381 });
382 }() );
383