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

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

258 lines 14.6 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 __ = wp.i18n.__;
4 var registerBlockType = wp.blocks.registerBlockType;
5 var useBlockProps = wp.blockEditor.useBlockProps;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
8 var MediaUpload = wp.blockEditor.MediaUpload;
9 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
10 var PanelBody = wp.components.PanelBody;
11 var RangeControl = wp.components.RangeControl;
12 var ToggleControl = wp.components.ToggleControl;
13 var SelectControl = wp.components.SelectControl;
14 var TextControl = wp.components.TextControl;
15 var TextareaControl = wp.components.TextareaControl;
16 var Button = wp.components.Button;
17
18 var _tc, _tv;
19 function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
20 function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
21
22 function Stars(rating, best, starSize, starColor, starEmpty) {
23 var stars = [];
24 for (var i = 1; i <= best; i++) {
25 var filled = i <= Math.round(rating);
26 stars.push(el('span', { key: i, style: {
27 fontSize: starSize + 'px',
28 color: filled ? starColor : starEmpty,
29 lineHeight: 1
30 }}, filled ? '�
31 ' : ''));
32 }
33 return el('div', { style: { display: 'flex', gap: 2, alignItems: 'center' }}, stars);
34 }
35
36 registerBlockType('blockenberg/review-schema', {
37 title: __('Review Schema'),
38 icon: 'star-filled',
39 category: 'bkbg-blog',
40
41 edit: function (props) {
42 var attr = props.attributes;
43 var setAttr = props.setAttributes;
44 var bp = useBlockProps((function () {
45 var _tv = getTypoCssVars();
46 var s = {};
47 if (_tv) {
48 Object.assign(s, _tv(attr.headingTypo, '--bkrs-ht-'));
49 Object.assign(s, _tv(attr.bodyTypo, '--bkrs-bt-'));
50 }
51 return { className: 'bkbg-rs-wrap', style: s };
52 })());
53
54 function updateReview(idx, field, val) {
55 var reviews = attr.reviews.map(function (r, i) {
56 return i === idx ? Object.assign({}, r, { [field]: val }) : r;
57 });
58 setAttr({ reviews: reviews });
59 }
60 function addReview() {
61 setAttr({ reviews: attr.reviews.concat([{
62 author: 'New Reviewer', date: new Date().toISOString().slice(0, 10),
63 rating: 5, body: 'Great product!'
64 }]) });
65 }
66 function removeReview(idx) {
67 setAttr({ reviews: attr.reviews.filter(function (_, i) { return i !== idx; }) });
68 }
69
70 var inspector = el(InspectorControls, {},
71 /* Item Info */
72 el(PanelBody, { title: __('Item Info'), initialOpen: true },
73 el(TextControl, { label: __('Item Name'), value: attr.itemName,
74 onChange: function (v) { setAttr({ itemName: v }); },
75 __nextHasNoMarginBottom: true }),
76 el(SelectControl, { label: __('Item Type'), value: attr.itemType,
77 options: ['Product','LocalBusiness','Organization','SoftwareApplication','Book','Movie','Restaurant'].map(function (v) {
78 return { label: v, value: v };
79 }),
80 onChange: function (v) { setAttr({ itemType: v }); },
81 __nextHasNoMarginBottom: true }),
82 el(TextareaControl, { label: __('Description'), value: attr.description,
83 onChange: function (v) { setAttr({ description: v }); },
84 __nextHasNoMarginBottom: true }),
85 el(MediaUploadCheck, {},
86 el(MediaUpload, {
87 onSelect: function (m) { setAttr({ imageUrl: m.url }); },
88 allowedTypes: ['image'], value: attr.imageUrl,
89 render: function (ref) {
90 return el(Button, { variant: attr.imageUrl ? 'secondary' : 'primary', onClick: ref.open },
91 attr.imageUrl ? __('Change Image') : __('Choose Image (schema)'));
92 }
93 })
94 )
95 ),
96
97 /* Rating */
98 el(PanelBody, { title: __('Aggregate Rating'), initialOpen: false },
99 el(RangeControl, { label: __('Rating Value'), value: attr.ratingValue,
100 min: 1, max: 5, step: 0.1,
101 onChange: function (v) { setAttr({ ratingValue: v }); },
102 __nextHasNoMarginBottom: true }),
103 el(RangeControl, { label: __('Rating Count'), value: attr.ratingCount,
104 min: 1, max: 100000,
105 onChange: function (v) { setAttr({ ratingCount: v }); },
106 __nextHasNoMarginBottom: true }),
107 el(RangeControl, { label: __('Best Rating'), value: attr.bestRating,
108 min: 5, max: 10,
109 onChange: function (v) { setAttr({ bestRating: v }); },
110 __nextHasNoMarginBottom: true }),
111 el(RangeControl, { label: __('Rating Size (px)'), value: attr.ratingSize,
112 min: 24, max: 96,
113 onChange: function (v) { setAttr({ ratingSize: v }); },
114 __nextHasNoMarginBottom: true }),
115 el(RangeControl, { label: __('Star Size (px)'), value: attr.starSize,
116 min: 16, max: 56,
117 onChange: function (v) { setAttr({ starSize: v }); },
118 __nextHasNoMarginBottom: true })
119 ),
120
121 /* Reviews */
122 el(PanelBody, { title: __('Reviews'), initialOpen: false },
123 el(ToggleControl, { label: __('Show Reviews'), checked: attr.showReviews,
124 onChange: function (v) { setAttr({ showReviews: v }); },
125 __nextHasNoMarginBottom: true }),
126 el(SelectControl, { label: __('Columns'), value: String(attr.reviewColumns),
127 options: ['1','2','3'].map(function (v) { return { label: v, value: v }; }),
128 onChange: function (v) { setAttr({ reviewColumns: Number(v) }); },
129 __nextHasNoMarginBottom: true }),
130 attr.reviews.map(function (r, idx) {
131 return el(PanelBody, { key: idx, title: (r.author || 'Review ' + (idx + 1)), initialOpen: false },
132 el(TextControl, { label: __('Author'), value: r.author || '',
133 onChange: function (v) { updateReview(idx, 'author', v); },
134 __nextHasNoMarginBottom: true }),
135 el(TextControl, { label: __('Date (YYYY-MM-DD)'), value: r.date || '',
136 onChange: function (v) { updateReview(idx, 'date', v); },
137 __nextHasNoMarginBottom: true }),
138 el(RangeControl, { label: __('Rating'), value: r.rating || 5,
139 min: 1, max: attr.bestRating,
140 onChange: function (v) { updateReview(idx, 'rating', v); },
141 __nextHasNoMarginBottom: true }),
142 el(TextareaControl, { label: __('Review Text'), value: r.body || '',
143 onChange: function (v) { updateReview(idx, 'body', v); },
144 __nextHasNoMarginBottom: true }),
145 el(Button, { isDestructive: true, variant: 'secondary',
146 onClick: function () { removeReview(idx); },
147 style: { marginTop: 8 }
148 }, __('Remove Review'))
149 );
150 }),
151 el(Button, { variant: 'primary', onClick: addReview,
152 style: { marginTop: 8, width: '100%' }
153 }, __('+ Add Review'))
154 ),
155
156 /* Schema */
157 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
158 (function () { var TC = getTypoControl(); return TC ? [
159 el(TC, { key: 'ht', label: __('Item Name'), value: attr.headingTypo, onChange: function (v) { setAttr({ headingTypo: v }); } }),
160 el(TC, { key: 'bt', label: __('Body Text'), value: attr.bodyTypo, onChange: function (v) { setAttr({ bodyTypo: v }); } })
161 ] : null; })()
162 ),
163 el(PanelBody, { title: __('Schema & Layout'), initialOpen: false },
164 el(ToggleControl, { label: __('Output JSON-LD Schema'), checked: attr.showSchema,
165 onChange: function (v) { setAttr({ showSchema: v }); },
166 __nextHasNoMarginBottom: true }),
167 el(SelectControl, { label: __('Layout'), value: attr.layout,
168 options: [
169 { label: __('Card'), value: 'card' },
170 { label: __('Compact'), value: 'compact' }
171 ],
172 onChange: function (v) { setAttr({ layout: v }); },
173 __nextHasNoMarginBottom: true }),
174 el(RangeControl, { label: __('Card Radius (px)'), value: attr.cardRadius,
175 min: 0, max: 24,
176 onChange: function (v) { setAttr({ cardRadius: v }); },
177 __nextHasNoMarginBottom: true })
178 ),
179
180 el(PanelColorSettings, {
181 title: __('Colors'), initialOpen: false,
182 colorSettings: [
183 { label: __('Star Filled'), value: attr.starColor,
184 onChange: function (v) { setAttr({ starColor: v || '#f59e0b' }); } },
185 { label: __('Star Empty'), value: attr.starEmpty,
186 onChange: function (v) { setAttr({ starEmpty: v || '#e2e8f0' }); } },
187 { label: __('Section BG'), value: attr.sectionBg,
188 onChange: function (v) { setAttr({ sectionBg: v || '' }); } },
189 { label: __('Card BG'), value: attr.cardBg,
190 onChange: function (v) { setAttr({ cardBg: v || '#f8fafc' }); } },
191 { label: __('Card Border'), value: attr.cardBorder,
192 onChange: function (v) { setAttr({ cardBorder: v || '#e2e8f0' }); } },
193 { label: __('Heading'), value: attr.headingColor,
194 onChange: function (v) { setAttr({ headingColor: v || '#0f172a' }); } },
195 { label: __('Body Text'), value: attr.bodyColor,
196 onChange: function (v) { setAttr({ bodyColor: v || '#475569' }); } }
197 ]
198 })
199 );
200
201 return el(wp.element.Fragment, {}, inspector,
202 el('div', bp,
203 el('div', { style: { background: attr.sectionBg || 'transparent', padding: attr.sectionBg ? '40px' : '0' }},
204 /* Aggregate summary */
205 el('div', { className: 'bkbg-rs-summary', style: {
206 background: attr.bgColor || '#ffffff',
207 borderRadius: attr.cardRadius + 'px',
208 padding: '32px', marginBottom: 32,
209 border: '1px solid ' + attr.cardBorder,
210 display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12,
211 textAlign: 'center'
212 }},
213 el('h3', { className: 'bkbg-rs-item-name', style: { margin: 0, color: attr.headingColor }}, attr.itemName),
214 Stars(attr.ratingValue, attr.bestRating, attr.starSize, attr.starColor, attr.starEmpty),
215 el('div', { style: { fontSize: attr.ratingSize + 'px', fontWeight: 900, color: attr.headingColor, lineHeight: 1 }},
216 attr.ratingValue.toFixed(1)
217 ),
218 el('p', { style: { margin: 0, color: attr.authorColor || '#64748b', fontSize: 14 }},
219 __('Based on ') + attr.ratingCount + __(' reviews')
220 )
221 ),
222 /* Review cards */
223 attr.showReviews && attr.reviews.length > 0 && el('div', { style: {
224 display: 'grid',
225 gridTemplateColumns: 'repeat(' + attr.reviewColumns + ', 1fr)',
226 gap: 16
227 }},
228 attr.reviews.map(function (r, i) {
229 return el('div', { key: i, style: {
230 background: attr.cardBg,
231 border: '1px solid ' + attr.cardBorder,
232 borderRadius: attr.cardRadius + 'px',
233 padding: '20px'
234 }},
235 Stars(r.rating || 5, attr.bestRating, 18, attr.starColor, attr.starEmpty),
236 el('p', { className: 'bkbg-rs-body', style: { margin: '10px 0 12px', color: attr.bodyColor }}, r.body),
237 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' }},
238 el('strong', { style: { fontSize: 13, color: attr.headingColor }}, r.author),
239 el('span', { style: { fontSize: 11, color: attr.authorColor || '#94a3b8' }}, r.date)
240 )
241 );
242 })
243 )
244 )
245 )
246 );
247 },
248
249 save: function (props) {
250 var attr = props.attributes;
251 var bp = useBlockProps.save();
252 return el('div', bp,
253 el('div', { className: 'bkbg-rs-app', 'data-opts': JSON.stringify(attr) })
254 );
255 }
256 });
257 }() );
258