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 / rating-summary / index.js

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

309 lines 23.9 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 PanelColorSettings = wp.blockEditor.PanelColorSettings;
8 var useBlockProps = wp.blockEditor.useBlockProps;
9 var PanelBody = wp.components.PanelBody;
10 var RangeControl = wp.components.RangeControl;
11 var ToggleControl = wp.components.ToggleControl;
12 var TextControl = wp.components.TextControl;
13 var SelectControl = wp.components.SelectControl;
14 var Button = wp.components.Button;
15 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
16 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
17
18 var LAYOUT_OPTIONS = [
19 { label: __('Horizontal (score left, bars right)', 'blockenberg'), value: 'horizontal' },
20 { label: __('Vertical (score top, bars below)', 'blockenberg'), value: 'vertical' },
21 { label: __('Compact (inline)', 'blockenberg'), value: 'compact' },
22 ];
23 var BAR_STYLE_OPTIONS = [
24 { label: __('Rounded', 'blockenberg'), value: 'rounded' },
25 { label: __('Flat', 'blockenberg'), value: 'flat' },
26 ];
27 var PLATFORM_OPTIONS = [
28 { label: 'Google', value: 'Google' },
29 { label: 'G2', value: 'G2' },
30 { label: 'Capterra', value: 'Capterra' },
31 { label: 'Trustpilot', value: 'Trustpilot' },
32 { label: 'Yelp', value: 'Yelp' },
33 { label: 'Amazon', value: 'Amazon' },
34 ];
35
36 /* ── Star renderer ─────────────────────────────────────── */
37 function renderStars(score, max, size, color) {
38 return el('div', { style: { display: 'flex', gap: '2px', alignItems: 'center' } },
39 Array.from({ length: max }).map(function (_, i) {
40 var fill = i < Math.floor(score) ? color : (i < score ? color : 'none');
41 var opacity = i < Math.floor(score) ? 1 : (i < score ? 0.5 : 1);
42 return el('svg', { key: i, width: size, height: size, viewBox: '0 0 24 24', fill: fill, stroke: color, strokeWidth: 1.5, strokeLinejoin: 'round', style: { opacity: opacity } },
43 el('path', { d: 'M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z' })
44 );
45 })
46 );
47 }
48
49 /* ── Score color helper (green/yellow/red) ─────────────── */
50 function scorePhrase(score, max) {
51 var pct = score / max;
52 if (pct >= 0.9) return 'Excellent';
53 if (pct >= 0.75) return 'Very Good';
54 if (pct >= 0.6) return 'Good';
55 if (pct >= 0.4) return 'Fair';
56 return 'Poor';
57 }
58
59 /* ── Bar renderer ──────────────────────────────────────── */
60 function BreakdownBars(props) {
61 var a = props.a;
62 var breakdowns = a.breakdowns;
63 var totalCount = breakdowns.reduce(function (s, r) { return s + (r.count || 0); }, 0) || 1;
64 var barRadius = a.barStyle === 'rounded' ? a.barRadius + 'px' : '0';
65
66 return el('div', { className: 'bkbg-rs-bars', style: { flex: 1, display: 'flex', flexDirection: 'column', gap: a.gap + 'px' } },
67 breakdowns.map(function (row, i) {
68 var pct = Math.round((row.count / totalCount) * 100);
69 return el('div', { key: i, className: 'bkbg-rs-row', style: { display: 'flex', alignItems: 'center', gap: '10px' } },
70 el('span', { className: 'bkbg-rs-bar-label', style: { color: a.labelColor, whiteSpace: 'nowrap', minWidth: '36px', textAlign: 'right' } }, row.stars + ' �
71 '),
72 el('div', { style: { flex: 1, height: a.barHeight + 'px', background: a.barTrackColor, borderRadius: barRadius, overflow: 'hidden' } },
73 el('div', { className: 'bkbg-rs-fill', style: { height: '100%', width: pct + '%', background: a.barColor, borderRadius: barRadius, transition: 'width 0.8s ease' } })
74 ),
75 el('span', { className: 'bkbg-rs-bar-count', style: { color: a.countColor, minWidth: '36px', fontVariantNumeric: 'tabular-nums' } }, pct + '%')
76 );
77 })
78 );
79 }
80
81 /* ── Score block ────────────────────────────────────────── */
82 function ScoreBlock(props) {
83 var a = props.a;
84 return el('div', { className: 'bkbg-rs-score', style: { display: 'flex', flexDirection: 'column', alignItems: 'center', flexShrink: 0, gap: '6px', minWidth: '100px' } },
85 a.showOverallScore && el('span', { className: 'bkbg-rs-score-value', style: { color: a.scoreColor } }, a.overallScore.toFixed(1)),
86 a.showStars && renderStars(a.overallScore, a.maxScore, a.starSize, a.starColor),
87 el('span', { className: 'bkbg-rs-label', style: { color: a.labelColor } }, scorePhrase(a.overallScore, a.maxScore)),
88 a.showTotalReviews && el('span', { className: 'bkbg-rs-total', style: { color: a.countColor } }, a.totalReviews.toLocaleString() + ' ' + a.totalReviewsLabel),
89 a.showPlatformBadge && el('span', { className: 'bkbg-rs-platform', style: { fontWeight: 700, background: '#f3f4f6', borderRadius: '6px', padding: '2px 10px', marginTop: '4px', color: '#374151' } }, a.platformName)
90 );
91 }
92
93 /* ── Full preview ─────────────────────────────────────── */
94 function Preview(props) {
95 var a = props.a;
96 var isHoriz = a.layout === 'horizontal';
97 return el('div', { className: 'bkbg-rating-summary bkbg-rs--' + a.layout, style: { display: 'flex', flexDirection: isHoriz ? 'row' : 'column', alignItems: isHoriz ? 'center' : 'flex-start', gap: '24px' } },
98 el(ScoreBlock, { a: a }),
99 el(BreakdownBars, { a: a })
100 );
101 }
102
103 registerBlockType('blockenberg/rating-summary', {
104 edit: function (props) {
105 var a = props.attributes;
106 var setAttributes = props.setAttributes;
107 var TC = getTypoControl();
108 var blockProps = useBlockProps((function() {
109 var _tvFn = getTypoCssVars();
110 var s = { paddingTop: a.paddingTop + 'px', paddingBottom: a.paddingBottom + 'px', backgroundColor: a.bgColor || undefined };
111 if (_tvFn) {
112 Object.assign(s, _tvFn(a.scoreTypo || {}, '--bkrs-sc-'));
113 Object.assign(s, _tvFn(a.labelTypo || {}, '--bkrs-lb-'));
114 }
115 return { style: s };
116 })());
117
118 function setBreakdown(index, key, val) {
119 var updated = a.breakdowns.map(function (b, i) { return i === index ? Object.assign({}, b, { [key]: val }) : b; });
120 setAttributes({ breakdowns: updated });
121 }
122
123 return el(Fragment, null,
124 el(InspectorControls, null,
125 el(PanelBody, { title: __('Rating Settings', 'blockenberg'), initialOpen: true },
126 el('p', { style: { margin: '0 0 8px', fontWeight: 600, fontSize: '11px', textTransform: 'uppercase', letterSpacing: '0.06em', color: '#757575' } }, __('Overall Score', 'blockenberg')),
127 el(RangeControl, { label: __('Score', 'blockenberg'), value: a.overallScore, min: 0, max: a.maxScore, step: 0.1, onChange: function (v) { setAttributes({ overallScore: v }); } }),
128 el(RangeControl, { label: __('Max score', 'blockenberg'), value: a.maxScore, min: 3, max: 10, onChange: function (v) { setAttributes({ maxScore: v }); } }),
129 el(RangeControl, { label: __('Total reviews', 'blockenberg'), value: a.totalReviews, min: 0, max: 100000, step: 1, onChange: function (v) { setAttributes({ totalReviews: v }); } }),
130 el(TextControl, { label: __('Reviews label', 'blockenberg'), value: a.totalReviewsLabel, onChange: function (v) { setAttributes({ totalReviewsLabel: v }); } }),
131 el(ToggleControl, { label: __('Show overall score number', 'blockenberg'), checked: a.showOverallScore, onChange: function (v) { setAttributes({ showOverallScore: v }); }, __nextHasNoMarginBottom: true }),
132 el(ToggleControl, { label: __('Show stars', 'blockenberg'), checked: a.showStars, onChange: function (v) { setAttributes({ showStars: v }); }, __nextHasNoMarginBottom: true }),
133 el(ToggleControl, { label: __('Show total reviews', 'blockenberg'), checked: a.showTotalReviews, onChange: function (v) { setAttributes({ showTotalReviews: v }); }, __nextHasNoMarginBottom: true }),
134 el(ToggleControl, { label: __('Show platform badge', 'blockenberg'), checked: a.showPlatformBadge, onChange: function (v) { setAttributes({ showPlatformBadge: v }); }, __nextHasNoMarginBottom: true }),
135 a.showPlatformBadge && el(SelectControl, { label: __('Platform', 'blockenberg'), value: a.platformName, options: PLATFORM_OPTIONS, onChange: function (v) { setAttributes({ platformName: v }); } })
136 ),
137 el(PanelBody, { title: __('Star Breakdown', 'blockenberg'), initialOpen: false },
138 a.breakdowns.map(function (b, i) {
139 return el('div', { key: i, style: { marginBottom: '12px', padding: '10px', background: '#f9fafb', borderRadius: '8px' } },
140 el('p', { style: { margin: '0 0 6px', fontWeight: 600, fontSize: '12px' } }, b.stars + ' �
141 '),
142 el(RangeControl, { label: __('Count', 'blockenberg'), value: b.count, min: 0, max: 9999, onChange: function (v) { setBreakdown(i, 'count', v); } })
143 );
144 })
145 ),
146 el(PanelBody, { title: __('Layout & Style', 'blockenberg'), initialOpen: false },
147 el(SelectControl, { label: __('Layout', 'blockenberg'), value: a.layout, options: LAYOUT_OPTIONS, onChange: function (v) { setAttributes({ layout: v }); } }),
148 el(SelectControl, { label: __('Bar style', 'blockenberg'), value: a.barStyle, options: BAR_STYLE_OPTIONS, onChange: function (v) { setAttributes({ barStyle: v }); } }),
149 el(RangeControl, { label: __('Bar height (px)', 'blockenberg'), value: a.barHeight, min: 4, max: 24, onChange: function (v) { setAttributes({ barHeight: v }); } }),
150 el(RangeControl, { label: __('Bar radius (px)', 'blockenberg'), value: a.barRadius, min: 0, max: 99, onChange: function (v) { setAttributes({ barRadius: v }); } }),
151 el(RangeControl, { label: __('Row gap (px)', 'blockenberg'), value: a.gap, min: 2, max: 24, onChange: function (v) { setAttributes({ gap: v }); } })
152 ),
153 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
154 TC && el(TC, { label: __('Score', 'blockenberg'), value: a.scoreTypo || {}, onChange: function(v) { setAttributes({ scoreTypo: v }); } }),
155 TC && el(TC, { label: __('Labels', 'blockenberg'), value: a.labelTypo || {}, onChange: function(v) { setAttributes({ labelTypo: v }); } }),
156 el(RangeControl, { label: __('Star size (px)', 'blockenberg'), value: a.starSize, min: 12, max: 40, onChange: function (v) { setAttributes({ starSize: v }); } })
157 ),
158 el(PanelColorSettings, {
159 title: __('Colors', 'blockenberg'), initialOpen: false,
160 colorSettings: [
161 { value: a.barColor, onChange: function (v) { setAttributes({ barColor: v || '' }); }, label: __('Bar fill', 'blockenberg') },
162 { value: a.barTrackColor,onChange: function (v) { setAttributes({ barTrackColor: v || '' }); },label: __('Bar track', 'blockenberg') },
163 { value: a.starColor, onChange: function (v) { setAttributes({ starColor: v || '' }); }, label: __('Stars', 'blockenberg') },
164 { value: a.scoreColor, onChange: function (v) { setAttributes({ scoreColor: v || '' }); }, label: __('Score number', 'blockenberg') },
165 { value: a.labelColor, onChange: function (v) { setAttributes({ labelColor: v || '' }); }, label: __('Labels', 'blockenberg') },
166 { value: a.countColor, onChange: function (v) { setAttributes({ countColor: v || '' }); }, label: __('Counts / %', 'blockenberg') },
167 { value: a.bgColor, onChange: function (v) { setAttributes({ bgColor: v || '' }); }, label: __('Section background', 'blockenberg') },
168 ]
169 }),
170 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
171 el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
172 el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
173 )
174 ),
175
176 el('div', blockProps, el(Preview, { a: a }))
177 );
178 },
179
180 save: function (props) {
181 var a = props.attributes;
182 var _tvFn = window.bkbgTypoCssVars;
183 var saveStyle = { paddingTop: a.paddingTop + 'px', paddingBottom: a.paddingBottom + 'px', backgroundColor: a.bgColor || undefined };
184 if (_tvFn) {
185 Object.assign(saveStyle, _tvFn(a.scoreTypo || {}, '--bkrs-sc-'));
186 Object.assign(saveStyle, _tvFn(a.labelTypo || {}, '--bkrs-lb-'));
187 }
188 var blockProps = wp.blockEditor.useBlockProps.save({ className: 'bkbg-rating-summary-wrap', style: saveStyle });
189 var isHoriz = a.layout === 'horizontal';
190 var totalCount = a.breakdowns.reduce(function (s, r) { return s + (r.count || 0); }, 0) || 1;
191 var barRadius = a.barStyle === 'rounded' ? a.barRadius + 'px' : '0';
192
193 function starsSVG(score, max, size, color) {
194 return el('div', { style: { display: 'flex', gap: '2px', alignItems: 'center' } },
195 Array.from({ length: max }).map(function (_, i) {
196 var fill = i < Math.floor(score) ? color : (i < score ? color : 'none');
197 var opacity = i < Math.floor(score) ? 1 : (i < score ? 0.5 : 1);
198 return el('svg', { key: i, width: size, height: size, viewBox: '0 0 24 24', fill: fill, stroke: color, strokeWidth: 1.5, strokeLinejoin: 'round', 'aria-hidden': 'true', style: { opacity: opacity } },
199 el('path', { d: 'M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z' })
200 );
201 })
202 );
203 }
204
205 return el('div', blockProps,
206 el('div', { className: 'bkbg-rating-summary bkbg-rs--' + a.layout, style: { display: 'flex', flexDirection: isHoriz ? 'row' : 'column', alignItems: isHoriz ? 'center' : 'flex-start', gap: '24px' } },
207 el('div', { className: 'bkbg-rs-score', style: { display: 'flex', flexDirection: 'column', alignItems: 'center', flexShrink: 0, gap: '6px', minWidth: '100px' } },
208 a.showOverallScore && el('span', { className: 'bkbg-rs-score-value', style: { color: a.scoreColor } }, a.overallScore.toFixed(1)),
209 a.showStars && starsSVG(a.overallScore, a.maxScore, a.starSize, a.starColor),
210 el('span', { className: 'bkbg-rs-label', style: { color: a.labelColor } }, scorePhrase(a.overallScore, a.maxScore)),
211 a.showTotalReviews && el('span', { className: 'bkbg-rs-total', style: { color: a.countColor } }, a.totalReviews.toLocaleString() + ' ' + a.totalReviewsLabel),
212 a.showPlatformBadge && el('span', { className: 'bkbg-rs-platform', style: { fontWeight: 700, background: '#f3f4f6', borderRadius: '6px', padding: '2px 10px', marginTop: '4px', color: '#374151' } }, a.platformName)
213 ),
214 el('div', { className: 'bkbg-rs-bars', style: { flex: 1, display: 'flex', flexDirection: 'column', gap: a.gap + 'px' } },
215 a.breakdowns.map(function (row, i) {
216 var pct = Math.round((row.count / totalCount) * 100);
217 return el('div', { key: i, className: 'bkbg-rs-row', style: { display: 'flex', alignItems: 'center', gap: '10px' } },
218 el('span', { className: 'bkbg-rs-bar-label', style: { color: a.labelColor, whiteSpace: 'nowrap', minWidth: '36px', textAlign: 'right' } }, row.stars + ' �
219 '),
220 el('div', { style: { flex: 1, height: a.barHeight + 'px', background: a.barTrackColor, borderRadius: barRadius, overflow: 'hidden' } },
221 el('div', { className: 'bkbg-rs-fill', 'data-pct': pct, style: { height: '100%', width: pct + '%', background: a.barColor, borderRadius: barRadius } })
222 ),
223 el('span', { className: 'bkbg-rs-bar-count', style: { color: a.countColor, minWidth: '36px', fontVariantNumeric: 'tabular-nums' } }, pct + '%')
224 );
225 })
226 )
227 )
228 );
229 },
230
231 deprecated: [{
232 attributes: {
233 "overallScore":{"type":"number","default":4.3},
234 "maxScore":{"type":"number","default":5},
235 "totalReviews":{"type":"number","default":124},
236 "showTotalReviews":{"type":"boolean","default":true},
237 "totalReviewsLabel":{"type":"string","default":"reviews"},
238 "showOverallScore":{"type":"boolean","default":true},
239 "showStars":{"type":"boolean","default":true},
240 "showPlatformBadge":{"type":"boolean","default":false},
241 "platformName":{"type":"string","default":"Google"},
242 "breakdowns":{"type":"array","default":[{"stars":5,"count":89},{"stars":4,"count":22},{"stars":3,"count":8},{"stars":2,"count":3},{"stars":1,"count":2}]},
243 "layout":{"type":"string","default":"horizontal"},
244 "barStyle":{"type":"string","default":"rounded"},
245 "textAlign":{"type":"string","default":"left"},
246 "starSize":{"type":"number","default":20},
247 "scoreSize":{"type":"number","default":52},
248 "labelSize":{"type":"number","default":13},
249 "barHeight":{"type":"number","default":8},
250 "barRadius":{"type":"number","default":99},
251 "gap":{"type":"number","default":6},
252 "barColor":{"type":"string","default":"#f59e0b"},
253 "barTrackColor":{"type":"string","default":"#e5e7eb"},
254 "starColor":{"type":"string","default":"#f59e0b"},
255 "scoreColor":{"type":"string","default":"#1e293b"},
256 "labelColor":{"type":"string","default":"#6b7280"},
257 "countColor":{"type":"string","default":"#6b7280"},
258 "bgColor":{"type":"string","default":""},
259 "paddingTop":{"type":"number","default":40},
260 "paddingBottom":{"type":"number","default":40}
261 },
262 save: function (props) {
263 var a = props.attributes;
264 var blockProps = wp.blockEditor.useBlockProps.save({ className: 'bkbg-rating-summary-wrap' });
265 var isHoriz = a.layout === 'horizontal';
266 var totalCount = a.breakdowns.reduce(function (s, r) { return s + (r.count || 0); }, 0) || 1;
267 var barRadius = a.barStyle === 'rounded' ? a.barRadius + 'px' : '0';
268
269 function starsSVG(score, max, size, color) {
270 return el('div', { style: { display: 'flex', gap: '2px', alignItems: 'center' } },
271 Array.from({ length: max }).map(function (_, i) {
272 var fill = i < Math.floor(score) ? color : (i < score ? color : 'none');
273 var opacity = i < Math.floor(score) ? 1 : (i < score ? 0.5 : 1);
274 return el('svg', { key: i, width: size, height: size, viewBox: '0 0 24 24', fill: fill, stroke: color, strokeWidth: 1.5, strokeLinejoin: 'round', 'aria-hidden': 'true', style: { opacity: opacity } },
275 el('path', { d: 'M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z' })
276 );
277 })
278 );
279 }
280
281 return el('div', Object.assign({}, blockProps, { style: { paddingTop: a.paddingTop + 'px', paddingBottom: a.paddingBottom + 'px', backgroundColor: a.bgColor || undefined } }),
282 el('div', { className: 'bkbg-rating-summary bkbg-rs--' + a.layout, style: { display: 'flex', flexDirection: isHoriz ? 'row' : 'column', alignItems: isHoriz ? 'center' : 'flex-start', gap: '24px' } },
283 el('div', { className: 'bkbg-rs-score', style: { display: 'flex', flexDirection: 'column', alignItems: 'center', flexShrink: 0, gap: '6px', minWidth: '100px' } },
284 a.showOverallScore && el('span', { style: { fontSize: a.scoreSize + 'px', fontWeight: 800, color: a.scoreColor, lineHeight: 1 } }, a.overallScore.toFixed(1)),
285 a.showStars && starsSVG(a.overallScore, a.maxScore, a.starSize, a.starColor),
286 el('span', { style: { fontSize: a.labelSize + 'px', color: a.labelColor, fontWeight: 500 } }, scorePhrase(a.overallScore, a.maxScore)),
287 a.showTotalReviews && el('span', { style: { fontSize: (a.labelSize - 1) + 'px', color: a.countColor } }, a.totalReviews.toLocaleString() + ' ' + a.totalReviewsLabel),
288 a.showPlatformBadge && el('span', { style: { fontSize: a.labelSize + 'px', fontWeight: 700, background: '#f3f4f6', borderRadius: '6px', padding: '2px 10px', marginTop: '4px', color: '#374151' } }, a.platformName)
289 ),
290 el('div', { className: 'bkbg-rs-bars', style: { flex: 1, display: 'flex', flexDirection: 'column', gap: a.gap + 'px' } },
291 a.breakdowns.map(function (row, i) {
292 var pct = Math.round((row.count / totalCount) * 100);
293 return el('div', { key: i, className: 'bkbg-rs-row', style: { display: 'flex', alignItems: 'center', gap: '10px' } },
294 el('span', { style: { fontSize: a.labelSize + 'px', color: a.labelColor, whiteSpace: 'nowrap', minWidth: '36px', textAlign: 'right', fontWeight: 500 } }, row.stars + ' �
295 '),
296 el('div', { style: { flex: 1, height: a.barHeight + 'px', background: a.barTrackColor, borderRadius: barRadius, overflow: 'hidden' } },
297 el('div', { className: 'bkbg-rs-fill', 'data-pct': pct, style: { height: '100%', width: pct + '%', background: a.barColor, borderRadius: barRadius } })
298 ),
299 el('span', { style: { fontSize: a.labelSize + 'px', color: a.countColor, minWidth: '36px', fontVariantNumeric: 'tabular-nums' } }, pct + '%')
300 );
301 })
302 )
303 )
304 );
305 }
306 }]
307 });
308 }() );
309