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 / icon-feature-grid / index.js

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

440 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 useState = wp.element.useState;
4 var __ = wp.i18n.__;
5 var registerBlockType = wp.blocks.registerBlockType;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var RichText = wp.blockEditor.RichText;
8 var useBlockProps = wp.blockEditor.useBlockProps;
9 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
10 var PanelBody = wp.components.PanelBody;
11 var RangeControl = wp.components.RangeControl;
12 var SelectControl = wp.components.SelectControl;
13 var ToggleControl = wp.components.ToggleControl;
14 var TextControl = wp.components.TextControl;
15 var Button = wp.components.Button;
16
17 var _TypographyControl, _typoCssVars;
18 function getTypographyControl() { return _TypographyControl || (_TypographyControl = window.bkbgTypographyControl); }
19 function getTypoCssVars() { return _typoCssVars || (_typoCssVars = window.bkbgTypoCssVars); }
20
21 function wrapStyle(a) {
22 var s = {
23 '--bkbg-ifg-bg': a.bgColor,
24 '--bkbg-ifg-heading-c': a.headingColor,
25 '--bkbg-ifg-sub-c': a.subColor,
26 '--bkbg-ifg-title-c': a.titleColor,
27 '--bkbg-ifg-desc-c': a.descColor,
28 '--bkbg-ifg-card-bg': a.cardBg,
29 '--bkbg-ifg-card-border': a.cardBorder,
30 '--bkbg-ifg-pt': a.paddingTop + 'px',
31 '--bkbg-ifg-pb': a.paddingBottom + 'px',
32 '--bkbg-ifg-heading-sz': a.headingSize + 'px',
33 '--bkbg-ifg-heading-w': a.headingWeight,
34 '--bkbg-ifg-heading-lh': a.headingLineHeight || 1.2,
35 '--bkbg-ifg-sub-sz': a.subSize + 'px',
36 '--bkbg-ifg-sub-w': a.subWeight || '600',
37 '--bkbg-ifg-sub-lh': a.subLineHeight || 1.4,
38 '--bkbg-ifg-title-sz': a.titleSize + 'px',
39 '--bkbg-ifg-title-w': a.titleWeight,
40 '--bkbg-ifg-title-lh': a.titleLineHeight || 1.3,
41 '--bkbg-ifg-desc-sz': a.descSize + 'px',
42 '--bkbg-ifg-desc-w': a.descWeight || '400',
43 '--bkbg-ifg-desc-lh': a.descLineHeight || 1.6,
44 '--bkbg-ifg-card-pad': a.cardPadding + 'px',
45 '--bkbg-ifg-card-r': a.cardRadius + 'px',
46 '--bkbg-ifg-gap': a.gap + 'px',
47 '--bkbg-ifg-cols': a.columns,
48 '--bkbg-ifg-icon-sz': a.iconSize + 'px',
49 '--bkbg-ifg-icon-box': a.iconBoxSize + 'px',
50 '--bkbg-ifg-icon-r': a.iconRadius + 'px',
51 '--bkbg-ifg-icon-bg': a.iconBg || 'rgba(108,63,181,0.1)',
52 '--bkbg-ifg-sect-gap': a.sectionGap + 'px',
53 '--bkbg-ifg-global-accent': a.globalAccent,
54 };
55 var _tv = getTypoCssVars();
56 if (_tv) {
57 Object.assign(s, _tv(a.headingTypo, '--bkbg-ifg-hd-'));
58 Object.assign(s, _tv(a.subTypo, '--bkbg-ifg-sh-'));
59 Object.assign(s, _tv(a.titleTypo, '--bkbg-ifg-tt-'));
60 Object.assign(s, _tv(a.descTypo, '--bkbg-ifg-ds-'));
61 }
62 return s;
63 }
64
65 var ICON_OPTIONS = [
66 { label: 'Performance', value: 'dashicons-performance' },
67 { label: 'Shield / Security', value: 'dashicons-shield-alt' },
68 { label: 'Chart / Analytics', value: 'dashicons-chart-line' },
69 { label: 'Groups / Team', value: 'dashicons-groups' },
70 { label: 'Migrate / Integrate', value: 'dashicons-migrate' },
71 { label: 'SOS / Support', value: 'dashicons-sos' },
72 { label: 'Star', value: 'dashicons-star-filled' },
73 { label: 'Clock / Time', value: 'dashicons-clock' },
74 { label: 'Checkmark', value: 'dashicons-yes-alt' },
75 { label: 'Lightbulb / Idea', value: 'dashicons-lightbulb' },
76 { label: 'Settings / Gear', value: 'dashicons-admin-settings' },
77 { label: 'Globe / World', value: 'dashicons-admin-site-alt3' },
78 { label: 'Lock', value: 'dashicons-lock' },
79 { label: 'Edit / Pencil', value: 'dashicons-edit' },
80 { label: 'Heart', value: 'dashicons-heart' },
81 { label: 'Rocket / Launch', value: 'dashicons-rocket' },
82 { label: 'Tag / Pricing', value: 'dashicons-tag' },
83 { label: 'Email', value: 'dashicons-email-alt' },
84 { label: 'Plugin / Puzzle', value: 'dashicons-plugins-checked' },
85 { label: 'Search', value: 'dashicons-search' },
86 ];
87
88 registerBlockType('blockenberg/icon-feature-grid', {
89 title: __('Icon Feature Grid', 'blockenberg'),
90 icon: 'grid-view',
91 category: 'bkbg-marketing',
92
93 edit: function (props) {
94 var a = props.attributes;
95 var set = props.setAttributes;
96
97 var editingState = useState(null);
98 var editing = editingState[0];
99 var setEditing = editingState[1];
100
101 var styleOptions = [
102 { label: __('Card (shadow)', 'blockenberg'), value: 'card' },
103 { label: __('Bordered', 'blockenberg'), value: 'bordered' },
104 { label: __('Minimal (no border)', 'blockenberg'), value: 'minimal' },
105 { label: __('Gradient backgrounds', 'blockenberg'), value: 'gradient' },
106 { label: __('Dark', 'blockenberg'), value: 'dark' },
107 ];
108 var iconStyleOptions = [
109 { label: __('Circle', 'blockenberg'), value: 'circle' },
110 { label: __('Square (rounded)', 'blockenberg'), value: 'square' },
111 { label: __('Plain (no box)', 'blockenberg'), value: 'plain' },
112 { label: __('Outline circle', 'blockenberg'), value: 'outline' },
113 ];
114 var columnsOptions = [
115 { label: '2', value: 2 }, { label: '3', value: 3 },
116 { label: '4', value: 4 }, { label: '5', value: 5 }, { label: '6', value: 6 }
117 ];
118 var alignOptions = [
119 { label: __('Left', 'blockenberg'), value: 'left' },
120 { label: __('Center', 'blockenberg'), value: 'center' },
121 ];
122
123 function updateItem(i, key, val) {
124 var ns = a.items.slice();
125 ns[i] = Object.assign({}, ns[i]);
126 ns[i][key] = val;
127 set({ items: ns });
128 }
129 function addItem() {
130 var colors = ['#6c3fb5','#3b82f6','#10b981','#f59e0b','#ef4444','#ec4899'];
131 var ns = a.items.concat([{
132 icon: 'dashicons-star-filled',
133 title: __('Feature Title', 'blockenberg'),
134 description: __('Describe this feature briefly.', 'blockenberg'),
135 accentColor: colors[a.items.length % colors.length]
136 }]);
137 set({ items: ns });
138 setEditing(ns.length - 1);
139 }
140 function removeItem(i) {
141 set({ items: a.items.filter(function (_, idx) { return idx !== i; }) });
142 if (editing === i) setEditing(null);
143 }
144 function moveItem(i, dir) {
145 var ni = i + dir;
146 if (ni < 0 || ni >= a.items.length) return;
147 var ns = a.items.slice();
148 var tmp = ns[i]; ns[i] = ns[ni]; ns[ni] = tmp;
149 set({ items: ns });
150 }
151
152 function getAccent(item) {
153 return a.useItemAccent ? (item.accentColor || a.globalAccent) : a.globalAccent;
154 }
155
156 function renderCard(item, i) {
157 var accent = getAccent(item);
158 var iconBoxStyle = {};
159 if (a.iconStyle !== 'plain') {
160 iconBoxStyle.background = a.iconBg || ('rgba(108,63,181,0.10)');
161 iconBoxStyle.background = accent.startsWith('#') ? accent + '18' : accent;
162 }
163 if (a.iconStyle === 'outline') {
164 iconBoxStyle.background = 'transparent';
165 iconBoxStyle.border = '2px solid ' + accent;
166 }
167
168 return el('div', { key: i, className: 'bkbg-ifg-card bkbg-ifg-icon-style--' + a.iconStyle },
169 el('div', { className: 'bkbg-ifg-icon-wrap', style: iconBoxStyle },
170 el('span', { className: 'dashicons ' + item.icon, style: { fontSize: a.iconSize + 'px', width: a.iconSize + 'px', height: a.iconSize + 'px', color: accent } })
171 ),
172 el(RichText, {
173 tagName: 'h3',
174 className: 'bkbg-ifg-title',
175 value: item.title,
176 onChange: function (v) { updateItem(i, 'title', v); },
177 placeholder: __('Feature title', 'blockenberg'),
178 allowedFormats: ['core/bold']
179 }),
180 el(RichText, {
181 tagName: 'p',
182 className: 'bkbg-ifg-desc',
183 value: item.description,
184 onChange: function (v) { updateItem(i, 'description', v); },
185 placeholder: __('Feature description', 'blockenberg'),
186 allowedFormats: ['core/bold', 'core/italic']
187 })
188 );
189 }
190
191 var blockProps = useBlockProps({
192 className: 'bkbg-ifg-wrap bkbg-ifg-style--' + a.style + ' bkbg-ifg-heading-align--' + a.headingAlign,
193 style: wrapStyle(a)
194 });
195
196 var inspector = el(InspectorControls, {},
197 el(PanelBody, { title: __('Section Header', 'blockenberg'), initialOpen: true },
198 el(ToggleControl, {
199 label: __('Show Heading', 'blockenberg'),
200 checked: a.showHeading,
201 __nextHasNoMarginBottom: true,
202 onChange: function (v) { set({ showHeading: v }); }
203 }),
204 a.showHeading && el(TextControl, {
205 label: __('Heading', 'blockenberg'),
206 value: a.heading,
207 onChange: function (v) { set({ heading: v }); }
208 }),
209 el(ToggleControl, {
210 label: __('Show Subheading', 'blockenberg'),
211 checked: a.showSubheading,
212 __nextHasNoMarginBottom: true,
213 onChange: function (v) { set({ showSubheading: v }); }
214 }),
215 a.showSubheading && el(TextControl, {
216 label: __('Subheading', 'blockenberg'),
217 value: a.subheading,
218 onChange: function (v) { set({ subheading: v }); }
219 }),
220 el(SelectControl, {
221 label: __('Heading Alignment', 'blockenberg'),
222 value: a.headingAlign,
223 options: alignOptions,
224 onChange: function (v) { set({ headingAlign: v }); }
225 })
226 ),
227 el(PanelBody, { title: __('Grid & Style', 'blockenberg'), initialOpen: false },
228 el(SelectControl, {
229 label: __('Card Style', 'blockenberg'),
230 value: a.style,
231 options: styleOptions,
232 onChange: function (v) { set({ style: v }); }
233 }),
234 el(SelectControl, {
235 label: __('Columns', 'blockenberg'),
236 value: a.columns,
237 options: columnsOptions,
238 onChange: function (v) { set({ columns: parseInt(v) }); }
239 }),
240 el(RangeControl, {
241 label: __('Card Padding (px)', 'blockenberg'),
242 value: a.cardPadding,
243 onChange: function (v) { set({ cardPadding: v }); },
244 min: 12, max: 56
245 }),
246 el(RangeControl, {
247 label: __('Card Radius (px)', 'blockenberg'),
248 value: a.cardRadius,
249 onChange: function (v) { set({ cardRadius: v }); },
250 min: 0, max: 32
251 }),
252 el(RangeControl, {
253 label: __('Grid Gap (px)', 'blockenberg'),
254 value: a.gap,
255 onChange: function (v) { set({ gap: v }); },
256 min: 8, max: 60
257 }),
258 el(RangeControl, {
259 label: __('Section-to-Grid Gap (px)', 'blockenberg'),
260 value: a.sectionGap,
261 onChange: function (v) { set({ sectionGap: v }); },
262 min: 16, max: 96
263 }),
264 el(RangeControl, {
265 label: __('Padding Top (px)', 'blockenberg'),
266 value: a.paddingTop,
267 onChange: function (v) { set({ paddingTop: v }); },
268 min: 0, max: 180
269 }),
270 el(RangeControl, {
271 label: __('Padding Bottom (px)', 'blockenberg'),
272 value: a.paddingBottom,
273 onChange: function (v) { set({ paddingBottom: v }); },
274 min: 0, max: 180
275 })
276 ),
277 el(PanelBody, { title: __('Icon Settings', 'blockenberg'), initialOpen: false },
278 el(SelectControl, {
279 label: __('Icon Box Style', 'blockenberg'),
280 value: a.iconStyle,
281 options: iconStyleOptions,
282 onChange: function (v) { set({ iconStyle: v }); }
283 }),
284 el(ToggleControl, {
285 label: __('Use Per-Item Accent Color', 'blockenberg'),
286 checked: a.useItemAccent,
287 __nextHasNoMarginBottom: true,
288 onChange: function (v) { set({ useItemAccent: v }); }
289 }),
290 el(RangeControl, {
291 label: __('Icon Size (px)', 'blockenberg'),
292 value: a.iconSize,
293 onChange: function (v) { set({ iconSize: v }); },
294 min: 14, max: 48
295 }),
296 el(RangeControl, {
297 label: __('Icon Box Size (px)', 'blockenberg'),
298 value: a.iconBoxSize,
299 onChange: function (v) { set({ iconBoxSize: v }); },
300 min: 28, max: 96
301 }),
302 el(RangeControl, {
303 label: __('Icon Box Radius (px)', 'blockenberg'),
304 value: a.iconRadius,
305 onChange: function (v) { set({ iconRadius: v }); },
306 min: 0, max: 50
307 })
308 ),
309 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
310 getTypographyControl() && el(getTypographyControl(), { label: __('Heading', 'blockenberg'), typo: a.headingTypo || {}, onChange: function (v) { set({ headingTypo: v }); } }),
311 getTypographyControl() && el(getTypographyControl(), { label: __('Subheading', 'blockenberg'), typo: a.subTypo || {}, onChange: function (v) { set({ subTypo: v }); } }),
312 getTypographyControl() && el(getTypographyControl(), { label: __('Feature Title', 'blockenberg'), typo: a.titleTypo || {}, onChange: function (v) { set({ titleTypo: v }); } }),
313 getTypographyControl() && el(getTypographyControl(), { label: __('Description', 'blockenberg'), typo: a.descTypo || {}, onChange: function (v) { set({ descTypo: v }); } })
314 ),
315 el(PanelBody, { title: __('Feature Items', 'blockenberg') + ' (' + a.items.length + ')', initialOpen: false },
316 a.items.map(function (item, i) {
317 var isEdit = editing === i;
318 return el('div', {
319 key: i,
320 style: { marginBottom: '8px', border: '1px solid #e2e8f0', borderRadius: '8px', overflow: 'hidden' }
321 },
322 el('div', {
323 style: { padding: '8px 12px', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '8px', background: isEdit ? '#f8f0ff' : '#f8fafc' },
324 onClick: function () { setEditing(isEdit ? null : i); }
325 },
326 el('span', { className: 'dashicons ' + item.icon, style: { fontSize: '16px', width: '16px', height: '16px', color: item.accentColor || a.globalAccent } }),
327 el('span', { style: { flex: 1, fontSize: '13px', fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, item.title || __('(untitled)', 'blockenberg')),
328 el('span', { style: { color: '#94a3b8' } }, isEdit ? '' : '')
329 ),
330 isEdit && el('div', { style: { padding: '12px' } },
331 el(SelectControl, {
332 label: __('Dashicon', 'blockenberg'),
333 value: item.icon,
334 options: ICON_OPTIONS,
335 onChange: function (v) { updateItem(i, 'icon', v); }
336 }),
337 el(TextControl, {
338 label: __('Title', 'blockenberg'),
339 value: item.title,
340 onChange: function (v) { updateItem(i, 'title', v); }
341 }),
342 el(TextControl, {
343 label: __('Description', 'blockenberg'),
344 value: item.description,
345 onChange: function (v) { updateItem(i, 'description', v); }
346 }),
347 a.useItemAccent && el('div', { style: { marginBottom: '12px' } },
348 el('label', { style: { display:'block', fontSize:'11px', fontWeight:'600', marginBottom:'4px', textTransform:'uppercase', letterSpacing:'.05em' } }, __('Accent Color', 'blockenberg')),
349 el('input', {
350 type: 'color',
351 value: item.accentColor || a.globalAccent,
352 onChange: function (e) { updateItem(i, 'accentColor', e.target.value); },
353 style: { width: '48px', height: '32px', border: 'none', borderRadius: '6px', cursor: 'pointer' }
354 })
355 ),
356 el('div', { style: { display: 'flex', gap: '6px', marginTop: '6px' } },
357 el(Button, { onClick: function () { moveItem(i, -1); }, variant: 'secondary', isSmall: true, disabled: i === 0 }, ''),
358 el(Button, { onClick: function () { moveItem(i, 1); }, variant: 'secondary', isSmall: true, disabled: i === a.items.length - 1 }, ''),
359 el(Button, { onClick: function () { removeItem(i); }, variant: 'tertiary', isDestructive: true, isSmall: true }, __('Remove', 'blockenberg'))
360 )
361 )
362 );
363 }),
364 el(Button, {
365 onClick: addItem,
366 variant: 'primary',
367 isSmall: true,
368 style: { marginTop: '8px', width: '100%', justifyContent: 'center' }
369 }, __('+ Add Feature', 'blockenberg'))
370 ),
371 el(PanelColorSettings, {
372 title: __('Colors', 'blockenberg'),
373 initialOpen: false,
374 colorSettings: [
375 { label: __('Section Background', 'blockenberg'), value: a.bgColor, onChange: function (v) { set({ bgColor: v || '#ffffff' }); } },
376 { label: __('Global Accent Color', 'blockenberg'), value: a.globalAccent, onChange: function (v) { set({ globalAccent: v || '#6c3fb5' }); } },
377 { label: __('Heading', 'blockenberg'), value: a.headingColor, onChange: function (v) { set({ headingColor: v || '#0f172a' }); } },
378 { label: __('Subheading', 'blockenberg'), value: a.subColor, onChange: function (v) { set({ subColor: v || '#64748b' }); } },
379 { label: __('Feature Title', 'blockenberg'), value: a.titleColor, onChange: function (v) { set({ titleColor: v || '#0f172a' }); } },
380 { label: __('Description', 'blockenberg'), value: a.descColor, onChange: function (v) { set({ descColor: v || '#475569' }); } },
381 { label: __('Card Background', 'blockenberg'), value: a.cardBg, onChange: function (v) { set({ cardBg: v || '#ffffff' }); } },
382 { label: __('Card Border', 'blockenberg'), value: a.cardBorder, onChange: function (v) { set({ cardBorder: v || '#e2e8f0' }); } },
383 ]
384 })
385 );
386
387 return el('div', {},
388 inspector,
389 el('div', blockProps,
390 (a.showHeading || a.showSubheading) && el('div', { className: 'bkbg-ifg-header' },
391 a.showHeading && el('h2', { className: 'bkbg-ifg-heading' }, a.heading),
392 a.showSubheading && el('p', { className: 'bkbg-ifg-sub' }, a.subheading)
393 ),
394 el('div', { className: 'bkbg-ifg-grid' },
395 a.items.map(function (item, i) { return renderCard(item, i); })
396 )
397 )
398 );
399 },
400
401 save: function (props) {
402 var a = props.attributes;
403 var blockProps = useBlockProps.save({
404 className: 'bkbg-ifg-wrap bkbg-ifg-style--' + a.style + ' bkbg-ifg-heading-align--' + a.headingAlign,
405 style: wrapStyle(a)
406 });
407
408 function getAccent(item) {
409 return a.useItemAccent ? (item.accentColor || a.globalAccent) : a.globalAccent;
410 }
411
412 function saveIconBoxStyle(item) {
413 var accent = getAccent(item);
414 if (a.iconStyle === 'plain') return {};
415 if (a.iconStyle === 'outline') return { background: 'transparent', border: '2px solid ' + accent };
416 return { background: accent + '18' };
417 }
418
419 return el('div', blockProps,
420 (a.showHeading || a.showSubheading) && el('div', { className: 'bkbg-ifg-header' },
421 a.showHeading && el('h2', { className: 'bkbg-ifg-heading' }, a.heading),
422 a.showSubheading && el('p', { className: 'bkbg-ifg-sub' }, a.subheading)
423 ),
424 el('div', { className: 'bkbg-ifg-grid' },
425 a.items.map(function (item, i) {
426 var accent = getAccent(item);
427 return el('div', { key: i, className: 'bkbg-ifg-card bkbg-ifg-icon-style--' + a.iconStyle },
428 el('div', { className: 'bkbg-ifg-icon-wrap', style: saveIconBoxStyle(item) },
429 el('span', { className: 'dashicons ' + item.icon, style: { fontSize: a.iconSize + 'px', width: a.iconSize + 'px', height: a.iconSize + 'px', color: accent } })
430 ),
431 el(RichText.Content, { tagName: 'h3', className: 'bkbg-ifg-title', value: item.title }),
432 el(RichText.Content, { tagName: 'p', className: 'bkbg-ifg-desc', value: item.description })
433 );
434 })
435 )
436 );
437 }
438 });
439 }() );
440