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

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

504 lines 23.1 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 useState = wp.element.useState;
5 var Fragment = wp.element.Fragment;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var useBlockProps = wp.blockEditor.useBlockProps;
9 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
10 var PanelBody = wp.components.PanelBody;
11 var PanelRow = wp.components.PanelRow;
12 var ToggleControl = wp.components.ToggleControl;
13 var RangeControl = wp.components.RangeControl;
14 var SelectControl = wp.components.SelectControl;
15 var TextControl = wp.components.TextControl;
16 var Button = wp.components.Button;
17 var ColorPicker = wp.components.ColorPicker;
18 var Popover = wp.components.Popover;
19
20 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
21 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
22
23 /* ---------- helpers ---------- */
24 function getTagFontSize(weight, minPx, maxPx) {
25 // weight 1-5 → fontSize minPx-maxPx
26 return Math.round(minPx + ((weight - 1) / 4) * (maxPx - minPx));
27 }
28
29 function getTagColors(index, a) {
30 if (a.colorMode === 'multi') {
31 var cols = a.multiColors.split(',').map(function (c) { return c.trim(); }).filter(Boolean);
32 return { bg: cols[index % cols.length], text: a.textColor };
33 }
34 if (a.colorMode === 'gradient') {
35 return { bg: 'linear-gradient(135deg,' + a.primaryColor + ',' + a.secondaryColor + ')', text: a.textColor };
36 }
37 /* single */
38 return { bg: a.primaryColor, text: a.textColor };
39 }
40
41 function getSortedTags(a) {
42 var tags = (a.tags || []).slice();
43 if (a.sortBy === 'alpha') {
44 tags.sort(function (x, y) { return x.label.localeCompare(y.label); });
45 } else if (a.sortBy === 'size') {
46 tags.sort(function (x, y) { return y.weight - x.weight; });
47 }
48 if (a.randomize) {
49 for (var i = tags.length - 1; i > 0; i--) {
50 var j = Math.floor(Math.random() * (i + 1));
51 var tmp = tags[i]; tags[i] = tags[j]; tags[j] = tmp;
52 }
53 }
54 return tags.slice(0, a.maxTags);
55 }
56
57 function buildTagStyle(index, a, weight) {
58 var fs = getTagFontSize(weight, a.fontSizeMin, a.fontSizeMax);
59 var colors = getTagColors(index, a);
60 var br = a.tagStyle === 'pill' ? 9999 : a.borderRadius;
61 var bgStr = a.tagStyle === 'outlined' ? 'transparent' : colors.bg;
62 var borderStr = a.tagStyle === 'outlined'
63 ? a.borderWidth + 'px solid ' + (a.colorMode === 'multi' ? colors.bg : a.borderColor)
64 : 'none';
65 return {
66 display: 'inline-block',
67 fontSize: fs + 'px',
68 padding: a.paddingY + 'px ' + a.paddingX + 'px',
69 borderRadius: br + 'px',
70 background: a.tagStyle === 'flat' ? 'none' : (a.tagStyle === 'outlined' ? 'transparent' : colors.bg),
71 color: a.tagStyle === 'flat'
72 ? (a.colorMode === 'multi' ? colors.bg : a.primaryColor)
73 : (a.tagStyle === 'outlined' ? (a.colorMode === 'multi' ? colors.bg : a.borderColor) : colors.text),
74 border: borderStr,
75 transition: a.animateHover ? 'all 0.2s ease' : 'none',
76 margin: '0',
77 };
78 }
79
80 /* ---------- editor preview tag ---------- */
81 function EditorTag(props) {
82 var a = props.attrs;
83 var tag = props.tag;
84 var index = props.index;
85 var style = buildTagStyle(index, a, tag.weight || 1);
86 return el('a', { href: '#', className: 'bktagcl-tag', style: style, onClick: function (e) { e.preventDefault(); } },
87 tag.label || __('Tag', 'blockenberg')
88 );
89 }
90
91 /* ---------- tag editor row ---------- */
92 function TagRow(props) {
93 var tag = props.tag;
94 var index = props.index;
95 var onChange = props.onChange;
96 var onRemove = props.onRemove;
97
98 return el('div', { style: { display: 'flex', gap: '8px', alignItems: 'center', marginBottom: '8px', flexWrap: 'wrap' } },
99 el(TextControl, {
100 placeholder: __('Label', 'blockenberg'),
101 value: tag.label || '',
102 onChange: function (v) { onChange('label', v); },
103 style: { flex: '1', minWidth: '100px', margin: 0 }
104 }),
105 el(TextControl, {
106 placeholder: __('URL', 'blockenberg'),
107 value: tag.url || '',
108 onChange: function (v) { onChange('url', v); },
109 style: { flex: '1', minWidth: '100px', margin: 0 }
110 }),
111 el(SelectControl, {
112 label: '',
113 value: String(tag.weight || 3),
114 options: [
115 { label: __('1 – XS', 'blockenberg'), value: '1' },
116 { label: __('2 – SM', 'blockenberg'), value: '2' },
117 { label: __('3 – MD', 'blockenberg'), value: '3' },
118 { label: __('4 – LG', 'blockenberg'), value: '4' },
119 { label: __('5 – XL', 'blockenberg'), value: '5' },
120 ],
121 onChange: function (v) { onChange('weight', parseInt(v, 10)); },
122 style: { margin: 0 }
123 }),
124 el(Button, {
125 isDestructive: true,
126 isSmall: true,
127 onClick: onRemove,
128 'aria-label': __('Remove tag', 'blockenberg')
129 }, '')
130 );
131 }
132
133 /* ---------- edit ---------- */
134 function Edit(props) {
135 var attributes = props.attributes;
136 var setAttributes = props.setAttributes;
137 var a = attributes;
138
139 function setTags(newTags) {
140 setAttributes({ tags: newTags });
141 }
142
143 function addTag() {
144 setAttributes({ tags: (a.tags || []).concat([{ label: 'New Tag', url: '#', weight: 3 }]) });
145 }
146
147 function removeTag(idx) {
148 var next = (a.tags || []).slice();
149 next.splice(idx, 1);
150 setAttributes({ tags: next });
151 }
152
153 function updateTag(idx, key, val) {
154 var next = (a.tags || []).slice();
155 next[idx] = Object.assign({}, next[idx], { [key]: val });
156 setAttributes({ tags: next });
157 }
158
159 var sortedPreview = getSortedTags(a);
160
161 var wrapStyle = {
162 display: 'flex',
163 flexWrap: 'wrap',
164 gap: a.gap + 'px',
165 justifyContent: a.textAlign === 'center' ? 'center' : (a.textAlign === 'right' ? 'flex-end' : 'flex-start'),
166 };
167
168 var blockProps = useBlockProps((function () {
169 var _tvf = getTypoCssVars();
170 var s = { padding: '16px' };
171 if (_tvf) Object.assign(s, _tvf(a.tagTypo, '--bktgc-tg-'));
172 return { style: s };
173 })());
174
175 var colorSettings = [
176 {
177 label: __('Primary Color', 'blockenberg'),
178 value: a.primaryColor,
179 onChange: function (v) { setAttributes({ primaryColor: v || '#6c3fb5' }); }
180 },
181 {
182 label: __('Secondary Color (gradient)', 'blockenberg'),
183 value: a.secondaryColor,
184 onChange: function (v) { setAttributes({ secondaryColor: v || '#a855f7' }); }
185 },
186 {
187 label: __('Text Color', 'blockenberg'),
188 value: a.textColor,
189 onChange: function (v) { setAttributes({ textColor: v || '#ffffff' }); }
190 },
191 {
192 label: __('Hover Background', 'blockenberg'),
193 value: a.hoverBg,
194 onChange: function (v) { setAttributes({ hoverBg: v || '#5a2fa0' }); }
195 },
196 {
197 label: __('Hover Text Color', 'blockenberg'),
198 value: a.hoverTextColor,
199 onChange: function (v) { setAttributes({ hoverTextColor: v || '#ffffff' }); }
200 },
201 {
202 label: __('Border Color', 'blockenberg'),
203 value: a.borderColor,
204 onChange: function (v) { setAttributes({ borderColor: v || '#6c3fb5' }); }
205 },
206 ];
207
208 return el(Fragment, null,
209 el(InspectorControls, null,
210
211 /* Source Panel */
212 el(PanelBody, { title: __('Source', 'blockenberg'), initialOpen: true },
213 el(SelectControl, {
214 label: __('Tag Source', 'blockenberg'),
215 value: a.sourceType,
216 options: [
217 { label: __('Custom Tags', 'blockenberg'), value: 'custom' },
218 { label: __('WordPress Tags', 'blockenberg'), value: 'wp-tags' },
219 ],
220 onChange: function (v) { setAttributes({ sourceType: v }); }
221 }),
222 a.sourceType === 'wp-tags' && el(Fragment, null,
223 el(RangeControl, {
224 label: __('Max Tags', 'blockenberg'),
225 value: a.maxTags,
226 min: 5,
227 max: 100,
228 onChange: function (v) { setAttributes({ maxTags: v }); }
229 }),
230 el(ToggleControl, {
231 label: __('Show Count', 'blockenberg'),
232 checked: a.showCount,
233 onChange: function (v) { setAttributes({ showCount: v }); },
234 __nextHasNoMarginBottom: true
235 })
236 )
237 ),
238
239 /* Custom Tags Panel */
240 a.sourceType === 'custom' && el(PanelBody, { title: __('Tags', 'blockenberg'), initialOpen: true },
241 (a.tags || []).map(function (tag, idx) {
242 return el(TagRow, {
243 key: idx,
244 tag: tag,
245 index: idx,
246 onChange: function (key, val) { updateTag(idx, key, val); },
247 onRemove: function () { removeTag(idx); }
248 });
249 }),
250 el(Button, { isPrimary: true, isSmall: true, onClick: addTag, style: { marginTop: '8px' } },
251 __('+ Add Tag', 'blockenberg')
252 )
253 ),
254
255 /* Sorting */
256 el(PanelBody, { title: __('Sorting', 'blockenberg'), initialOpen: false },
257 el(SelectControl, {
258 label: __('Sort By', 'blockenberg'),
259 value: a.sortBy,
260 options: [
261 { label: __('Input order', 'blockenberg'), value: 'input' },
262 { label: __('Alphabetical', 'blockenberg'), value: 'alpha' },
263 { label: __('Size (weight)', 'blockenberg'), value: 'size' },
264 ],
265 onChange: function (v) { setAttributes({ sortBy: v }); }
266 }),
267 el(ToggleControl, {
268 label: __('Randomize Order', 'blockenberg'),
269 checked: a.randomize,
270 onChange: function (v) { setAttributes({ randomize: v }); },
271 __nextHasNoMarginBottom: true
272 })
273 ),
274
275 /* Style Panel */
276 el(PanelBody, { title: __('Style', 'blockenberg'), initialOpen: false },
277 el(SelectControl, {
278 label: __('Tag Style', 'blockenberg'),
279 value: a.tagStyle,
280 options: [
281 { label: __('Rounded', 'blockenberg'), value: 'rounded' },
282 { label: __('Pill', 'blockenberg'), value: 'pill' },
283 { label: __('Outlined', 'blockenberg'), value: 'outlined' },
284 { label: __('Flat (no background)', 'blockenberg'), value: 'flat' },
285 ],
286 onChange: function (v) { setAttributes({ tagStyle: v }); }
287 }),
288 el(SelectControl, {
289 label: __('Color Mode', 'blockenberg'),
290 value: a.colorMode,
291 options: [
292 { label: __('Single color', 'blockenberg'), value: 'single' },
293 { label: __('Multi-color', 'blockenberg'), value: 'multi' },
294 { label: __('Gradient', 'blockenberg'), value: 'gradient' },
295 ],
296 onChange: function (v) { setAttributes({ colorMode: v }); }
297 }),
298 a.colorMode === 'multi' && el(BkbgMultiColorControl, {
299 label: __('Colors (comma-separated hex)', 'blockenberg'),
300 value: a.multiColors,
301 onChange: function (v) { setAttributes({ multiColors: v }); }
302 }),
303 el(SelectControl, {
304 label: __('Text Align', 'blockenberg'),
305 value: a.textAlign,
306 options: [
307 { label: __('Left', 'blockenberg'), value: 'left' },
308 { label: __('Center', 'blockenberg'), value: 'center' },
309 { label: __('Right', 'blockenberg'), value: 'right' },
310 ],
311 onChange: function (v) { setAttributes({ textAlign: v }); }
312 }),
313 el(ToggleControl, {
314 label: __('Animated Hover', 'blockenberg'),
315 checked: a.animateHover,
316 onChange: function (v) { setAttributes({ animateHover: v }); },
317 __nextHasNoMarginBottom: true
318 })
319 ),
320
321 /* Typography Panel */
322 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
323 getTypoControl()({ label: __('Tag', 'blockenberg'), value: a.tagTypo, onChange: function (v) { setAttributes({ tagTypo: v }); } }),
324 el(RangeControl, {
325 label: __('Min Font Size (px)', 'blockenberg'),
326 value: a.fontSizeMin,
327 min: 9,
328 max: 20,
329 onChange: function (v) { setAttributes({ fontSizeMin: v }); }
330 }),
331 el(RangeControl, {
332 label: __('Max Font Size (px)', 'blockenberg'),
333 value: a.fontSizeMax,
334 min: 14,
335 max: 40,
336 onChange: function (v) { setAttributes({ fontSizeMax: v }); }
337 })
338 ),
339
340 /* Spacing Panel */
341 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
342 el(RangeControl, {
343 label: __('Gap Between Tags (px)', 'blockenberg'),
344 value: a.gap,
345 min: 0,
346 max: 32,
347 onChange: function (v) { setAttributes({ gap: v }); }
348 }),
349 el(RangeControl, {
350 label: __('Horizontal Padding (px)', 'blockenberg'),
351 value: a.paddingX,
352 min: 4,
353 max: 40,
354 onChange: function (v) { setAttributes({ paddingX: v }); }
355 }),
356 el(RangeControl, {
357 label: __('Vertical Padding (px)', 'blockenberg'),
358 value: a.paddingY,
359 min: 2,
360 max: 24,
361 onChange: function (v) { setAttributes({ paddingY: v }); }
362 }),
363 el(RangeControl, {
364 label: __('Border Radius (px)', 'blockenberg'),
365 value: a.borderRadius,
366 min: 0,
367 max: 40,
368 onChange: function (v) { setAttributes({ borderRadius: v }); }
369 }),
370 el(RangeControl, {
371 label: __('Border Width (px)', 'blockenberg'),
372 value: a.borderWidth,
373 min: 1,
374 max: 6,
375 onChange: function (v) { setAttributes({ borderWidth: v }); }
376 })
377 ),
378
379 /* Colors */
380 el(PanelColorSettings, {
381 title: __('Colors', 'blockenberg'),
382 initialOpen: false,
383 colorSettings: colorSettings
384 })
385 ),
386
387 /* ---- editor preview ---- */
388 el('div', blockProps,
389 a.sourceType === 'wp-tags' && el('p', { style: { textAlign: 'center', color: '#888', fontStyle: 'italic', marginBottom: '12px', fontSize: '13px' } },
390 __('WordPress tags will render on the front end.', 'blockenberg')
391 ),
392 el('div', {
393 className: 'bktagcl-wrap',
394 style: wrapStyle,
395 'data-source': a.sourceType,
396 'data-max': a.maxTags,
397 'data-sort': a.sortBy,
398 'data-count': a.showCount ? '1' : '0',
399 'data-hover-bg': a.hoverBg,
400 'data-hover-text': a.hoverTextColor,
401 'data-animate': a.animateHover ? '1' : '0',
402 },
403 sortedPreview.map(function (tag, idx) {
404 return el(EditorTag, { key: idx, attrs: a, tag: tag, index: idx });
405 })
406 )
407 )
408 );
409 }
410
411 /* ---------- save ---------- */
412 function Save(props) {
413 var a = props.attributes;
414 var sorted = getSortedTags(a);
415 var blockProps = (function () {
416 var _tvf = getTypoCssVars();
417 var s = {};
418 if (_tvf) Object.assign(s, _tvf(a.tagTypo, '--bktgc-tg-'));
419 return wp.blockEditor.useBlockProps.save({ style: s });
420 })();
421
422 var wrapStyle = {
423 display: 'flex',
424 flexWrap: 'wrap',
425 gap: a.gap + 'px',
426 justifyContent: a.textAlign === 'center' ? 'center' : (a.textAlign === 'right' ? 'flex-end' : 'flex-start'),
427 };
428
429 return el('div', blockProps,
430 el('div', Object.assign({
431 className: 'bktagcl-wrap',
432 'data-source': a.sourceType,
433 'data-max': a.maxTags,
434 'data-sort': a.sortBy,
435 'data-count': a.showCount ? '1' : '0',
436 'data-hover-bg': a.hoverBg,
437 'data-hover-text': a.hoverTextColor,
438 'data-animate': a.animateHover ? '1' : '0',
439 '--bktagcl-hover-bg': a.hoverBg,
440 '--bktagcl-hover-text': a.hoverTextColor,
441 }, { style: wrapStyle }),
442 a.sourceType === 'custom' && sorted.map(function (tag, idx) {
443 var fs = getTagFontSize(tag.weight || 1, a.fontSizeMin, a.fontSizeMax);
444 var colors = getTagColors(idx, a);
445 var br = a.tagStyle === 'pill' ? 9999 : a.borderRadius;
446 var bgVal = a.tagStyle === 'flat' ? 'none' : (a.tagStyle === 'outlined' ? 'transparent' : colors.bg);
447 var textVal = a.tagStyle === 'flat'
448 ? (a.colorMode === 'multi' ? colors.bg : a.primaryColor)
449 : (a.tagStyle === 'outlined' ? (a.colorMode === 'multi' ? colors.bg : a.borderColor) : colors.text);
450 var borderVal = a.tagStyle === 'outlined'
451 ? a.borderWidth + 'px solid ' + (a.colorMode === 'multi' ? colors.bg : a.borderColor)
452 : 'none';
453
454 return el('a', {
455 key: idx,
456 href: tag.url || '#',
457 className: 'bktagcl-tag',
458 style: {
459 fontSize: fs + 'px',
460 padding: a.paddingY + 'px ' + a.paddingX + 'px',
461 borderRadius: br + 'px',
462 background: bgVal,
463 color: textVal,
464 border: borderVal,
465 display: 'inline-block',
466 }
467 }, tag.label);
468 }),
469 /* wp-tags placeholder — rendered by frontend.js */
470 a.sourceType === 'wp-tags' && null
471 )
472 );
473 }
474
475 /* ── BkbgMultiColorControl ──────────────────────────────────────── */
476 function BkbgMultiColorControl(props) {
477 var label = props.label;
478 var value = props.value || '';
479 var onChange = props.onChange;
480 var colors = value.split(',').map(function (c) { return c.trim(); }).filter(Boolean);
481 var st = useState(-1); var openIdx = st[0]; var setOpenIdx = st[1];
482 return el(Fragment, null,
483 el('div', { style: { marginBottom: '8px' } },
484 el('span', { style: { fontSize: '11px', fontWeight: 500, textTransform: 'uppercase', display: 'block', marginBottom: '4px' } }, label),
485 el('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '6px', alignItems: 'center' } },
486 colors.map(function (c, i) {
487 return el('div', { key: i, style: { position: 'relative', display: 'inline-flex' } },
488 el('button', { type: 'button', style: { width: 28, height: 28, borderRadius: 4, border: '1px solid #ccc', background: c, cursor: 'pointer', padding: 0 }, onClick: function () { setOpenIdx(openIdx === i ? -1 : i); } }),
489 el('button', { type: 'button', 'aria-label': 'Remove', style: { position: 'absolute', top: -6, right: -6, width: 14, height: 14, borderRadius: '50%', border: 'none', background: '#d00', color: '#fff', fontSize: '10px', lineHeight: '14px', cursor: 'pointer', padding: 0, textAlign: 'center' }, onClick: function () { var n = colors.slice(); n.splice(i, 1); onChange(n.join(',')); } }, '×'),
490 openIdx === i && el(Popover, { onClose: function () { setOpenIdx(-1); } }, el('div', { style: { padding: '8px' } }, el(ColorPicker, { color: c, enableAlpha: true, onChange: function (v) { var n = colors.slice(); n[i] = v; onChange(n.join(',')); } })))
491 );
492 }),
493 el(Button, { isSmall: true, variant: 'secondary', onClick: function () { onChange(value ? value + ',#6c3fb5' : '#6c3fb5'); }, style: { height: 28, minWidth: 28 } }, '+')
494 )
495 )
496 );
497 }
498
499 registerBlockType('blockenberg/tag-cloud', {
500 edit: Edit,
501 save: Save,
502 });
503 }() );
504