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 / review-box / index.js

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

477 lines 28.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 var el = window.wp.element.createElement;
3 var __ = function (s) { return s; };
4 var registerBlockType = window.wp.blocks.registerBlockType;
5 var InspectorControls = window.wp.blockEditor.InspectorControls;
6 var MediaUpload = window.wp.blockEditor.MediaUpload;
7 var MediaUploadCheck = window.wp.blockEditor.MediaUploadCheck;
8 var PanelBody = window.wp.components.PanelBody;
9 var ToggleControl = window.wp.components.ToggleControl;
10 var SelectControl = window.wp.components.SelectControl;
11 var RangeControl = window.wp.components.RangeControl;
12 var TextControl = window.wp.components.TextControl;
13 var TextareaControl = window.wp.components.TextareaControl;
14 var Button = window.wp.components.Button;
15 var PanelColorSettings = window.wp.blockEditor.PanelColorSettings;
16 var Fragment = window.wp.element.Fragment;
17 var useBlockProps = window.wp.blockEditor.useBlockProps;
18
19 var _tc, _tv;
20 function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
21 function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
22
23 function genId() { return 'r' + Math.random().toString(36).slice(2,8); }
24
25 function renderStars(score, max, color) {
26 var stars = [];
27 for (var i = 1; i <= max; i++) {
28 var pct = Math.min(1, Math.max(0, score - (i-1))) * 100;
29 stars.push(
30 el('span', { key: i, style: { position:'relative', display:'inline-block', fontSize: 20, lineHeight:1 } },
31 el('span', { style: { color: '#d1d5db' } }, '�
32 '),
33 el('span', { style: { position:'absolute', left:0, top:0, overflow:'hidden', width: pct+'%', color: color } }, '�
34 ')
35 )
36 );
37 }
38 return el('div', { style: { display:'flex', gap: 2 } }, stars);
39 }
40
41 registerBlockType('blockenberg/review-box', {
42 title: __('Review Box'),
43 description: __('Professional review card with score, pros/cons, and Schema.org markup.'),
44 category: 'bkbg-blog',
45 icon: el('svg', { viewBox: '0 0 24 24', fill: 'currentColor', width: 24, height: 24 },
46 el('path', { d: 'M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z' })
47 ),
48
49 edit: function (props) {
50 var a = props.attributes;
51 var setA = props.setAttributes;
52
53 function updateList(list, key, id, val) {
54 setA({ [key]: list.map(function (it) { return it.id === id ? Object.assign({}, it, { text: val }) : it; }) });
55 }
56 function removeFromList(list, key, id) {
57 setA({ [key]: list.filter(function (it) { return it.id !== id; }) });
58 }
59 function addToList(list, key, placeholder) {
60 setA({ [key]: list.concat([{ id: genId(), text: placeholder }]) });
61 }
62
63 var inspector = el(InspectorControls, null,
64 el(PanelBody, { title: __('Product Details'), initialOpen: true },
65 el(TextControl, { label: __('Product Name'), value: a.productName, onChange: function (v) { setA({ productName: v }); } }),
66 el(TextControl, { label: __('Review Title'), value: a.reviewTitle, onChange: function (v) { setA({ reviewTitle: v }); } }),
67 el(TextareaControl, { label: __('Summary / Verdict'), value: a.summary, rows: 3, onChange: function (v) { setA({ summary: v }); } }),
68 el(TextControl, { label: __('Price'), value: a.price, onChange: function (v) { setA({ price: v }); } }),
69 el(TextControl, { label: __('Price Label'), value: a.priceLabel, onChange: function (v) { setA({ priceLabel: v }); } })
70 ),
71 el(PanelBody, { title: __('Score'), initialOpen: false },
72 el(RangeControl, { label: __('Score'), value: a.score, min: 0, max: a.maxScore, step: 0.1, onChange: function (v) { setA({ score: v }); } }),
73 el(RangeControl, { label: __('Max Score'), value: a.maxScore, min: 5, max: 10, step: 1, onChange: function (v) { setA({ maxScore: v }); } }),
74 el(TextControl, { label: __('Score Label'), value: a.scoreLabel, onChange: function (v) { setA({ scoreLabel: v }); } })
75 ),
76 el(PanelBody, { title: __('Button'), initialOpen: false },
77 el(TextControl, { label: __('Button Label'), value: a.buttonLabel, onChange: function (v) { setA({ buttonLabel: v }); } }),
78 el(TextControl, { label: __('Button URL'), value: a.buttonUrl, onChange: function (v) { setA({ buttonUrl: v }); } }),
79 el(SelectControl, {
80 label: __('Button Style'), value: a.buttonStyle,
81 options: [
82 { label: 'Primary', value: 'primary' },
83 { label: 'Outline', value: 'outline' },
84 { label: 'Ghost', value: 'ghost' },
85 ],
86 onChange: function (v) { setA({ buttonStyle: v }); },
87 })
88 ),
89 el(PanelBody, { title: __('Image'), initialOpen: false },
90 el(MediaUploadCheck, null,
91 el(MediaUpload, {
92 onSelect: function (m) { setA({ imageUrl: m.url, imageId: m.id }); },
93 allowedTypes: ['image'],
94 value: a.imageId,
95 render: function (ref) {
96 return el('div', null,
97 a.imageUrl && el('img', { src: a.imageUrl, style: { width: '100%', borderRadius: 6, marginBottom: 8 } }),
98 el(Button, { onClick: ref.open, variant: a.imageId ? 'secondary' : 'primary', style: { marginBottom: 6 } },
99 a.imageId ? __('Replace Image') : __('Select Image')),
100 a.imageId && el(Button, { onClick: function () { setA({ imageUrl: '', imageId: 0 }); }, variant: 'link', isDestructive: true }, __('Remove Image'))
101 );
102 }
103 })
104 )
105 ),
106 el(PanelBody, { title: __('Typography'), initialOpen: false },
107 (function () { var TC = getTypoControl(); return TC ? [
108 el(TC, { key: 'tt', label: __('Product Name'), value: a.titleTypo, onChange: function (v) { setA({ titleTypo: v }); } }),
109 el(TC, { key: 'bt', label: __('Body Text'), value: a.bodyTypo, onChange: function (v) { setA({ bodyTypo: v }); } }),
110 ] : null; })()
111 ),
112 el(PanelBody, { title: __('Sizing'), initialOpen: false },
113 el(RangeControl, { label: __('Score Badge Size'), value: a.scoreSize, min: 32, max: 80, onChange: function (v) { setA({ scoreSize: v }); } }),
114 el(RangeControl, { label: __('Score Label Size (px)'), value: a.scoreLabelSize, min: 8, max: 18, __nextHasNoMarginBottom: true, onChange: function (v) { setA({ scoreLabelSize: v }); } }),
115 el(RangeControl, { label: __('Price Size (px)'), value: a.priceSize, min: 10, max: 32, __nextHasNoMarginBottom: true, onChange: function (v) { setA({ priceSize: v }); } }),
116 el(RangeControl, { label: __('Price Label Size (px)'), value: a.priceLabelSize, min: 10, max: 24, __nextHasNoMarginBottom: true, onChange: function (v) { setA({ priceLabelSize: v }); } })
117 ),
118 el(PanelBody, { title: __('Schema & Style'), initialOpen: false },
119 el(ToggleControl, {
120 label: __('Enable Schema.org markup'), checked: a.schemaEnabled,
121 onChange: function (v) { setA({ schemaEnabled: v }); },
122 __nextHasNoMarginBottom: true,
123 }),
124 a.schemaEnabled && el(SelectControl, {
125 label: __('Schema Type'), value: a.schemaType,
126 options: [
127 { label: 'Product', value: 'Product' },
128 { label: 'Software Application', value: 'SoftwareApplication' },
129 { label: 'Book', value: 'Book' },
130 { label: 'Local Business', value: 'LocalBusiness' },
131 ],
132 onChange: function (v) { setA({ schemaType: v }); },
133 }),
134 el(SelectControl, {
135 label: __('Skin'), value: a.skin,
136 options: [
137 { label: 'Bordered', value: 'bordered' },
138 { label: 'Shadow', value: 'shadow' },
139 { label: 'Gradient', value: 'gradient' },
140 { label: 'Flat', value: 'flat' },
141 ],
142 onChange: function (v) { setA({ skin: v }); },
143 }),
144 el(RangeControl, { label: __('Border Radius'), value: a.borderRadius, min: 0, max: 30, onChange: function (v) { setA({ borderRadius: v }); } }),
145 el(PanelColorSettings, {
146 title: __('Colors'), initialOpen: false,
147 colorSettings: [
148 { label: __('Card BG'), value: a.bgColor, onChange: function (v) { setA({ bgColor: v || '#ffffff' }); } },
149 { label: __('Header BG'), value: a.headerBg, onChange: function (v) { setA({ headerBg: v || '#f9fafb' }); } },
150 { label: __('Border'), value: a.borderColor, onChange: function (v) { setA({ borderColor: v || '#e5e7eb' }); } },
151 { label: __('Star Color'), value: a.starColor, onChange: function (v) { setA({ starColor: v || '#f59e0b' }); } },
152 { label: __('Pro Color'), value: a.proColor, onChange: function (v) { setA({ proColor: v || '#10b981' }); } },
153 { label: __('Con Color'), value: a.conColor, onChange: function (v) { setA({ conColor: v || '#ef4444' }); } },
154 { label: __('Score Badge BG'), value: a.scoreBg, onChange: function (v) { setA({ scoreBg: v || '#2563eb' }); } },
155 { label: __('Score Text'), value: a.scoreColor, onChange: function (v) { setA({ scoreColor: v || '#ffffff' }); } },
156 ],
157 })
158 )
159 );
160
161 /* Pros/Cons edit */
162 var prosEdit = el(PanelBody, { title: __('Pros'), initialOpen: true },
163 a.pros.map(function (p) {
164 return el('div', { key: p.id, style: { display:'flex', gap:6, marginBottom:6 } },
165 el(TextControl, { value: p.text, onChange: function (v) { updateList(a.pros, 'pros', p.id, v); }, style: { flex: 1 } }),
166 el(Button, { onClick: function () { removeFromList(a.pros, 'pros', p.id); }, icon: 'trash', isDestructive: true, label: 'Remove' })
167 );
168 }),
169 el(Button, { variant: 'secondary', onClick: function () { addToList(a.pros, 'pros', 'New pro point'); } }, '+ Add Pro')
170 );
171 var consEdit = el(PanelBody, { title: __('Cons'), initialOpen: true },
172 a.cons.map(function (c) {
173 return el('div', { key: c.id, style: { display:'flex', gap:6, marginBottom:6 } },
174 el(TextControl, { value: c.text, onChange: function (v) { updateList(a.cons, 'cons', c.id, v); } }),
175 el(Button, { onClick: function () { removeFromList(a.cons, 'cons', c.id); }, icon: 'trash', isDestructive: true, label: 'Remove' })
176 );
177 }),
178 el(Button, { variant: 'secondary', onClick: function () { addToList(a.cons, 'cons', 'New con point'); } }, '+ Add Con')
179 );
180
181 /* ── Editor preview ── */
182 var skinBorder = a.skin === 'bordered' ? '1px solid ' + a.borderColor : 'none';
183 var skinShadow = a.skin === 'shadow' ? '0 8px 24px rgba(0,0,0,0.12)' : 'none';
184
185 var pct = (a.score / a.maxScore) * 100;
186
187 var blockProps = useBlockProps((function () {
188 var _tvFn = getTypoCssVars();
189 var s = {
190 background: a.bgColor,
191 border: skinBorder,
192 boxShadow: skinShadow,
193 borderRadius: a.borderRadius + 'px',
194 overflow: 'hidden',
195 };
196 if (_tvFn) {
197 Object.assign(s, _tvFn(a.titleTypo || {}, '--bkrvb-tt-'));
198 Object.assign(s, _tvFn(a.bodyTypo || {}, '--bkrvb-bt-'));
199 }
200 return { className: 'bkbg-rvb-wrap bkbg-rvb-skin--' + a.skin, style: s };
201 })());
202
203 var preview = el('div', blockProps,
204 /* Header */
205 el('div', { style: { background: a.headerBg, padding: '20px 24px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: '1px solid ' + a.borderColor } },
206 el('div', null,
207 el('div', { style: { fontSize:11, fontWeight:600, textTransform:'uppercase', letterSpacing:'0.08em', color:'#6b7280', marginBottom:4 } }, a.reviewTitle),
208 el('div', { className: 'bkbg-rvb-product-name' }, a.productName)
209 ),
210 el('div', { style: { textAlign:'center' } },
211 el('div', { style: { background: a.scoreBg, color: a.scoreColor, borderRadius: 10, padding: '8px 16px', fontSize: a.scoreSize * 0.6, fontWeight: 800 } },
212 a.score.toFixed(1)
213 ),
214 el('div', { style: { fontSize: (a.scoreLabelSize || 10), color:'#9ca3af', marginTop:4 } }, a.scoreLabel)
215 )
216 ),
217 /* Stars + bar */
218 el('div', { style: { padding: '16px 24px', borderBottom: '1px solid ' + a.borderColor } },
219 renderStars(a.score, a.maxScore, a.starColor),
220 el('div', { style: { marginTop:8, background:'#e5e7eb', borderRadius:99, height:8, overflow:'hidden' } },
221 el('div', { style: { width: pct+'%', height:'100%', background: a.scoreBg, borderRadius:'inherit' } })
222 )
223 ),
224 /* Image + summary */
225 el('div', { style: { padding: '16px 24px', display:'flex', gap:16, borderBottom: '1px solid ' + a.borderColor } },
226 a.imageUrl && el('img', { src: a.imageUrl, style: { width:100, height:100, objectFit:'cover', borderRadius:8, flexShrink:0 } }),
227 el('div', { className: 'bkbg-rvb-summary' },
228 a.summary && el('p', { style: { margin:'0 0 8px', color:'#374151' } }, a.summary),
229 a.price && el('div', { className: 'bkbg-rvb-price', style: { color:'#111827' } }, a.priceLabel + ': ' + a.price)
230 )
231 ),
232 /* Pros & Cons */
233 el('div', { style: { padding:'16px 24px', display:'grid', gridTemplateColumns:'1fr 1fr', gap:16, borderBottom: '1px solid ' + a.borderColor } },
234 el('div', null,
235 el('div', { style: { fontWeight:700, fontSize:13, color: a.proColor, marginBottom:8 } }, '✓ Pros'),
236 a.pros.map(function (p) { return el('div', { key:p.id, style:{fontSize:13, color:'#374151', marginBottom:4, display:'flex', gap:6 } }, el('span',{style:{color:a.proColor}},''), p.text); })
237 ),
238 el('div', null,
239 el('div', { style: { fontWeight:700, fontSize:13, color: a.conColor, marginBottom:8 } }, '✗ Cons'),
240 a.cons.map(function (c) { return el('div', { key:c.id, style:{fontSize:13, color:'#374151', marginBottom:4, display:'flex', gap:6 } }, el('span',{style:{color:a.conColor}},''), c.text); })
241 )
242 ),
243 /* CTA */
244 a.buttonLabel && a.buttonUrl && el('div', { style: { padding:'16px 24px' } },
245 el('a', {
246 href: a.buttonUrl,
247 style: {
248 display:'inline-flex', alignItems:'center', gap:6,
249 padding: '10px 22px', borderRadius:8,
250 background: a.buttonStyle === 'primary' ? a.scoreBg : 'transparent',
251 color: a.buttonStyle === 'primary' ? '#ffffff' : a.scoreBg,
252 border: '2px solid ' + a.scoreBg,
253 fontWeight:700, fontSize:14, textDecoration:'none',
254 }
255 }, a.buttonLabel, '')
256 )
257 );
258
259 return el(Fragment, null,
260 el(InspectorControls, null, prosEdit, consEdit, inspector.props.children),
261 preview
262 );
263 },
264
265 save: function (props) {
266 var a = props.attributes;
267 var pct = (a.score / a.maxScore) * 100;
268
269 function starHTML(score, max, color) {
270 var html = '';
271 for (var i = 1; i <= max; i++) {
272 var p = Math.min(100, Math.max(0, (score - (i-1))) * 100);
273 html += '<span class="bkbg-rvb-star" style="--pct:' + p + '%;--color:' + color + '">�
274 </span>';
275 }
276 return html;
277 }
278
279 var savStyle = {
280 '--bkbg-rvb-bg': a.bgColor,
281 '--bkbg-rvb-hbg': a.headerBg,
282 '--bkbg-rvb-border': a.borderColor,
283 '--bkbg-rvb-radius': a.borderRadius + 'px',
284 '--bkbg-rvb-star': a.starColor,
285 '--bkbg-rvb-pro': a.proColor,
286 '--bkbg-rvb-con': a.conColor,
287 '--bkbg-rvb-score-bg': a.scoreBg,
288 '--bkbg-rvb-score-c': a.scoreColor,
289 };
290 var _tvFn = getTypoCssVars();
291 if (_tvFn) {
292 Object.assign(savStyle, _tvFn(a.titleTypo || {}, '--bkrvb-tt-'));
293 Object.assign(savStyle, _tvFn(a.bodyTypo || {}, '--bkrvb-bt-'));
294 }
295
296 return el('div', {
297 className: 'bkbg-rvb-wrap bkbg-rvb-skin--' + a.skin,
298 style: savStyle,
299 'data-schema': a.schemaEnabled ? '1' : '0',
300 'data-schema-type': a.schemaType,
301 'data-name': a.productName,
302 'data-score': a.score,
303 'data-max-score': a.maxScore,
304 'data-price': a.price,
305 },
306 /* Header */
307 el('div', { className: 'bkbg-rvb-header' },
308 el('div', { className: 'bkbg-rvb-header-text' },
309 el('div', { className: 'bkbg-rvb-pretitle' }, a.reviewTitle),
310 el('div', { className: 'bkbg-rvb-product-name' }, a.productName)
311 ),
312 el('div', { className: 'bkbg-rvb-score-badge' },
313 el('div', { className: 'bkbg-rvb-score-num', style: { fontSize: a.scoreSize * 0.6 + 'px' } }, a.score.toFixed(1)),
314 el('div', { className: 'bkbg-rvb-score-label', style: { fontSize: (a.scoreLabelSize || 10) + 'px' } }, a.scoreLabel)
315 )
316 ),
317 /* Stars */
318 el('div', { className: 'bkbg-rvb-stars-row' },
319 el('div', { className: 'bkbg-rvb-stars', dangerouslySetInnerHTML: { __html: starHTML(a.score, a.maxScore, a.starColor) } }),
320 el('div', { className: 'bkbg-rvb-bar-wrap' },
321 el('div', { className: 'bkbg-rvb-bar', style: { width: pct + '%' } })
322 )
323 ),
324 /* Image + summary */
325 el('div', { className: 'bkbg-rvb-body' },
326 a.imageUrl && el('img', { className: 'bkbg-rvb-thumb', src: a.imageUrl, alt: a.productName, loading: 'lazy' }),
327 el('div', { className: 'bkbg-rvb-summary' },
328 a.summary && el('p', null, a.summary),
329 a.price && el('div', { className: 'bkbg-rvb-price' }, a.priceLabel + ': ' + a.price)
330 )
331 ),
332 /* Pros & Cons */
333 el('div', { className: 'bkbg-rvb-pros-cons' },
334 el('div', { className: 'bkbg-rvb-pros' },
335 el('div', { className: 'bkbg-rvb-pros-title' }, '✓ Pros'),
336 el('ul', null,
337 a.pros.map(function (p) { return el('li', { key: p.id }, p.text); })
338 )
339 ),
340 el('div', { className: 'bkbg-rvb-cons' },
341 el('div', { className: 'bkbg-rvb-cons-title' }, '✗ Cons'),
342 el('ul', null,
343 a.cons.map(function (c) { return el('li', { key: c.id }, c.text); })
344 )
345 )
346 ),
347 /* CTA */
348 a.buttonLabel && a.buttonUrl && el('div', { className: 'bkbg-rvb-cta' },
349 el('a', {
350 href: a.buttonUrl,
351 className: 'bkbg-rvb-btn bkbg-rvb-btn--' + a.buttonStyle,
352 target: '_blank',
353 rel: 'noopener noreferrer nofollow',
354 }, a.buttonLabel + '')
355 )
356 );
357 },
358
359 deprecated: [{
360 attributes: {
361 productName: { type: 'string', default: 'Product Name' },
362 reviewTitle: { type: 'string', default: 'Our Verdict' },
363 summary: { type: 'string', default: '' },
364 score: { type: 'number', default: 4.5 },
365 maxScore: { type: 'number', default: 5 },
366 scoreLabel: { type: 'string', default: 'Overall Score' },
367 pros: { type: 'array', default: [{ id: 'pro-1', text: 'Excellent build quality' }, { id: 'pro-2', text: 'Great value for money' }, { id: 'pro-3', text: 'Easy to use' }] },
368 cons: { type: 'array', default: [{ id: 'con-1', text: 'Limited color options' }, { id: 'con-2', text: 'Battery life could be better' }] },
369 imageUrl: { type: 'string', default: '' },
370 imageId: { type: 'number', default: 0 },
371 price: { type: 'string', default: '' },
372 priceLabel: { type: 'string', default: 'Price' },
373 buttonLabel: { type: 'string', default: 'Buy Now' },
374 buttonUrl: { type: 'string', default: '' },
375 buttonStyle: { type: 'string', default: 'primary' },
376 schemaType: { type: 'string', default: 'Product' },
377 schemaEnabled: { type: 'boolean', default: true },
378 skin: { type: 'string', default: 'bordered' },
379 starColor: { type: 'string', default: '#f59e0b' },
380 proColor: { type: 'string', default: '#10b981' },
381 conColor: { type: 'string', default: '#ef4444' },
382 headerBg: { type: 'string', default: '#f9fafb' },
383 bgColor: { type: 'string', default: '#ffffff' },
384 borderColor: { type: 'string', default: '#e5e7eb' },
385 borderRadius: { type: 'number', default: 12 },
386 scoreBg: { type: 'string', default: '#2563eb' },
387 scoreColor: { type: 'string', default: '#ffffff' },
388 scoreSize: { type: 'number', default: 48 },
389 summarySize: { type: 'number', default: 14 },
390 priceSize: { type: 'number', default: 14 },
391 priceLabelSize: { type: 'number', default: 14 },
392 scoreLabelSize: { type: 'number', default: 10 },
393 productNameSize: { type: 'number', default: 22 },
394 },
395 save: function (props) {
396 var a = props.attributes;
397 var pct = (a.score / a.maxScore) * 100;
398 function starHTML(score, max, color) {
399 var html = '';
400 for (var i = 1; i <= max; i++) {
401 var p = Math.min(100, Math.max(0, (score - (i-1))) * 100);
402 html += '<span class="bkbg-rvb-star" style="--pct:' + p + '%;--color:' + color + '">�
403 </span>';
404 }
405 return html;
406 }
407 return el('div', {
408 className: 'bkbg-rvb-wrap bkbg-rvb-skin--' + a.skin,
409 style: {
410 '--bkbg-rvb-bg': a.bgColor,
411 '--bkbg-rvb-hbg': a.headerBg,
412 '--bkbg-rvb-border': a.borderColor,
413 '--bkbg-rvb-radius': a.borderRadius + 'px',
414 '--bkbg-rvb-star': a.starColor,
415 '--bkbg-rvb-pro': a.proColor,
416 '--bkbg-rvb-con': a.conColor,
417 '--bkbg-rvb-score-bg': a.scoreBg,
418 '--bkbg-rvb-score-c': a.scoreColor,
419 },
420 'data-schema': a.schemaEnabled ? '1' : '0',
421 'data-schema-type': a.schemaType,
422 'data-name': a.productName,
423 'data-score': a.score,
424 'data-max-score': a.maxScore,
425 'data-price': a.price,
426 },
427 el('div', { className: 'bkbg-rvb-header' },
428 el('div', { className: 'bkbg-rvb-header-text' },
429 el('div', { className: 'bkbg-rvb-pretitle' }, a.reviewTitle),
430 el('div', { className: 'bkbg-rvb-product-name' }, a.productName)
431 ),
432 el('div', { className: 'bkbg-rvb-score-badge' },
433 el('div', { className: 'bkbg-rvb-score-num', style: { fontSize: a.scoreSize * 0.6 + 'px' } }, a.score.toFixed(1)),
434 el('div', { className: 'bkbg-rvb-score-label', style: { fontSize: (a.scoreLabelSize || 10) + 'px' } }, a.scoreLabel)
435 )
436 ),
437 el('div', { className: 'bkbg-rvb-stars-row' },
438 el('div', { className: 'bkbg-rvb-stars', dangerouslySetInnerHTML: { __html: starHTML(a.score, a.maxScore, a.starColor) } }),
439 el('div', { className: 'bkbg-rvb-bar-wrap' },
440 el('div', { className: 'bkbg-rvb-bar', style: { width: pct + '%' } })
441 )
442 ),
443 el('div', { className: 'bkbg-rvb-body' },
444 a.imageUrl && el('img', { className: 'bkbg-rvb-thumb', src: a.imageUrl, alt: a.productName, loading: 'lazy' }),
445 el('div', { className: 'bkbg-rvb-summary' },
446 a.summary && el('p', null, a.summary),
447 a.price && el('div', { className: 'bkbg-rvb-price' }, a.priceLabel + ': ' + a.price)
448 )
449 ),
450 el('div', { className: 'bkbg-rvb-pros-cons' },
451 el('div', { className: 'bkbg-rvb-pros' },
452 el('div', { className: 'bkbg-rvb-pros-title' }, '✓ Pros'),
453 el('ul', null,
454 a.pros.map(function (p) { return el('li', { key: p.id }, p.text); })
455 )
456 ),
457 el('div', { className: 'bkbg-rvb-cons' },
458 el('div', { className: 'bkbg-rvb-cons-title' }, '✗ Cons'),
459 el('ul', null,
460 a.cons.map(function (c) { return el('li', { key: c.id }, c.text); })
461 )
462 )
463 ),
464 a.buttonLabel && a.buttonUrl && el('div', { className: 'bkbg-rvb-cta' },
465 el('a', {
466 href: a.buttonUrl,
467 className: 'bkbg-rvb-btn bkbg-rvb-btn--' + a.buttonStyle,
468 target: '_blank',
469 rel: 'noopener noreferrer nofollow',
470 }, a.buttonLabel + '')
471 )
472 );
473 }
474 }],
475 });
476 })();
477