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 / how-it-works / index.js

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

332 lines 22.8 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 _TypographyControl, _typoCssVars;
20 function getTypographyControl() { return _TypographyControl || (_TypographyControl = window.bkbgTypographyControl); }
21 function getTypoCssVars() { return _typoCssVars || (_typoCssVars = window.bkbgTypoCssVars); }
22
23 var IP = function () { return window.bkbgIconPicker; };
24
25 var LAYOUT_OPTIONS = [
26 { label: __('Horizontal (left→right)', 'blockenberg'), value: 'horizontal' },
27 { label: __('Vertical (top→bottom)', 'blockenberg'), value: 'vertical' },
28 ];
29 var NUMBER_STYLE_OPTIONS = [
30 { label: __('Circle', 'blockenberg'), value: 'circle' },
31 { label: __('Square', 'blockenberg'), value: 'square' },
32 { label: __('Plain', 'blockenberg'), value: 'plain' },
33 { label: __('Outlined', 'blockenberg'), value: 'outlined' },
34 ];
35 var CONNECTOR_OPTIONS = [
36 { label: __('Solid line', 'blockenberg'), value: 'line' },
37 { label: __('Dashed', 'blockenberg'), value: 'dashed' },
38 { label: __('Dotted', 'blockenberg'), value: 'dotted' },
39 { label: __('Arrow', 'blockenberg'), value: 'arrow' },
40 ];
41 var CARD_STYLE_OPTIONS = [
42 { label: __('Plain', 'blockenberg'), value: 'plain' },
43 { label: __('Card (bg)', 'blockenberg'), value: 'card' },
44 { label: __('Bordered', 'blockenberg'), value: 'bordered' },
45 { label: __('Shadow', 'blockenberg'), value: 'shadow' },
46 ];
47 var ALIGN_OPTIONS = [
48 { label: __('Left', 'blockenberg'), value: 'left' },
49 { label: __('Center', 'blockenberg'), value: 'center' },
50 ];
51
52 function makeId() { return 'hw' + Math.random().toString(36).substr(2, 6); }
53
54 function buildWrapStyle(a) {
55 var s = {
56 '--bkbg-hiw-accent': a.numberBg,
57 '--bkbg-hiw-num-color': a.numberColor,
58 '--bkbg-hiw-num-size': a.numberSize + 'px',
59 '--bkbg-hiw-num-bg-size': a.numberBgSize + 'px',
60 '--bkbg-hiw-icon-size': a.iconSize + 'px',
61 '--bkbg-hiw-connector': a.connectorColor,
62 '--bkbg-hiw-title-color': a.titleColor,
63 '--bkbg-hiw-title-size': a.titleSize + 'px',
64 '--bkbg-hiw-desc-color': a.descColor,
65 '--bkbg-hiw-desc-size': a.descSize + 'px',
66 '--bkbg-hiw-card-bg': a.cardBg,
67 '--bkbg-hiw-card-border': a.cardBorderColor,
68 '--bkbg-hiw-card-radius': a.cardRadius + 'px',
69 '--bkbg-hiw-card-pad': a.cardPadding + 'px',
70 '--bkbg-hiw-gap': a.gap + 'px',
71 '--bkbg-hiw-text-align': a.textAlign,
72 paddingTop: a.paddingTop + 'px',
73 paddingBottom: a.paddingBottom + 'px',
74 backgroundColor: a.bgColor || undefined,
75 };
76 var _tv = getTypoCssVars();
77 if (_tv) {
78 Object.assign(s, _tv(a.titleTypo || {}, '--bkbg-hiw-tt-'));
79 Object.assign(s, _tv(a.descTypo || {}, '--bkbg-hiw-desc-'));
80 }
81 if (a.titleSize && a.titleSize !== 18) s['--bkbg-hiw-tt-sz'] = a.titleSize + 'px';
82 if (a.titleFontWeight && a.titleFontWeight !== '700') s['--bkbg-hiw-tt-fw'] = a.titleFontWeight;
83 if (a.titleLineHeight && a.titleLineHeight !== 1.3) s['--bkbg-hiw-tt-lh'] = String(a.titleLineHeight);
84 if (a.descSize && a.descSize !== 14) s['--bkbg-hiw-desc-sz'] = a.descSize + 'px';
85 if (a.descFontWeight && a.descFontWeight !== '400') s['--bkbg-hiw-desc-fw'] = a.descFontWeight;
86 if (a.descLineHeight && a.descLineHeight !== 1.6) s['--bkbg-hiw-desc-lh'] = String(a.descLineHeight);
87 return s;
88 }
89
90 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
91 var isOpen = openKey === key;
92 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
93 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
94 el('div', { style: { position: 'relative', flexShrink: 0 } },
95 el('button', { type: 'button', title: value || 'default', onClick: function () { setOpenKey(isOpen ? null : key); },
96 style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#cccccc' }
97 }),
98 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
99 el('div', { style: { padding: '8px' } },
100 el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange })
101 )
102 )
103 )
104 );
105 }
106
107 /* ── Step card component ─────────────────────────────────────────────── */
108 function StepCard(props) {
109 var step = props.step;
110 var idx = props.idx;
111 var a = props.a;
112 var isHoriz = a.layout === 'horizontal';
113
114 var numStyle = {
115 width: a.numberBgSize + 'px', height: a.numberBgSize + 'px',
116 borderRadius: a.numberStyle === 'circle' ? '50%' : a.numberStyle === 'square' ? a.cardRadius + 'px' : '0',
117 background: a.numberStyle === 'plain' || a.numberStyle === 'outlined' ? 'transparent' : a.numberBg,
118 border: a.numberStyle === 'outlined' ? '2px solid ' + a.numberBg : 'none',
119 color: a.numberStyle === 'plain' || a.numberStyle === 'outlined' ? a.numberBg : a.numberColor,
120 display: 'flex', alignItems: 'center', justifyContent: 'center',
121 fontSize: a.numberSize + 'px', fontWeight: 800, flexShrink: 0
122 };
123
124 var cardStyle = {
125 flex: isHoriz ? '1 1 0' : undefined,
126 background: a.cardStyle === 'card' || a.cardStyle === 'shadow' ? a.cardBg : 'transparent',
127 border: a.cardStyle === 'bordered' ? '1.5px solid ' + a.cardBorderColor : 'none',
128 borderRadius: a.cardStyle !== 'plain' ? a.cardRadius + 'px' : '0',
129 boxShadow: a.cardStyle === 'shadow' ? '0 4px 16px rgba(0,0,0,0.09)' : 'none',
130 padding: a.cardStyle !== 'plain' ? a.cardPadding + 'px' : '0',
131 display: 'flex', flexDirection: 'column', alignItems: a.textAlign === 'center' ? 'center' : 'flex-start',
132 textAlign: a.textAlign,
133 };
134
135 return el('div', { className: 'bkbg-hiw-step bkbg-hiw-step--' + a.numberStyle + (a.animate ? ' bkbg-hiw-anim' : ''), style: cardStyle },
136 el('div', { style: numStyle }, String(idx + 1).padStart(2, '0')),
137 a.showIcon && step.icon && el('div', { className: 'bkbg-hiw-icon', style: { fontSize: a.iconSize + 'px', lineHeight: 1, margin: '12px 0 6px' } },
138 (step.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(step.iconType, step.icon, step.iconDashicon, step.iconImageUrl, step.iconDashiconColor) : step.icon
139 ),
140 el(RichText, { tagName: 'h3', value: step.title, onChange: props.onTitleChange, placeholder: __('Step title…', 'blockenberg'), className: 'bkbg-hiw-title', style: { color: a.titleColor, margin: '12px 0 6px' } }),
141 el(RichText, { tagName: 'p', value: step.description, onChange: props.onDescChange, placeholder: __('Describe this step…', 'blockenberg'), className: 'bkbg-hiw-desc', style: { color: a.descColor, margin: 0 } })
142 );
143 }
144
145 /* ── Connector ───────────────────────────────────────────────────────── */
146 function Connector(props) {
147 var a = props.a;
148 var isHoriz = a.layout === 'horizontal';
149 var borderStyle = a.connectorStyle === 'line' ? 'solid' : a.connectorStyle === 'dashed' ? 'dashed' : a.connectorStyle === 'dotted' ? 'dotted' : 'solid';
150
151 if (isHoriz) {
152 return el('div', { className: 'bkbg-hiw-connector', style: { flex: '0 0 40px', alignSelf: 'flex-start', marginTop: (a.numberBgSize / 2) + 'px', borderTop: '2px ' + borderStyle + ' ' + a.connectorColor } });
153 }
154 return el('div', { className: 'bkbg-hiw-connector bkbg-hiw-connector--vert', style: { width: '2px', height: '32px', background: a.connectorColor, margin: '0 auto', borderLeft: '2px ' + borderStyle + ' ' + a.connectorColor } });
155 }
156
157 /* ── Register ────────────────────────────────────────────────────────── */
158 registerBlockType('blockenberg/how-it-works', {
159 title: __('How It Works', 'blockenberg'),
160 icon: 'list-view',
161 category: 'bkbg-marketing',
162
163 edit: function (props) {
164 var a = props.attributes;
165 var setAttributes = props.setAttributes;
166
167 var openColorKeyState = useState(null);
168 var openColorKey = openColorKeyState[0];
169 var setOpenColorKey = openColorKeyState[1];
170
171 var blockProps = useBlockProps({ style: buildWrapStyle(a) });
172
173 function cc(key, label, attrKey) {
174 return renderColorControl(key, label, a[attrKey], function (val) {
175 var upd = {}; upd[attrKey] = val; setAttributes(upd);
176 }, openColorKey, setOpenColorKey);
177 }
178
179 function updateStep(id, key, val) {
180 setAttributes({ steps: a.steps.map(function (s) { if (s.id !== id) return s; var u = Object.assign({}, s); u[key] = val; return u; }) });
181 }
182 function addStep() {
183 setAttributes({ steps: a.steps.concat([{ id: makeId(), icon: '', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '', title: 'New Step', description: 'Describe this step.' }]) });
184 }
185 function removeStep(id) {
186 if (a.steps.length <= 1) return;
187 setAttributes({ steps: a.steps.filter(function (s) { return s.id !== id; }) });
188 }
189
190 var isHoriz = a.layout === 'horizontal';
191
192 return el(Fragment, null,
193 el(InspectorControls, null,
194 /* Layout */
195 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: true },
196 el(SelectControl, { label: __('Direction', 'blockenberg'), value: a.layout, options: LAYOUT_OPTIONS, onChange: function (v) { setAttributes({ layout: v }); } }),
197 el(SelectControl, { label: __('Number style', 'blockenberg'), value: a.numberStyle, options: NUMBER_STYLE_OPTIONS, onChange: function (v) { setAttributes({ numberStyle: v }); } }),
198 el(SelectControl, { label: __('Card style', 'blockenberg'), value: a.cardStyle, options: CARD_STYLE_OPTIONS, onChange: function (v) { setAttributes({ cardStyle: v }); } }),
199 el(SelectControl, { label: __('Text align', 'blockenberg'), value: a.textAlign, options: ALIGN_OPTIONS, onChange: function (v) { setAttributes({ textAlign: v }); } }),
200 el(RangeControl, { label: __('Gap (px)', 'blockenberg'), value: a.gap, min: 16, max: 80, onChange: function (v) { setAttributes({ gap: v }); } }),
201 a.cardStyle !== 'plain' && el(RangeControl, { label: __('Card padding (px)', 'blockenberg'), value: a.cardPadding, min: 12, max: 56, onChange: function (v) { setAttributes({ cardPadding: v }); } }),
202 a.cardStyle !== 'plain' && el(RangeControl, { label: __('Card radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 32, onChange: function (v) { setAttributes({ cardRadius: v }); } }),
203 el(ToggleControl, { label: __('Show connector', 'blockenberg'), checked: a.showConnector, onChange: function (v) { setAttributes({ showConnector: v }); }, __nextHasNoMarginBottom: true }),
204 a.showConnector && el(SelectControl, { label: __('Connector style', 'blockenberg'), value: a.connectorStyle, options: CONNECTOR_OPTIONS, onChange: function (v) { setAttributes({ connectorStyle: v }); } }),
205 el(ToggleControl, { label: __('Show emoji icon', 'blockenberg'), checked: a.showIcon, onChange: function (v) { setAttributes({ showIcon: v }); }, __nextHasNoMarginBottom: true }),
206 el(ToggleControl, { label: __('Animate on scroll', 'blockenberg'), checked: a.animate, onChange: function (v) { setAttributes({ animate: v }); }, __nextHasNoMarginBottom: true })
207 ),
208 /* Typography */
209 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
210 el(RangeControl, { label: __('Number size (px)', 'blockenberg'), value: a.numberSize, min: 14, max: 40, onChange: function (v) { setAttributes({ numberSize: v }); } }),
211 el(RangeControl, { label: __('Number badge size (px)', 'blockenberg'), value: a.numberBgSize, min: 36, max: 88, onChange: function (v) { setAttributes({ numberBgSize: v }); } }),
212 el(RangeControl, { label: __('Icon size (px)', 'blockenberg'), value: a.iconSize, min: 20, max: 64, onChange: function (v) { setAttributes({ iconSize: v }); } }),
213 getTypographyControl() && el(getTypographyControl(), { label: __('Step Title', 'blockenberg'), typo: a.titleTypo || {}, onChange: function(v){ setAttributes({ titleTypo: v }); } }),
214 getTypographyControl() && el(getTypographyControl(), { label: __('Step Description', 'blockenberg'), typo: a.descTypo || {}, onChange: function(v){ setAttributes({ descTypo: v }); } })
215 ),
216 /* Colors */
217 el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false },
218 cc('numberBg', __('Number background', 'blockenberg'), 'numberBg'),
219 cc('numberColor', __('Number text', 'blockenberg'), 'numberColor'),
220 cc('connectorColor',__('Connector', 'blockenberg'), 'connectorColor'),
221 cc('titleColor', __('Step title', 'blockenberg'), 'titleColor'),
222 cc('descColor', __('Step description', 'blockenberg'), 'descColor'),
223 cc('cardBg', __('Card background', 'blockenberg'), 'cardBg'),
224 cc('cardBorderColor',__('Card border', 'blockenberg'), 'cardBorderColor'),
225 cc('bgColor', __('Section background', 'blockenberg'), 'bgColor')
226 ),
227 /* Spacing */
228 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
229 el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
230 el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
231 ),
232 /* Steps */
233 el(PanelBody, { title: __('Steps', 'blockenberg'), initialOpen: false },
234 a.steps.map(function (step, idx) {
235 return el(PanelBody, { key: step.id, title: (idx + 1) + '. ' + (step.title || __('Step', 'blockenberg')), initialOpen: false },
236 el(IP().IconPickerControl, { iconType: step.iconType || 'custom-char', customChar: step.icon, dashicon: step.iconDashicon || '', imageUrl: step.iconImageUrl || '',
237 onChangeType: function (v) { updateStep(step.id, 'iconType', v); }, onChangeChar: function (v) { updateStep(step.id, 'icon', v); },
238 onChangeDashicon: function (v) { updateStep(step.id, 'iconDashicon', v); }, onChangeImageUrl: function (v) { updateStep(step.id, 'iconImageUrl', v); } }),
239 el(TextControl, { label: __('Title', 'blockenberg'), value: step.title, onChange: function (v) { updateStep(step.id, 'title', v); } }),
240 el(wp.components.TextareaControl, { label: __('Description', 'blockenberg'), value: step.description, rows: 3, onChange: function (v) { updateStep(step.id, 'description', v); } }),
241 a.steps.length > 1 && el(Button, { onClick: function () { removeStep(step.id); }, variant: 'tertiary', isDestructive: true, size: 'compact' }, __('Remove step', 'blockenberg'))
242 );
243 }),
244 el(Button, { onClick: addStep, variant: 'primary', style: { marginTop: '8px' } }, __('+ Add Step', 'blockenberg'))
245 )
246 ),
247
248 /* Canvas */
249 el('div', blockProps,
250 el('div', {
251 className: 'bkbg-hiw-steps bkbg-hiw--' + a.layout,
252 style: {
253 display: 'flex',
254 flexDirection: isHoriz ? 'row' : 'column',
255 alignItems: isHoriz ? 'flex-start' : 'center',
256 gap: isHoriz ? '0' : a.gap + 'px',
257 }
258 },
259 a.steps.map(function (step, idx) {
260 return el(Fragment, { key: step.id },
261 el(StepCard, {
262 step: step, idx: idx, a: a,
263 onTitleChange: function (v) { updateStep(step.id, 'title', v); },
264 onDescChange: function (v) { updateStep(step.id, 'description', v); },
265 }),
266 idx < a.steps.length - 1 && a.showConnector && el(Connector, { a: a })
267 );
268 })
269 )
270 )
271 );
272 },
273
274 save: function (props) {
275 var a = props.attributes;
276 var isHoriz = a.layout === 'horizontal';
277
278 function numStyle(idx) {
279 return {
280 width: a.numberBgSize + 'px', height: a.numberBgSize + 'px',
281 borderRadius: a.numberStyle === 'circle' ? '50%' : a.numberStyle === 'square' ? a.cardRadius + 'px' : '0',
282 background: a.numberStyle === 'plain' || a.numberStyle === 'outlined' ? 'transparent' : a.numberBg,
283 border: a.numberStyle === 'outlined' ? '2px solid ' + a.numberBg : 'none',
284 color: a.numberStyle === 'plain' || a.numberStyle === 'outlined' ? a.numberBg : a.numberColor,
285 display: 'flex', alignItems: 'center', justifyContent: 'center',
286 fontSize: a.numberSize + 'px', fontWeight: 800, flexShrink: 0
287 };
288 }
289
290 function cardStyle() {
291 return {
292 flex: isHoriz ? '1 1 0' : undefined,
293 background: a.cardStyle === 'card' || a.cardStyle === 'shadow' ? a.cardBg : 'transparent',
294 border: a.cardStyle === 'bordered' ? '1.5px solid ' + a.cardBorderColor : 'none',
295 borderRadius: a.cardStyle !== 'plain' ? a.cardRadius + 'px' : '0',
296 boxShadow: a.cardStyle === 'shadow' ? '0 4px 16px rgba(0,0,0,0.09)' : 'none',
297 padding: a.cardStyle !== 'plain' ? a.cardPadding + 'px' : '0',
298 display: 'flex', flexDirection: 'column', alignItems: a.textAlign === 'center' ? 'center' : 'flex-start',
299 textAlign: a.textAlign,
300 };
301 }
302
303 var borderStyle = a.connectorStyle === 'line' ? 'solid' : a.connectorStyle === 'dashed' ? 'dashed' : a.connectorStyle === 'dotted' ? 'dotted' : 'solid';
304
305 return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-hiw-wrapper', style: buildWrapStyle(a) }),
306 el('div', {
307 className: 'bkbg-hiw-steps bkbg-hiw--' + a.layout,
308 style: { display: 'flex', flexDirection: isHoriz ? 'row' : 'column', alignItems: isHoriz ? 'flex-start' : 'center', gap: isHoriz ? '0' : a.gap + 'px' }
309 },
310 a.steps.map(function (step, idx) {
311 return el(Fragment, { key: step.id },
312 el('div', { className: 'bkbg-hiw-step bkbg-hiw-step--' + a.numberStyle + (a.animate ? ' bkbg-hiw-anim' : ''), style: cardStyle() },
313 el('div', { className: 'bkbg-hiw-number', style: numStyle(idx) }, String(idx + 1).padStart(2, '0')),
314 a.showIcon && step.icon && el('div', { className: 'bkbg-hiw-icon', style: { fontSize: a.iconSize + 'px', lineHeight: 1, margin: '12px 0 6px' } },
315 (step.iconType || 'custom-char') !== 'custom-char' ? IP().buildSaveIcon(step.iconType, step.icon, step.iconDashicon, step.iconImageUrl, step.iconDashiconColor) : step.icon
316 ),
317 el(RichText.Content, { tagName: 'h3', value: step.title, className: 'bkbg-hiw-title', style: { color: a.titleColor } }),
318 el(RichText.Content, { tagName: 'p', value: step.description, className: 'bkbg-hiw-desc', style: { color: a.descColor } })
319 ),
320 idx < a.steps.length - 1 && a.showConnector && (
321 isHoriz
322 ? el('div', { className: 'bkbg-hiw-connector', style: { flex: '0 0 ' + a.gap + 'px', alignSelf: 'flex-start', marginTop: (a.numberBgSize / 2) + 'px', borderTop: '2px ' + borderStyle + ' ' + a.connectorColor } })
323 : el('div', { className: 'bkbg-hiw-connector bkbg-hiw-connector--vert', style: { width: '2px', height: '32px', background: a.connectorColor, margin: '0 auto' } })
324 )
325 );
326 })
327 )
328 );
329 }
330 });
331 }() );
332