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 / story-section / index.js

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

444 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 registerBlockType = wp.blocks.registerBlockType;
6 var useBlockProps = wp.blockEditor.useBlockProps;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var MediaUpload = wp.blockEditor.MediaUpload;
9 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
10 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
11 var PanelBody = wp.components.PanelBody;
12 var TextControl = wp.components.TextControl;
13 var TextareaControl = wp.components.TextareaControl;
14 var ToggleControl = wp.components.ToggleControl;
15 var RangeControl = wp.components.RangeControl;
16 var SelectControl = wp.components.SelectControl;
17 var Button = wp.components.Button;
18 var __ = wp.i18n.__;
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 updateMilestone(list, idx, field, val) {
25 return list.map(function (m, i) {
26 if (i !== idx) return m;
27 var u = {}; u[field] = val;
28 return Object.assign({}, m, u);
29 });
30 }
31
32 // ─── StoryPreview ────────────────────────────────────────────────────────────
33 function StoryPreview(props) {
34 var a = props.attributes;
35 var setAttributes = props.setAttributes;
36 var openMedia = props.openMedia;
37
38 var isPhotoLeft = a.layout === 'photo-left';
39 var isCentered = a.layout === 'centered';
40
41 // photo column
42 function PhotoCol() {
43 return el('div', { className: 'bkbg-stry-photo-col' },
44 el('div', {
45 className: 'bkbg-stry-photo-wrap',
46 style: { borderRadius: a.photoBorderRadius + 'px' }
47 },
48 a.founderPhotoUrl
49 ? el('img', {
50 src: a.founderPhotoUrl,
51 alt: a.founderName,
52 className: 'bkbg-stry-photo',
53 style: { borderRadius: a.photoBorderRadius + 'px' }
54 })
55 : el('div', {
56 className: 'bkbg-stry-photo-placeholder',
57 style: { borderRadius: a.photoBorderRadius + 'px', borderColor: a.accentColor }
58 },
59 el('div', {
60 className: 'bkbg-stry-photo-btn',
61 style: { color: a.accentColor },
62 onClick: openMedia
63 }, '+ Add Photo')
64 ),
65 a.founderPhotoUrl && a.photoCaption && el('div', {
66 className: 'bkbg-stry-founder-caption',
67 style: { color: a.subColor }
68 },
69 el('strong', { style: { color: a.headlineColor } }, a.founderName),
70 a.founderTitle && el('span', null, ', ' + a.founderTitle)
71 )
72 )
73 );
74 }
75
76 // content column
77 function ContentCol() {
78 return el('div', { className: 'bkbg-stry-content-col' },
79 el('h2', {
80 className: 'bkbg-stry-headline',
81 style: { color: a.headlineColor },
82 contentEditable: true,
83 suppressContentEditableWarning: true,
84 onBlur: function (e) { setAttributes({ headline: e.target.textContent }); }
85 }, a.headline),
86 el('p', {
87 className: 'bkbg-stry-subheadline',
88 style: { color: a.subColor },
89 contentEditable: true,
90 suppressContentEditableWarning: true,
91 onBlur: function (e) { setAttributes({ subheadline: e.target.textContent }); }
92 }, a.subheadline),
93 el('p', {
94 className: 'bkbg-stry-body',
95 style: { color: a.bodyColor },
96 contentEditable: true,
97 suppressContentEditableWarning: true,
98 onBlur: function (e) { setAttributes({ bodyText: e.target.textContent }); }
99 }, a.bodyText),
100 a.showPullQuote && el('blockquote', {
101 className: 'bkbg-stry-quote',
102 style: {
103 color: a.quoteColor,
104 borderLeftColor: a.accentColor
105 },
106 contentEditable: true,
107 suppressContentEditableWarning: true,
108 onBlur: function (e) { setAttributes({ pullQuote: e.target.textContent }); }
109 }, a.pullQuote),
110 a.showCta && el('div', { className: 'bkbg-stry-cta-row' },
111 el('span', {
112 className: 'bkbg-stry-cta-btn',
113 style: {
114 background: a.ctaBg,
115 color: a.ctaColor,
116 borderRadius: a.borderRadius + 'px'
117 },
118 contentEditable: true,
119 suppressContentEditableWarning: true,
120 onBlur: function (e) { setAttributes({ ctaLabel: e.target.textContent }); }
121 }, a.ctaLabel)
122 )
123 );
124 }
125
126 // milestones
127 function MilestonesSection() {
128 if (!a.showMilestones) return null;
129 return el('div', { className: 'bkbg-stry-milestones' },
130 el('div', { className: 'bkbg-stry-milestone-line', style: { background: a.accentColor } }),
131 el('div', { className: 'bkbg-stry-milestone-list' },
132 a.milestones.map(function (m, i) {
133 return el('div', { key: i, className: 'bkbg-stry-milestone' },
134 el('div', { className: 'bkbg-stry-milestone-dot', style: { background: a.accentColor } }),
135 el('div', { className: 'bkbg-stry-milestone-year', style: { color: a.yearColor } }, m.year),
136 el('div', { className: 'bkbg-stry-milestone-title', style: { color: a.milestoneTitleColor } }, m.title),
137 el('div', { className: 'bkbg-stry-milestone-desc', style: { color: a.milestoneTextColor } }, m.description)
138 );
139 })
140 )
141 );
142 }
143
144 var mainClass = 'bkbg-stry-main bkbg-stry-layout-' + a.layout;
145
146 return el('div', { className: 'bkbg-stry-block', style: { background: a.bgColor } },
147 el('div', { className: mainClass },
148 !isCentered && a.showPhoto && (isPhotoLeft
149 ? el(Fragment, null, el(PhotoCol, null), el(ContentCol, null))
150 : el(Fragment, null, el(ContentCol, null), el(PhotoCol, null))
151 ),
152 isCentered && el(Fragment, null,
153 a.showPhoto && el(PhotoCol, null),
154 el(ContentCol, null)
155 )
156 ),
157 el(MilestonesSection, null)
158 );
159 }
160
161 // ─── MilestoneEditor ─────────────────────────────────────────────────────────
162 function MilestoneEditor(props) {
163 var milestones = props.milestones;
164 var setAttributes = props.setAttributes;
165 var accentColor = props.accentColor;
166
167 var openStates = useState(
168 milestones.map(function () { return false; })
169 );
170 var open = openStates[0];
171 var setOpen = openStates[1];
172
173 function toggle(i) {
174 setOpen(open.map(function (v, j) { return j === i ? !v : v; }));
175 }
176
177 function removeAt(i) {
178 setAttributes({ milestones: milestones.filter(function (_, j) { return j !== i; }) });
179 setOpen(open.filter(function (_, j) { return j !== i; }));
180 }
181
182 function addMilestone() {
183 var newList = milestones.concat([{ year: '2025', title: 'New Milestone', description: 'Describe this milestone.' }]);
184 setAttributes({ milestones: newList });
185 setOpen(open.concat([true]));
186 }
187
188 return el('div', null,
189 milestones.map(function (m, i) {
190 return el('div', { key: i, className: 'bkbg-stry-milestone-editor' },
191 el('div', {
192 className: 'bkbg-stry-milestone-header',
193 onClick: function () { toggle(i); },
194 style: { borderLeftColor: accentColor }
195 },
196 el('strong', null, m.year + '' + m.title),
197 el('span', null, open[i] ? '' : '')
198 ),
199 open[i] && el('div', { className: 'bkbg-stry-milestone-fields' },
200 el(TextControl, {
201 label: __('Year'),
202 value: m.year,
203 __nextHasNoMarginBottom: true,
204 onChange: function (v) { setAttributes({ milestones: updateMilestone(milestones, i, 'year', v) }); }
205 }),
206 el(TextControl, {
207 label: __('Title'),
208 value: m.title,
209 __nextHasNoMarginBottom: true,
210 onChange: function (v) { setAttributes({ milestones: updateMilestone(milestones, i, 'title', v) }); }
211 }),
212 el(TextareaControl, {
213 label: __('Description'),
214 value: m.description,
215 __nextHasNoMarginBottom: true,
216 onChange: function (v) { setAttributes({ milestones: updateMilestone(milestones, i, 'description', v) }); }
217 }),
218 el(Button, {
219 variant: 'link',
220 isDestructive: true,
221 onClick: function () { removeAt(i); }
222 }, __('Remove milestone'))
223 )
224 );
225 }),
226 el(Button, {
227 variant: 'secondary',
228 onClick: addMilestone,
229 style: { marginTop: '8px' }
230 }, __('+ Add Milestone'))
231 );
232 }
233
234 // ─── register ────────────────────────────────────────────────────────────────
235 registerBlockType('blockenberg/story-section', {
236 edit: function (props) {
237 var a = props.attributes;
238 var setAttributes = props.setAttributes;
239
240 function inspector() {
241 return el(InspectorControls, null,
242
243 el(PanelBody, { title: __('Layout'), initialOpen: true },
244 el(SelectControl, {
245 label: __('Layout'),
246 value: a.layout,
247 __nextHasNoMarginBottom: true,
248 options: [
249 { value: 'photo-left', label: 'Photo Left' },
250 { value: 'photo-right', label: 'Photo Right' },
251 { value: 'centered', label: 'Centered' }
252 ],
253 onChange: function (v) { setAttributes({ layout: v }); }
254 }),
255 el(ToggleControl, {
256 label: __('Show founder photo'),
257 checked: a.showPhoto,
258 __nextHasNoMarginBottom: true,
259 onChange: function (v) { setAttributes({ showPhoto: v }); }
260 }),
261 a.showPhoto && a.founderPhotoUrl && el(ToggleControl, {
262 label: __('Show name & title caption'),
263 checked: a.photoCaption,
264 __nextHasNoMarginBottom: true,
265 onChange: function (v) { setAttributes({ photoCaption: v }); }
266 }),
267 el(ToggleControl, {
268 label: __('Show pull quote'),
269 checked: a.showPullQuote,
270 __nextHasNoMarginBottom: true,
271 onChange: function (v) { setAttributes({ showPullQuote: v }); }
272 }),
273 el(ToggleControl, {
274 label: __('Show milestones'),
275 checked: a.showMilestones,
276 __nextHasNoMarginBottom: true,
277 onChange: function (v) { setAttributes({ showMilestones: v }); }
278 }),
279 el(ToggleControl, {
280 label: __('Show CTA button'),
281 checked: a.showCta,
282 __nextHasNoMarginBottom: true,
283 onChange: function (v) { setAttributes({ showCta: v }); }
284 })
285 ),
286
287 el(PanelBody, { title: __('Founder Info'), initialOpen: false },
288 el(TextControl, {
289 label: __('Founder / Author Name'),
290 value: a.founderName,
291 __nextHasNoMarginBottom: true,
292 onChange: function (v) { setAttributes({ founderName: v }); }
293 }),
294 el(TextControl, {
295 label: __('Title / Role'),
296 value: a.founderTitle,
297 __nextHasNoMarginBottom: true,
298 onChange: function (v) { setAttributes({ founderTitle: v }); }
299 })
300 ),
301
302 el(PanelBody, { title: __('Founder Photo'), initialOpen: false },
303 el(MediaUploadCheck, null,
304 el(MediaUpload, {
305 onSelect: function (media) {
306 setAttributes({ founderPhotoUrl: media.url, founderPhotoId: media.id });
307 },
308 allowedTypes: ['image'],
309 value: a.founderPhotoId,
310 render: function (ref) {
311 return el(Fragment, null,
312 a.founderPhotoUrl && el('img', {
313 src: a.founderPhotoUrl,
314 style: { width: '100%', borderRadius: '8px', marginBottom: '8px', display: 'block' }
315 }),
316 el(Button, {
317 variant: a.founderPhotoUrl ? 'secondary' : 'primary',
318 onClick: ref.open
319 }, a.founderPhotoUrl ? __('Replace Photo') : __('Select Photo')),
320 a.founderPhotoUrl && el(Button, {
321 variant: 'link',
322 isDestructive: true,
323 onClick: function () { setAttributes({ founderPhotoUrl: '', founderPhotoId: 0 }); },
324 style: { marginLeft: '8px' }
325 }, __('Remove'))
326 );
327 }
328 })
329 )
330 ),
331
332 a.showCta && el(PanelBody, { title: __('CTA Button'), initialOpen: false },
333 el(TextControl, {
334 label: __('Button Label'),
335 value: a.ctaLabel,
336 __nextHasNoMarginBottom: true,
337 onChange: function (v) { setAttributes({ ctaLabel: v }); }
338 }),
339 el(TextControl, {
340 label: __('Button URL'),
341 value: a.ctaUrl,
342 __nextHasNoMarginBottom: true,
343 onChange: function (v) { setAttributes({ ctaUrl: v }); }
344 }),
345 el(ToggleControl, {
346 label: __('Open in new tab'),
347 checked: a.ctaNewTab,
348 __nextHasNoMarginBottom: true,
349 onChange: function (v) { setAttributes({ ctaNewTab: v }); }
350 })
351 ),
352
353 a.showMilestones && el(PanelBody, { title: __('Milestones'), initialOpen: false },
354 el(MilestoneEditor, {
355 milestones: a.milestones,
356 setAttributes: setAttributes,
357 accentColor: a.accentColor
358 })
359 ),
360
361 el(PanelBody, { title: __('Typography'), initialOpen: false },
362 getTypoControl()({ label: __('Headline', 'blockenberg'), value: a.headlineTypo, onChange: function (v) { setAttributes({ headlineTypo: v }); } }),
363 getTypoControl()({ label: __('Subheadline', 'blockenberg'), value: a.subheadlineTypo, onChange: function (v) { setAttributes({ subheadlineTypo: v }); } }),
364 getTypoControl()({ label: __('Body', 'blockenberg'), value: a.bodyTypo, onChange: function (v) { setAttributes({ bodyTypo: v }); } }),
365 getTypoControl()({ label: __('Pull Quote', 'blockenberg'), value: a.quoteTypo, onChange: function (v) { setAttributes({ quoteTypo: v }); } })
366 ),
367
368 el(PanelBody, { title: __('Shape'), initialOpen: false },
369 el(RangeControl, {
370 label: __('Button border radius (px)'),
371 value: a.borderRadius,
372 min: 0, max: 40,
373 __nextHasNoMarginBottom: true,
374 onChange: function (v) { setAttributes({ borderRadius: v }); }
375 }),
376 el(RangeControl, {
377 label: __('Photo border radius (px)'),
378 value: a.photoBorderRadius,
379 min: 0, max: 40,
380 __nextHasNoMarginBottom: true,
381 onChange: function (v) { setAttributes({ photoBorderRadius: v }); }
382 })
383 ),
384
385 el(PanelColorSettings, {
386 title: __('Colors'),
387 initialOpen: false,
388 colorSettings: [
389 { label: __('Background'), value: a.bgColor, onChange: function (v) { setAttributes({ bgColor: v || '#ffffff' }); } },
390 { label: __('Accent'), value: a.accentColor, onChange: function (v) { setAttributes({ accentColor: v || '#6366f1' }); } },
391 { label: __('Headline'), value: a.headlineColor, onChange: function (v) { setAttributes({ headlineColor: v || '#0f172a' }); } },
392 { label: __('Subheadline'), value: a.subColor, onChange: function (v) { setAttributes({ subColor: v || '#475569' }); } },
393 { label: __('Body text'), value: a.bodyColor, onChange: function (v) { setAttributes({ bodyColor: v || '#334155' }); } },
394 { label: __('Pull quote'), value: a.quoteColor, onChange: function (v) { setAttributes({ quoteColor: v || '#1e293b' }); } },
395 { label: __('Milestone year'), value: a.yearColor, onChange: function (v) { setAttributes({ yearColor: v || '#6366f1' }); } },
396 { label: __('Milestone title'), value: a.milestoneTitleColor, onChange: function (v) { setAttributes({ milestoneTitleColor: v || '#0f172a' }); } },
397 { label: __('Milestone text'), value: a.milestoneTextColor, onChange: function (v) { setAttributes({ milestoneTextColor: v || '#475569' }); } },
398 { label: __('CTA button bg'), value: a.ctaBg, onChange: function (v) { setAttributes({ ctaBg: v || '#6366f1' }); } },
399 { label: __('CTA button text'), value: a.ctaColor, onChange: function (v) { setAttributes({ ctaColor: v || '#ffffff' }); } }
400 ]
401 })
402 );
403 }
404
405 return el(Fragment, null,
406 inspector(),
407 el('div', useBlockProps((function () {
408 var _tvf = getTypoCssVars();
409 var s = {};
410 Object.assign(s, _tvf(a.headlineTypo, '--bkstry-hl-'));
411 Object.assign(s, _tvf(a.subheadlineTypo, '--bkstry-sh-'));
412 Object.assign(s, _tvf(a.bodyTypo, '--bkstry-bd-'));
413 Object.assign(s, _tvf(a.quoteTypo, '--bkstry-qt-'));
414 return { className: 'bkbg-stry-editor-wrap', style: s };
415 })()),
416 el(MediaUpload, {
417 onSelect: function (media) {
418 props.setAttributes({ founderPhotoUrl: media.url, founderPhotoId: media.id });
419 },
420 allowedTypes: ['image'],
421 value: a.founderPhotoId,
422 render: function (ref) {
423 return el(StoryPreview, {
424 attributes: a,
425 setAttributes: setAttributes,
426 openMedia: ref.open
427 });
428 }
429 })
430 )
431 );
432 },
433
434 save: function (props) {
435 return el('div', useBlockProps.save(),
436 el('div', {
437 className: 'bkbg-stry-app',
438 'data-opts': JSON.stringify(props.attributes)
439 })
440 );
441 }
442 });
443 }() );
444