PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.11
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.11
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 / interactive-steps / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.11, at blocks/interactive-steps/index.js

322 lines 18.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 registerBlockType = wp.blocks.registerBlockType;
6 var useBlockProps = wp.blockEditor.useBlockProps;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var RichText = wp.blockEditor.RichText;
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 _TypographyControl, _typoCssVars;
19 function getTypographyControl() { return _TypographyControl || (_TypographyControl = window.bkbgTypographyControl); }
20 function getTypoCssVars() { return _typoCssVars || (_typoCssVars = window.bkbgTypoCssVars); }
21 var IP = function () { return window.bkbgIconPicker; };
22
23 function StepBubble(idx, step, a, isActive, isDone, onClick) {
24 var bg = isActive ? a.activeBg : isDone ? a.doneBg : a.inactiveBg;
25 var color = isActive ? a.activeColor : isDone ? a.doneColor : a.inactiveColor;
26 return el('button', {
27 key: idx,
28 onClick: onClick,
29 className: 'bkbg-is-bubble' + (isActive ? ' bkbg-is-active' : '') + (isDone ? ' bkbg-is-done' : ''),
30 style: {
31 width: a.stepSize + 'px',
32 height: a.stepSize + 'px',
33 borderRadius: '50%',
34 background: bg,
35 color: color,
36 border: 'none',
37 cursor: 'pointer',
38 fontSize: isDone ? '20px' : (a.stepFontSize || 14) + 'px',
39 fontWeight: 700,
40 display: 'flex',
41 alignItems: 'center',
42 justifyContent: 'center',
43 flexShrink: 0,
44 transition: 'background 0.3s, transform 0.2s',
45 transform: isActive ? 'scale(1.12)' : 'scale(1)',
46 boxShadow: isActive ? '0 4px 16px rgba(99,102,241,0.4)' : 'none'
47 }
48 }, isDone ? '' : ((step.iconType || 'custom-char') !== 'custom-char' && IP() ? IP().buildEditorIcon(step.iconType, step.icon, step.iconDashicon, step.iconImageUrl, step.iconDashiconColor) : (step.icon || (idx + 1))));
49 }
50
51 registerBlockType('blockenberg/interactive-steps', {
52 title: __('Interactive Steps'),
53 icon: 'editor-ol',
54 category: 'bkbg-interactive',
55
56 edit: function (props) {
57 var attr = props.attributes;
58 var setAttr = props.setAttributes;
59 var active = useState(attr.initialStep || 0);
60 var activeIdx = active[0];
61 var setActive = active[1];
62 var bp = useBlockProps((function () {
63 var _tv = getTypoCssVars();
64 var s = {};
65 Object.assign(s, _tv(attr.headingTypo, '--bkbg-is-h-'));
66 Object.assign(s, _tv(attr.bodyTypo, '--bkbg-is-bd-'));
67 return { className: 'bkbg-is-wrap', style: s };
68 })());
69
70 function updateStep(idx, field, val) {
71 var steps = attr.steps.map(function (s, i) {
72 return i === idx ? Object.assign({}, s, { [field]: val }) : s;
73 });
74 setAttr({ steps: steps });
75 }
76 function addStep() {
77 setAttr({ steps: attr.steps.concat([{
78 title: 'New Step', icon: '',
79 iconType: 'custom-char', iconDashicon: '', iconImageUrl: '',
80 heading: 'Step heading', body: 'Describe this step.'
81 }]) });
82 }
83 function removeStep(idx) {
84 if (attr.steps.length <= 2) return;
85 setAttr({ steps: attr.steps.filter(function (_, i) { return i !== idx; }) });
86 if (activeIdx >= attr.steps.length - 1) setActive(attr.steps.length - 2);
87 }
88
89 var total = attr.steps.length;
90
91 var inspector = el(InspectorControls, {},
92 /* Steps content */
93 el(PanelBody, { title: __('Steps'), initialOpen: true },
94 attr.steps.map(function (step, idx) {
95 return el(PanelBody, { key: idx, title: (idx + 1) + '. ' + (step.title || 'Step'), initialOpen: false },
96 el(TextControl, { label: __('Step Title (nav label)'), value: step.title || '',
97 onChange: function (v) { updateStep(idx, 'title', v); },
98 __nextHasNoMarginBottom: true }),
99 IP() && el(IP().IconPickerControl, {
100 iconType: step.iconType || 'custom-char',
101 customChar: step.icon || '',
102 dashicon: step.iconDashicon || '',
103 imageUrl: step.iconImageUrl || '',
104 onChangeType: function (v) { updateStep(idx, 'iconType', v); },
105 onChangeChar: function (v) { updateStep(idx, 'icon', v); },
106 onChangeDashicon: function (v) { updateStep(idx, 'iconDashicon', v); },
107 onChangeImageUrl: function (v) { updateStep(idx, 'iconImageUrl', v); }
108 }),
109 el(TextControl, { label: __('Panel Heading'), value: step.heading || '',
110 onChange: function (v) { updateStep(idx, 'heading', v); },
111 __nextHasNoMarginBottom: true }),
112 el(TextareaControl, { label: __('Panel Body'), value: step.body || '', rows: 4,
113 onChange: function (v) { updateStep(idx, 'body', v); },
114 __nextHasNoMarginBottom: true }),
115 attr.steps.length > 2 && el(Button, {
116 isDestructive: true, variant: 'secondary',
117 onClick: function () { removeStep(idx); },
118 style: { marginTop: '8px' }
119 }, __('Remove Step'))
120 );
121 }),
122 el(Button, { variant: 'primary', onClick: addStep,
123 style: { marginTop: '8px', width: '100%' }
124 }, __('+ Add Step'))
125 ),
126
127 /* Layout */
128 el(PanelBody, { title: __('Layout'), initialOpen: false },
129 el(SelectControl, {
130 label: __('Layout Direction'),
131 value: attr.layout,
132 options: [
133 { label: __('Horizontal'), value: 'horizontal' },
134 { label: __('Vertical'), value: 'vertical' }
135 ],
136 onChange: function (v) { setAttr({ layout: v }); },
137 __nextHasNoMarginBottom: true
138 }),
139 el(ToggleControl, { label: __('Show Connector Line'), checked: attr.showConnector,
140 onChange: function (v) { setAttr({ showConnector: v }); },
141 __nextHasNoMarginBottom: true }),
142 el(ToggleControl, { label: __('Animate Content'), checked: attr.animateContent,
143 onChange: function (v) { setAttr({ animateContent: v }); },
144 __nextHasNoMarginBottom: true }),
145 el(RangeControl, { label: __('Bubble Size (px)'), value: attr.stepSize,
146 min: 32, max: 80,
147 onChange: function (v) { setAttr({ stepSize: v }); },
148 __nextHasNoMarginBottom: true }),
149 el(RangeControl, { label: __('Content Radius (px)'), value: attr.contentRadius,
150 min: 0, max: 32,
151 onChange: function (v) { setAttr({ contentRadius: v }); },
152 __nextHasNoMarginBottom: true }),
153 el(RangeControl, { label: __('Content Padding (px)'), value: attr.contentPadding,
154 min: 12, max: 64,
155 onChange: function (v) { setAttr({ contentPadding: v }); },
156 __nextHasNoMarginBottom: true }),
157 el(RangeControl, { label: __('Connector Height (px)'), value: attr.connectorHeight,
158 min: 1, max: 8,
159 onChange: function (v) { setAttr({ connectorHeight: v }); },
160 __nextHasNoMarginBottom: true })
161 ),
162
163 /* Colors */
164
165 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
166 el(getTypographyControl(), { label: 'Heading', value: attr.headingTypo, onChange: function (v) { setAttr({ headingTypo: v }); } }),
167 el(getTypographyControl(), { label: 'Body', value: attr.bodyTypo, onChange: function (v) { setAttr({ bodyTypo: v }); } }),
168 el(RangeControl, { label: __('Step Font Size (px)', 'blockenberg'), value: attr.stepFontSize, min: 10, max: 24, __nextHasNoMarginBottom: true, onChange: function (v) { setAttr({ stepFontSize: v }); } })
169 ),
170 el(PanelColorSettings, {
171 title: __('Colors'), initialOpen: false,
172 colorSettings: [
173 { label: __('Active Bubble BG'), value: attr.activeBg,
174 onChange: function (v) { setAttr({ activeBg: v || '#6366f1' }); } },
175 { label: __('Active Bubble Text'), value: attr.activeColor,
176 onChange: function (v) { setAttr({ activeColor: v || '#ffffff' }); } },
177 { label: __('Inactive Bubble BG'), value: attr.inactiveBg,
178 onChange: function (v) { setAttr({ inactiveBg: v || '#e5e7eb' }); } },
179 { label: __('Inactive Bubble Text'), value: attr.inactiveColor,
180 onChange: function (v) { setAttr({ inactiveColor: v || '#64748b' }); } },
181 { label: __('Done Bubble BG'), value: attr.doneBg,
182 onChange: function (v) { setAttr({ doneBg: v || '#10b981' }); } },
183 { label: __('Done Bubble Text'), value: attr.doneColor,
184 onChange: function (v) { setAttr({ doneColor: v || '#ffffff' }); } },
185 { label: __('Connector Default'), value: attr.connectorColor,
186 onChange: function (v) { setAttr({ connectorColor: v || '#e5e7eb' }); } },
187 { label: __('Connector Done'), value: attr.connectorDone,
188 onChange: function (v) { setAttr({ connectorDone: v || '#10b981' }); } },
189 { label: __('Content Panel BG'), value: attr.contentBg,
190 onChange: function (v) { setAttr({ contentBg: v || '#f8fafc' }); } },
191 { label: __('Content Panel Border'), value: attr.contentBorder,
192 onChange: function (v) { setAttr({ contentBorder: v || '#e5e7eb' }); } },
193 { label: __('Heading Color'), value: attr.headingColor,
194 onChange: function (v) { setAttr({ headingColor: v || '#0f172a' }); } },
195 { label: __('Body Color'), value: attr.bodyColor,
196 onChange: function (v) { setAttr({ bodyColor: v || '#475569' }); } },
197 { label: __('Label Color'), value: attr.labelColor,
198 onChange: function (v) { setAttr({ labelColor: v || '#0f172a' }); } },
199 { label: __('Section BG'), value: attr.sectionBg,
200 onChange: function (v) { setAttr({ sectionBg: v || 'transparent' }); } }
201 ]
202 })
203 );
204
205 var currentStep = attr.steps[activeIdx] || attr.steps[0];
206 var isHoriz = attr.layout !== 'vertical';
207
208 /* ── Nav row / column ─────────────────────────────────── */
209 var navEl = el('div', {
210 className: 'bkbg-is-nav',
211 style: {
212 display: isHoriz ? 'flex' : 'flex',
213 flexDirection: isHoriz ? 'row' : 'column',
214 alignItems: isHoriz ? 'center' : 'flex-start',
215 gap: isHoriz ? '0' : '8px',
216 marginBottom: isHoriz ? '32px' : '0',
217 marginRight: isHoriz ? '0' : '32px',
218 flexShrink: 0
219 }
220 },
221 attr.steps.map(function (step, idx) {
222 var isActive = idx === activeIdx;
223 var isDone = idx < activeIdx;
224 return el(wp.element.Fragment, { key: idx },
225 /* connector */
226 idx > 0 && attr.showConnector !== false && el('div', {
227 className: 'bkbg-is-connector',
228 style: {
229 flex: isHoriz ? 1 : 'none',
230 height: isHoriz ? attr.connectorHeight + 'px' : '24px',
231 width: isHoriz ? 'auto' : attr.connectorHeight + 'px',
232 background: idx <= activeIdx ? (attr.connectorDone || '#10b981') : (attr.connectorColor || '#e5e7eb'),
233 margin: isHoriz ? '0' : '0 0 0 ' + (attr.stepSize / 2) + 'px',
234 alignSelf: isHoriz ? 'center' : 'auto',
235 minWidth: isHoriz ? '24px' : 'auto',
236 transition: 'background 0.4s ease'
237 }
238 }),
239 el('div', { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '6px' } },
240 StepBubble(idx, step, attr, isActive, isDone, function () { setActive(idx); }),
241 el('div', {
242 style: {
243 fontSize: (attr.stepFontSize || 14) + 'px',
244 fontWeight: isActive ? 700 : 500,
245 color: isActive ? (attr.activeBg || '#6366f1') : (attr.labelColor || '#0f172a'),
246 whiteSpace: 'nowrap',
247 textAlign: 'center',
248 transition: 'color 0.3s'
249 }
250 }, step.title || ('Step ' + (idx + 1)))
251 )
252 );
253 })
254 );
255
256 /* ── Content panel ───────────────────────────────────── */
257 var panel = el('div', {
258 className: 'bkbg-is-panel',
259 style: {
260 flex: 1,
261 background: attr.contentBg || '#f8fafc',
262 border: '1px solid ' + (attr.contentBorder || '#e5e7eb'),
263 borderRadius: attr.contentRadius + 'px',
264 padding: attr.contentPadding + 'px'
265 }
266 },
267 el('div', {
268 className: 'bkbg-is-heading',
269 style: { color: attr.headingColor || '#0f172a' }
270 }, currentStep.heading || ''),
271 el('div', {
272 className: 'bkbg-is-body',
273 style: { color: attr.bodyColor || '#475569' }
274 }, currentStep.body || ''),
275 /* navigation buttons */
276 el('div', { style: { display: 'flex', gap: '12px', marginTop: '24px' } },
277 activeIdx > 0 && el('button', {
278 onClick: function () { setActive(activeIdx - 1); },
279 style: { padding: '10px 24px', borderRadius: '8px',
280 border: '1px solid ' + (attr.contentBorder || '#e5e7eb'),
281 background: 'transparent', cursor: 'pointer', fontSize: '14px',
282 color: attr.bodyColor || '#475569', fontWeight: 600 }
283 }, '← Previous'),
284 activeIdx < total - 1 && el('button', {
285 onClick: function () { setActive(activeIdx + 1); },
286 style: { padding: '10px 24px', borderRadius: '8px',
287 border: 'none', background: attr.activeBg || '#6366f1',
288 color: attr.activeColor || '#ffffff', cursor: 'pointer',
289 fontSize: '14px', fontWeight: 700 }
290 }, 'Next →')
291 )
292 );
293
294 return el(wp.element.Fragment, {}, inspector,
295 el('div', bp,
296 el('div', {
297 className: 'bkbg-is-root',
298 style: {
299 background: attr.sectionBg || 'transparent',
300 display: 'flex',
301 flexDirection: isHoriz ? 'column' : 'row',
302 gap: '0'
303 }
304 }, navEl, panel)
305 )
306 );
307 },
308
309 save: function (props) {
310 var attr = props.attributes;
311 var _tv = getTypoCssVars();
312 var s = {};
313 Object.assign(s, _tv(attr.headingTypo, '--bkbg-is-h-'));
314 Object.assign(s, _tv(attr.bodyTypo, '--bkbg-is-bd-'));
315 var bp = useBlockProps.save({ style: s });
316 return el('div', bp,
317 el('div', { className: 'bkbg-is-app', 'data-opts': JSON.stringify(attr) })
318 );
319 }
320 });
321 }() );
322