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

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

363 lines 23.7 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 useState = wp.element.useState;
5 var __ = wp.i18n.__;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var RichText = wp.blockEditor.RichText;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var PanelBody = wp.components.PanelBody;
11 var Button = wp.components.Button;
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 ColorPicker = wp.components.ColorPicker;
17 var Popover = wp.components.Popover;
18
19 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
20 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
21 var IP = function () { return window.bkbgIconPicker; };
22
23 var STYLE_OPTIONS = [
24 { label: __('Cards (bordered)', 'blockenberg'), value: 'cards' },
25 { label: __('Flat (no border)', 'blockenberg'), value: 'flat' },
26 { label: __('Filled', 'blockenberg'), value: 'filled' },
27 ];
28 var DIVIDER_OPTIONS = [
29 { label: __('Line', 'blockenberg'), value: 'line' },
30 { label: __('VS Badge', 'blockenberg'), value: 'vs' },
31 { label: __('Arrow →', 'blockenberg'), value: 'arrow' },
32 { label: __('None', 'blockenberg'), value: 'none' },
33 ];
34 var ALIGN_OPTIONS = [
35 { label: __('Center', 'blockenberg'), value: 'center' },
36 { label: __('Left', 'blockenberg'), value: 'left' },
37 ];
38
39 function makeId() { return 'tc' + Math.random().toString(36).substr(2, 5); }
40
41 function buildWrapStyle(a) {
42 var _tvf = getTypoCssVars();
43 var s = {
44 '--bkbg-tc-left-bg': a.leftBg,
45 '--bkbg-tc-right-bg': a.rightBg,
46 '--bkbg-tc-left-border': a.leftBorderColor,
47 '--bkbg-tc-right-border': a.rightBorderColor,
48 '--bkbg-tc-left-label': a.leftLabelColor,
49 '--bkbg-tc-right-label': a.rightLabelColor,
50 '--bkbg-tc-left-icon': a.leftItemIconColor,
51 '--bkbg-tc-right-icon': a.rightItemIconColor,
52 '--bkbg-tc-left-text': a.leftTextColor,
53 '--bkbg-tc-right-text': a.rightTextColor,
54 '--bkbg-tc-left-desc': a.leftDescColor,
55 '--bkbg-tc-right-desc': a.rightDescColor,
56 '--bkbg-tc-divider': a.dividerColor,
57 '--bkbg-tc-icon-sz': a.iconSize + 'px',
58 '--bkbg-tc-item-icon-sz': a.itemIconSize + 'px',
59 '--bkbg-tc-card-r': a.cardRadius + 'px',
60 '--bkbg-tc-card-pad': a.cardPadding + 'px',
61 paddingTop: a.paddingTop + 'px',
62 paddingBottom: a.paddingBottom + 'px',
63 backgroundColor: a.bgColor || undefined,
64 };
65 if (_tvf) { Object.assign(s, _tvf(a.labelTypo, '--bktcm-lb-'), _tvf(a.descTypo, '--bktcm-ds-'), _tvf(a.itemTypo, '--bktcm-it-')); }
66 return s;
67 }
68
69 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
70 var isOpen = openKey === key;
71 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
72 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
73 el('div', { style: { position: 'relative', flexShrink: 0 } },
74 el('button', { type: 'button', onClick: function () { setOpenKey(isOpen ? null : key); }, style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#ccc' } }),
75 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
76 el('div', { style: { padding: '8px' } },
77 el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange })
78 )
79 )
80 )
81 );
82 }
83
84 /* ── Column component (editor) ──────────────────────────────────── */
85 function CompareColumn(props) {
86 var side = props.side; /* 'left' | 'right' */
87 var a = props.a;
88 var setAttributes = props.setAttributes;
89
90 var label = side === 'left' ? a.leftLabel : a.rightLabel;
91 var description = side === 'left' ? a.leftDescription : a.rightDescription;
92 var icon = side === 'left' ? a.leftIcon : a.rightIcon;
93 var iconType = side === 'left' ? (a.leftIconType || 'custom-char') : (a.rightIconType || 'custom-char');
94 var iconDash = side === 'left' ? a.leftIconDashicon : a.rightIconDashicon;
95 var iconImg = side === 'left' ? a.leftIconImageUrl : a.rightIconImageUrl;
96 var items = side === 'left' ? a.leftItems : a.rightItems;
97 var itemIcon = side === 'left' ? a.leftItemIcon : a.rightItemIcon;
98 var itemIconType = side === 'left' ? (a.leftItemIconType || 'custom-char') : (a.rightItemIconType || 'custom-char');
99 var itemIconDash = side === 'left' ? a.leftItemIconDashicon : a.rightItemIconDashicon;
100 var itemIconImg = side === 'left' ? a.leftItemIconImageUrl : a.rightItemIconImageUrl;
101
102 var labelColor = side === 'left' ? a.leftLabelColor : a.rightLabelColor;
103 var itemIconColor = side === 'left' ? a.leftItemIconColor : a.rightItemIconColor;
104 var textColor = side === 'left' ? a.leftTextColor : a.rightTextColor;
105 var descColor = side === 'left' ? a.leftDescColor : a.rightDescColor;
106 var bg = side === 'left' ? a.leftBg : a.rightBg;
107 var borderColor = side === 'left' ? a.leftBorderColor : a.rightBorderColor;
108
109 function setItems(newItems) {
110 var upd = {};
111 upd[side === 'left' ? 'leftItems' : 'rightItems'] = newItems;
112 setAttributes(upd);
113 }
114
115 var cardStyle = {
116 background: bg,
117 borderRadius: a.cardRadius + 'px',
118 padding: a.cardPadding + 'px',
119 flex: 1,
120 boxSizing: 'border-box',
121 };
122 if (a.style === 'cards') {
123 cardStyle.border = '2px solid ' + borderColor;
124 } else if (a.style === 'filled') {
125 cardStyle.border = 'none';
126 }
127
128 return el('div', { className: 'bkbg-tc-col bkbg-tc-col--' + side, style: cardStyle },
129 /* Header */
130 el('div', { className: 'bkbg-tc-col-header', style: { textAlign: a.headerAlign, marginBottom: '20px' } },
131 a.showIcons && el('div', { className: 'bkbg-tc-col-icon', style: { fontSize: a.iconSize + 'px', marginBottom: '10px', lineHeight: 1 } }, iconType !== 'custom-char' ? IP().buildEditorIcon(iconType, icon, iconDash, iconImg, iconDashColor) : icon),
132 el(RichText, {
133 tagName: 'h3', className: 'bkbg-tc-col-label',
134 value: label,
135 onChange: function (v) { var u = {}; u[side === 'left' ? 'leftLabel' : 'rightLabel'] = v; setAttributes(u); },
136 placeholder: side === 'left' ? __('Old Way', 'blockenberg') : __('New Way', 'blockenberg'),
137 style: { color: labelColor, margin: 0 },
138 }),
139 a.showDescriptions && el(RichText, {
140 tagName: 'p', className: 'bkbg-tc-col-desc',
141 value: description,
142 onChange: function (v) { var u = {}; u[side === 'left' ? 'leftDescription' : 'rightDescription'] = v; setAttributes(u); },
143 placeholder: __('Short description…', 'blockenberg'),
144 style: { color: descColor, margin: '8px 0 0' },
145 })
146 ),
147 /* Items */
148 el('ul', { className: 'bkbg-tc-items', style: { listStyle: 'none', margin: 0, padding: 0 } },
149 items.map(function (item, idx) {
150 return el('li', { key: item.id, className: 'bkbg-tc-item', style: { display: 'flex', alignItems: 'flex-start', gap: '10px', marginBottom: '10px' } },
151 el('span', { className: 'bkbg-tc-item-icon', style: { fontSize: a.itemIconSize + 'px', color: itemIconColor, flexShrink: 0, lineHeight: 1.4, fontWeight: 900 } }, itemIconType !== 'custom-char' ? IP().buildEditorIcon(itemIconType, itemIcon, itemIconDash, itemIconImg, itemIconDashColor) : itemIcon),
152 el(RichText, {
153 tagName: 'span', className: 'bkbg-tc-item-text',
154 value: item.text,
155 onChange: function (v) { setItems(items.map(function (it) { return it.id === item.id ? Object.assign({}, it, { text: v }) : it; })); },
156 placeholder: __('Item…', 'blockenberg'),
157 style: { color: textColor, flex: 1 },
158 }),
159 el(Button, {
160 icon: 'trash', isSmall: true, isDestructive: true,
161 onClick: function () { setItems(items.filter(function (it) { return it.id !== item.id; })); },
162 style: { flexShrink: 0 },
163 label: __('Remove item', 'blockenberg'),
164 })
165 );
166 })
167 ),
168 el(Button, {
169 variant: 'secondary', size: 'compact',
170 onClick: function () { setItems(items.concat([{ id: makeId(), text: __('New item', 'blockenberg') }])); },
171 style: { marginTop: '12px' },
172 }, '+ ' + __('Add item', 'blockenberg'))
173 );
174 }
175
176 /* ── Divider ────────────────────────────────────────────────────── */
177 function Divider(props) {
178 var a = props.a;
179 if (!a.showDivider || a.dividerStyle === 'none') return null;
180
181 var style = { display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 };
182
183 if (a.dividerStyle === 'vs') {
184 return el('div', { className: 'bkbg-tc-divider bkbg-tc-divider--vs', style: Object.assign({}, style, { width: '48px' }) },
185 el('div', { className: 'bkbg-tc-vs-badge', style: { background: a.dividerColor, color: '#fff', borderRadius: '50%', width: '44px', height: '44px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 900, fontSize: '13px', flexShrink: 0 } }, 'VS')
186 );
187 }
188 if (a.dividerStyle === 'arrow') {
189 return el('div', { className: 'bkbg-tc-divider bkbg-tc-divider--arrow', style: Object.assign({}, style, { width: '40px' }) },
190 el('span', { style: { fontSize: '28px', color: a.dividerColor, flexShrink: 0 } }, '')
191 );
192 }
193 /* line */
194 return el('div', { className: 'bkbg-tc-divider bkbg-tc-divider--line', style: { width: '2px', background: a.dividerColor, alignSelf: 'stretch', flexShrink: 0, borderRadius: '99px' } });
195 }
196
197 registerBlockType('blockenberg/text-comparison', {
198 title: __('Text Comparison', 'blockenberg'),
199 icon: 'columns',
200 category: 'bkbg-dev',
201
202 edit: function (props) {
203 var a = props.attributes;
204 var setAttributes = props.setAttributes;
205
206 var openColorKeyState = useState(null);
207 var openColorKey = openColorKeyState[0];
208 var setOpenColorKey = openColorKeyState[1];
209
210 var blockProps = useBlockProps({ style: buildWrapStyle(a) });
211
212 function cc(key, label, attrKey) {
213 return renderColorControl(key, label, a[attrKey], function (val) {
214 var upd = {}; upd[attrKey] = val; setAttributes(upd);
215 }, openColorKey, setOpenColorKey);
216 }
217
218 var gridStyle = {
219 display: 'flex',
220 gap: a.gap + 'px',
221 maxWidth: a.maxWidth + 'px',
222 margin: '0 auto',
223 alignItems: 'stretch',
224 };
225
226 return el(Fragment, null,
227 el(InspectorControls, null,
228 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: true },
229 el(SelectControl, { label: __('Style', 'blockenberg'), value: a.style, options: STYLE_OPTIONS, onChange: function (v) { setAttributes({ style: v }); } }),
230 el(SelectControl, { label: __('Header align', 'blockenberg'), value: a.headerAlign, options: ALIGN_OPTIONS, onChange: function (v) { setAttributes({ headerAlign: v }); } }),
231 el(ToggleControl, { label: __('Show icons', 'blockenberg'), checked: a.showIcons, onChange: function (v) { setAttributes({ showIcons: v }); }, __nextHasNoMarginBottom: true }),
232 el(ToggleControl, { label: __('Show descriptions', 'blockenberg'), checked: a.showDescriptions, onChange: function (v) { setAttributes({ showDescriptions: v }); }, __nextHasNoMarginBottom: true }),
233 el(ToggleControl, { label: __('Show divider', 'blockenberg'), checked: a.showDivider, onChange: function (v) { setAttributes({ showDivider: v }); }, __nextHasNoMarginBottom: true }),
234 a.showDivider && el(SelectControl, { label: __('Divider style', 'blockenberg'), value: a.dividerStyle, options: DIVIDER_OPTIONS, onChange: function (v) { setAttributes({ dividerStyle: v }); } }),
235 el(RangeControl, { label: __('Max width (px)', 'blockenberg'), value: a.maxWidth, min: 480, max: 1400, onChange: function (v) { setAttributes({ maxWidth: v }); } }),
236 el(RangeControl, { label: __('Column gap (px)', 'blockenberg'), value: a.gap, min: 0, max: 80, onChange: function (v) { setAttributes({ gap: v }); } }),
237 el(RangeControl, { label: __('Card radius (px)','blockenberg'), value: a.cardRadius, min: 0, max: 32, onChange: function (v) { setAttributes({ cardRadius: v }); } }),
238 el(RangeControl, { label: __('Card padding (px)','blockenberg'), value: a.cardPadding, min: 12, max: 64, onChange: function (v) { setAttributes({ cardPadding: v }); } })
239 ),
240 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
241 getTypoControl() && getTypoControl()({
242 label: __('Label', 'blockenberg'),
243 value: a.labelTypo || {},
244 onChange: function (v) { setAttributes({ labelTypo: v }); }
245 }),
246 getTypoControl() && getTypoControl()({
247 label: __('Description', 'blockenberg'),
248 value: a.descTypo || {},
249 onChange: function (v) { setAttributes({ descTypo: v }); }
250 }),
251 getTypoControl() && getTypoControl()({
252 label: __('Item Text', 'blockenberg'),
253 value: a.itemTypo || {},
254 onChange: function (v) { setAttributes({ itemTypo: v }); }
255 }),
256 el(RangeControl, { label: __('Icon size (px)', 'blockenberg'), value: a.iconSize, min: 18, max: 60, onChange: function (v) { setAttributes({ iconSize: v }); } }),
257 el(RangeControl, { label: __('Item icon (px)', 'blockenberg'), value: a.itemIconSize, min: 12, max: 24, onChange: function (v) { setAttributes({ itemIconSize: v }); } })
258 ),
259 el(PanelBody, { title: __('Left column', 'blockenberg'), initialOpen: false },
260 el(IP().IconPickerControl, IP().iconPickerProps(a, setAttributes, { charAttr: 'leftIcon', typeAttr: 'leftIconType', dashiconAttr: 'leftIconDashicon', imageUrlAttr: 'leftIconImageUrl', colorAttr: 'leftIconDashiconColor' })),
261 el(IP().IconPickerControl, IP().iconPickerProps(a, setAttributes, { charAttr: 'leftItemIcon', typeAttr: 'leftItemIconType', dashiconAttr: 'leftItemIconDashicon', imageUrlAttr: 'leftItemIconImageUrl', colorAttr: 'leftItemIconDashiconColor' })),
262 cc('leftBg', __('Background', 'blockenberg'), 'leftBg'),
263 cc('leftBorderColor', __('Border color', 'blockenberg'), 'leftBorderColor'),
264 cc('leftLabelColor', __('Label color', 'blockenberg'), 'leftLabelColor'),
265 cc('leftDescColor', __('Desc color', 'blockenberg'), 'leftDescColor'),
266 cc('leftTextColor', __('Item text', 'blockenberg'), 'leftTextColor'),
267 cc('leftItemIconColor', __('Item icon', 'blockenberg'), 'leftItemIconColor')
268 ),
269 el(PanelBody, { title: __('Right column', 'blockenberg'), initialOpen: false },
270 el(IP().IconPickerControl, IP().iconPickerProps(a, setAttributes, { charAttr: 'rightIcon', typeAttr: 'rightIconType', dashiconAttr: 'rightIconDashicon', imageUrlAttr: 'rightIconImageUrl', colorAttr: 'rightIconDashiconColor' })),
271 el(IP().IconPickerControl, IP().iconPickerProps(a, setAttributes, { charAttr: 'rightItemIcon', typeAttr: 'rightItemIconType', dashiconAttr: 'rightItemIconDashicon', imageUrlAttr: 'rightItemIconImageUrl', colorAttr: 'rightItemIconDashiconColor' })),
272 cc('rightBg', __('Background', 'blockenberg'), 'rightBg'),
273 cc('rightBorderColor', __('Border color', 'blockenberg'), 'rightBorderColor'),
274 cc('rightLabelColor', __('Label color', 'blockenberg'), 'rightLabelColor'),
275 cc('rightDescColor', __('Desc color', 'blockenberg'), 'rightDescColor'),
276 cc('rightTextColor', __('Item text', 'blockenberg'), 'rightTextColor'),
277 cc('rightItemIconColor', __('Item icon', 'blockenberg'), 'rightItemIconColor')
278 ),
279 el(PanelBody, { title: __('Divider & Background', 'blockenberg'), initialOpen: false },
280 cc('dividerColor', __('Divider color', 'blockenberg'), 'dividerColor'),
281 cc('bgColor', __('Section bg', 'blockenberg'), 'bgColor')
282 ),
283 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
284 el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
285 el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
286 )
287 ),
288
289 el('div', blockProps,
290 el('div', { className: 'bkbg-tc-grid', style: gridStyle },
291 el(CompareColumn, { side: 'left', a: a, setAttributes: setAttributes }),
292 el(Divider, { a: a }),
293 el(CompareColumn, { side: 'right', a: a, setAttributes: setAttributes })
294 )
295 )
296 );
297 },
298
299 save: function (props) {
300 var a = props.attributes;
301
302 function ColItems(side) {
303 var items = side === 'left' ? a.leftItems : a.rightItems;
304 var itemIcon = side === 'left' ? a.leftItemIcon : a.rightItemIcon;
305 var itemIconType = side === 'left' ? (a.leftItemIconType || 'custom-char') : (a.rightItemIconType || 'custom-char');
306 var itemIconDash = side === 'left' ? a.leftItemIconDashicon : a.rightItemIconDashicon;
307 var itemIconImg = side === 'left' ? a.leftItemIconImageUrl : a.rightItemIconImageUrl;
308 var itemIconDashColor = side === 'left' ? a.leftItemIconDashiconColor : a.rightItemIconDashiconColor;
309 var iconClr = side === 'left' ? a.leftItemIconColor : a.rightItemIconColor;
310 var txtClr = side === 'left' ? a.leftTextColor : a.rightTextColor;
311 return el('ul', { className: 'bkbg-tc-items' },
312 items.map(function (item) {
313 return el('li', { key: item.id, className: 'bkbg-tc-item' },
314 el('span', { className: 'bkbg-tc-item-icon', 'aria-hidden': 'true' }, itemIconType !== 'custom-char' ? IP().buildSaveIcon(itemIconType, itemIcon, itemIconDash, itemIconImg, itemIconDashColor) : itemIcon),
315 el(RichText.Content, { tagName: 'span', className: 'bkbg-tc-item-text', value: item.text })
316 );
317 })
318 );
319 }
320
321 function SaveCol(side) {
322 var label = side === 'left' ? a.leftLabel : a.rightLabel;
323 var description = side === 'left' ? a.leftDescription : a.rightDescription;
324 var icon = side === 'left' ? a.leftIcon : a.rightIcon;
325 var iconType = side === 'left' ? (a.leftIconType || 'custom-char') : (a.rightIconType || 'custom-char');
326 var iconDash = side === 'left' ? a.leftIconDashicon : a.rightIconDashicon;
327 var iconImg = side === 'left' ? a.leftIconImageUrl : a.rightIconImageUrl;
328 var iconDashColor = side === 'left' ? a.leftIconDashiconColor : a.rightIconDashiconColor;
329 return el('div', { className: 'bkbg-tc-col bkbg-tc-col--' + side },
330 el('div', { className: 'bkbg-tc-col-header' },
331 a.showIcons && el('div', { className: 'bkbg-tc-col-icon', 'aria-hidden': 'true' }, iconType !== 'custom-char' ? IP().buildSaveIcon(iconType, icon, iconDash, iconImg, iconDashColor) : icon),
332 el(RichText.Content, { tagName: 'h3', className: 'bkbg-tc-col-label', value: label }),
333 a.showDescriptions && el(RichText.Content, { tagName: 'p', className: 'bkbg-tc-col-desc', value: description })
334 ),
335 ColItems(side)
336 );
337 }
338
339 var dividerEl = null;
340 if (a.showDivider && a.dividerStyle !== 'none') {
341 if (a.dividerStyle === 'vs') {
342 dividerEl = el('div', { className: 'bkbg-tc-divider bkbg-tc-divider--vs', 'aria-hidden': 'true' }, el('div', { className: 'bkbg-tc-vs-badge' }, 'VS'));
343 } else if (a.dividerStyle === 'arrow') {
344 dividerEl = el('div', { className: 'bkbg-tc-divider bkbg-tc-divider--arrow', 'aria-hidden': 'true' }, el('span', null, ''));
345 } else {
346 dividerEl = el('div', { className: 'bkbg-tc-divider bkbg-tc-divider--line', 'aria-hidden': 'true' });
347 }
348 }
349
350 return el('div', wp.blockEditor.useBlockProps.save({
351 className: 'bkbg-tc-wrapper bkbg-tc--' + a.style,
352 style: buildWrapStyle(a),
353 }),
354 el('div', { className: 'bkbg-tc-grid', style: { maxWidth: a.maxWidth + 'px', margin: '0 auto', gap: a.gap + 'px' } },
355 SaveCol('left'),
356 dividerEl,
357 SaveCol('right')
358 )
359 );
360 }
361 });
362 }() );
363