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 / team-members / index.js

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

1,217 lines 61.5 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 __ = wp.i18n.__;
5 var useState = wp.element.useState;
6 var useRef = wp.element.useRef;
7 var useEffect = wp.element.useEffect;
8
9 var registerBlockType = wp.blocks.registerBlockType;
10
11 var InspectorControls = wp.blockEditor.InspectorControls;
12 var BlockControls = wp.blockEditor.BlockControls;
13 var RichText = wp.blockEditor.RichText;
14 var useBlockProps = wp.blockEditor.useBlockProps;
15
16 var PanelBody = wp.components.PanelBody;
17 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
18 var ToggleControl = wp.components.ToggleControl;
19 var RangeControl = wp.components.RangeControl;
20 var SelectControl = wp.components.SelectControl;
21 var Button = wp.components.Button;
22 var ToolbarGroup = wp.components.ToolbarGroup;
23 var ToolbarButton = wp.components.ToolbarButton;
24 var TextControl = wp.components.TextControl;
25
26 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
27 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
28
29 var SOCIAL_TYPES = [
30 { value: 'website', label: __('Website', 'blockenberg'), icon: 'admin-site' },
31 { value: 'email', label: __('Email', 'blockenberg'), icon: 'email' },
32 { value: 'phone', label: __('Phone', 'blockenberg'), icon: 'phone' },
33 { value: 'facebook', label: __('Facebook', 'blockenberg'), icon: 'facebook' },
34 { value: 'twitter', label: __('X (Twitter)', 'blockenberg'), icon: null },
35 { value: 'instagram', label: __('Instagram', 'blockenberg'), icon: 'instagram' },
36 { value: 'linkedin', label: __('LinkedIn', 'blockenberg'), icon: 'linkedin' },
37 { value: 'github', label: __('GitHub', 'blockenberg'), icon: null }
38 ];
39
40 function clone(obj) {
41 var out = {};
42 for (var k in obj) out[k] = obj[k];
43 return out;
44 }
45
46 function getPhotoRadius(shape, radiusPx) {
47 if (shape === 'circle') return '999px';
48 if (shape === 'square') return '0px';
49 // rounded
50 return (radiusPx || 12) + 'px';
51 }
52
53 function getSocialIcon(type) {
54 var found = SOCIAL_TYPES.filter(function (t) { return t.value === type; })[0];
55 return found ? found.icon : 'admin-site';
56 }
57
58 function renderSocialIcon(type) {
59 // X (Twitter)
60 if (type === 'twitter') {
61 return el('svg', {
62 viewBox: '0 0 24 24',
63 width: '24',
64 height: '24',
65 'aria-hidden': 'true',
66 focusable: 'false'
67 },
68 // Simplified X mark
69 el('path', {
70 d: 'M18.3 2H21l-6.6 7.6L22 22h-6.2l-4.8-6.3L5.5 22H3l7.1-8.2L2 2h6.3l4.3 5.7L18.3 2Zm-1.1 18h1.4L7 3.9H5.5L17.2 20Z'
71 })
72 );
73 }
74
75 // GitHub (octocat)
76 if (type === 'github') {
77 return el('svg', {
78 viewBox: '0 0 24 24',
79 width: '24',
80 height: '24',
81 'aria-hidden': 'true',
82 focusable: 'false'
83 },
84 el('path', {
85 d: 'M12 .5C5.65.5.5 5.82.5 12.39c0 5.24 3.44 9.68 8.2 11.25.6.11.82-.26.82-.58 0-.29-.01-1.06-.02-2.07-3.34.75-4.04-1.66-4.04-1.66-.55-1.43-1.33-1.81-1.33-1.81-1.08-.76.08-.74.08-.74 1.2.09 1.83 1.26 1.83 1.26 1.06 1.87 2.78 1.33 3.46 1.01.11-.79.42-1.33.76-1.63-2.66-.31-5.46-1.38-5.46-6.14 0-1.36.47-2.47 1.24-3.34-.12-.31-.54-1.56.12-3.25 0 0 1.01-.33 3.3 1.28a11.1 11.1 0 0 1 3.01-.42c1.02.01 2.05.14 3.01.42 2.28-1.61 3.29-1.28 3.29-1.28.66 1.69.24 2.94.12 3.25.77.87 1.24 1.98 1.24 3.34 0 4.78-2.8 5.83-5.48 6.14.43.38.82 1.13.82 2.29 0 1.65-.02 2.98-.02 3.39 0 .32.22.7.83.58 4.76-1.57 8.2-6.01 8.2-11.25C23.5 5.82 18.35.5 12 .5Z'
86 })
87 );
88 }
89
90 var dash = getSocialIcon(type) || 'admin-site';
91 return el('span', { className: 'dashicons dashicons-' + dash });
92 }
93
94 function normalizeUrl(type, url) {
95 if (!url) return '';
96 var v = String(url).trim();
97 if (!v) return '';
98
99 if (type === 'email') {
100 if (v.indexOf('mailto:') === 0) return v;
101 return 'mailto:' + v;
102 }
103 if (type === 'phone') {
104 if (v.indexOf('tel:') === 0) return v;
105 return 'tel:' + v;
106 }
107 if (v.charAt(0) === '#') return v;
108 // If it already has a scheme (http:, https:, etc), keep it.
109 if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(v)) return v;
110 return 'https://' + v;
111 }
112
113 function openMedia(onSelect) {
114 if (!wp || !wp.media) return;
115 var frame = wp.media({
116 title: __('Select Image', 'blockenberg'),
117 button: { text: __('Use image', 'blockenberg') },
118 multiple: false
119 });
120
121 frame.on('select', function () {
122 var attachment = frame.state().get('selection').first().toJSON();
123 onSelect(attachment);
124 });
125
126 frame.open();
127 }
128
129 registerBlockType('blockenberg/team-members', {
130 title: __('Team Members', 'blockenberg'),
131 icon: 'groups',
132 category: 'bkbg-business',
133 description: __('Show your team members with photos, roles, bios, and social links.', 'blockenberg'),
134
135 edit: function (props) {
136 var attributes = props.attributes;
137 var setAttributes = props.setAttributes;
138 var isSelected = props.isSelected;
139 var a = attributes;
140
141 var activeState = useState(0);
142 var activeIndex = activeState[0];
143 var setActiveIndex = activeState[1];
144
145 function setMembers(members) {
146 setAttributes({ members: members });
147 }
148
149 function updateMember(index, field, value) {
150 var next = a.members.map(function (m, i) {
151 if (i !== index) return m;
152 var nm = clone(m);
153 nm[field] = value;
154 return nm;
155 });
156 setMembers(next);
157 }
158
159 function updateMemberImage(index, image) {
160 var img = {
161 id: image && image.id ? image.id : 0,
162 url: image && image.url ? image.url : '',
163 alt: image && image.alt ? image.alt : ''
164 };
165 updateMember(index, 'image', img);
166 }
167
168 function addMember() {
169 var next = a.members.concat([
170 {
171 name: __('New Member', 'blockenberg'),
172 role: __('Role', 'blockenberg'),
173 bio: __('Write a short bio. Click to edit.', 'blockenberg'),
174 image: { id: 0, url: '', alt: '' },
175 socials: [
176 { type: 'linkedin', url: '' },
177 { type: 'website', url: '' }
178 ]
179 }
180 ]);
181 setMembers(next);
182 setActiveIndex(next.length - 1);
183 }
184
185 function removeMember(index) {
186 if (a.members.length <= 1) return;
187 var next = a.members.filter(function (_, i) { return i !== index; });
188 setMembers(next);
189 setActiveIndex(Math.max(0, Math.min(activeIndex, next.length - 1)));
190 }
191
192 function duplicateMember(index) {
193 var next = a.members.slice();
194 var copy = clone(a.members[index]);
195 copy.image = clone(copy.image || { id: 0, url: '', alt: '' });
196 copy.socials = (copy.socials || []).map(function (s) { return clone(s); });
197 next.splice(index + 1, 0, copy);
198 setMembers(next);
199 setActiveIndex(index + 1);
200 }
201
202 function moveMember(index, dir) {
203 var ni = index + dir;
204 if (ni < 0 || ni >= a.members.length) return;
205 var next = a.members.slice();
206 var tmp = next[index];
207 next[index] = next[ni];
208 next[ni] = tmp;
209 setMembers(next);
210 setActiveIndex(ni);
211 }
212
213 function updateSocial(memberIndex, socialIndex, field, value) {
214 var next = a.members.map(function (m, i) {
215 if (i !== memberIndex) return m;
216 var nm = clone(m);
217 var socials = (nm.socials || []).slice();
218 var s = clone(socials[socialIndex] || { type: 'website', url: '' });
219 s[field] = value;
220 socials[socialIndex] = s;
221 nm.socials = socials;
222 return nm;
223 });
224 setMembers(next);
225 }
226
227 function addSocial(memberIndex) {
228 var next = a.members.map(function (m, i) {
229 if (i !== memberIndex) return m;
230 var nm = clone(m);
231 var socials = (nm.socials || []).slice();
232 socials.push({ type: 'website', url: '' });
233 nm.socials = socials;
234 return nm;
235 });
236 setMembers(next);
237 }
238
239 function removeSocial(memberIndex, socialIndex) {
240 var next = a.members.map(function (m, i) {
241 if (i !== memberIndex) return m;
242 var nm = clone(m);
243 var socials = (nm.socials || []).filter(function (_, si) { return si !== socialIndex; });
244 nm.socials = socials;
245 return nm;
246 });
247 setMembers(next);
248 }
249
250 var fontWeightOptions = [
251 { label: '300', value: 300 },
252 { label: '400', value: 400 },
253 { label: '500', value: 500 },
254 { label: '600', value: 600 },
255 { label: '700', value: 700 },
256 { label: '800', value: 800 }
257 ];
258
259 var columnsOptions = [
260 { label: '1', value: 1 },
261 { label: '2', value: 2 },
262 { label: '3', value: 3 },
263 { label: '4', value: 4 }
264 ];
265
266 var alignOptions = [
267 { label: __('Left', 'blockenberg'), value: 'left' },
268 { label: __('Center', 'blockenberg'), value: 'center' },
269 { label: __('Right', 'blockenberg'), value: 'right' }
270 ];
271
272 var imageShapeOptions = [
273 { label: __('Circle', 'blockenberg'), value: 'circle' },
274 { label: __('Rounded', 'blockenberg'), value: 'rounded' },
275 { label: __('Square', 'blockenberg'), value: 'square' }
276 ];
277
278 var activeMember = a.members[activeIndex] || a.members[0];
279
280 var inspector = el(InspectorControls, {},
281 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: true },
282 el(SelectControl, {
283 label: __('Layout Style', 'blockenberg'),
284 value: a.layoutStyle,
285 options: [
286 { label: __('Cards (Grid)', 'blockenberg'), value: 'cards' },
287 { label: __('Carousel', 'blockenberg'), value: 'carousel' }
288 ],
289 onChange: function (v) { setAttributes({ layoutStyle: v }); }
290 }),
291 el(SelectControl, {
292 label: a.layoutStyle === 'carousel' ? __('Visible Cards', 'blockenberg') : __('Columns', 'blockenberg'),
293 value: a.columns,
294 options: columnsOptions,
295 onChange: function (v) { setAttributes({ columns: parseInt(v, 10) }); }
296 }),
297 el(RangeControl, {
298 label: __('Gap', 'blockenberg'),
299 value: a.gap,
300 min: 8,
301 max: 60,
302 onChange: function (v) { setAttributes({ gap: v }); }
303 }),
304 a.layoutStyle === 'carousel' && el(ToggleControl, {
305 label: __('Show Carousel Navigation', 'blockenberg'),
306 checked: a.carouselNav,
307 __nextHasNoMarginBottom: true,
308 onChange: function (v) { setAttributes({ carouselNav: v }); }
309 }),
310 a.layoutStyle === 'carousel' && el(SelectControl, {
311 label: __('Arrow Style', 'blockenberg'),
312 value: a.carouselNavStyle,
313 options: [
314 { label: __('Top Right', 'blockenberg'), value: 'top' },
315 { label: __('Overlay Sides', 'blockenberg'), value: 'overlay' },
316 { label: __('Bottom Center', 'blockenberg'), value: 'bottom' }
317 ],
318 onChange: function (v) { setAttributes({ carouselNavStyle: v }); }
319 }),
320 a.layoutStyle === 'carousel' && el(ToggleControl, {
321 label: __('Peek Next Card', 'blockenberg'),
322 checked: a.carouselPeek,
323 __nextHasNoMarginBottom: true,
324 onChange: function (v) { setAttributes({ carouselPeek: v }); }
325 }),
326 a.layoutStyle === 'carousel' && el(SelectControl, {
327 label: __('Indicators', 'blockenberg'),
328 value: a.carouselIndicators,
329 options: [
330 { label: __('None', 'blockenberg'), value: 'none' },
331 { label: __('Dots', 'blockenberg'), value: 'dots' },
332 { label: __('Progress Bar', 'blockenberg'), value: 'progress' },
333 { label: __('Fraction (1/6)', 'blockenberg'), value: 'fraction' }
334 ],
335 onChange: function (v) { setAttributes({ carouselIndicators: v }); }
336 }),
337 a.layoutStyle === 'carousel' && a.carouselIndicators === 'dots' && el(SelectControl, {
338 label: __('Dots Style', 'blockenberg'),
339 value: a.carouselDotsStyle,
340 options: [
341 { label: __('Dots', 'blockenberg'), value: 'default' },
342 { label: __('Active Pill', 'blockenberg'), value: 'pill' }
343 ],
344 onChange: function (v) { setAttributes({ carouselDotsStyle: v }); }
345 }),
346 a.layoutStyle === 'carousel' && a.carouselIndicators === 'dots' && el(RangeControl, {
347 label: __('Dot Size', 'blockenberg'),
348 value: a.carouselIndicatorSize,
349 min: 6,
350 max: 16,
351 onChange: function (v) { setAttributes({ carouselIndicatorSize: v }); }
352 }),
353 a.layoutStyle === 'carousel' && a.carouselIndicators === 'progress' && el(SelectControl, {
354 label: __('Progress Style', 'blockenberg'),
355 value: a.carouselProgressStyle,
356 options: [
357 { label: __('Contained', 'blockenberg'), value: 'default' },
358 { label: __('Edge-to-edge', 'blockenberg'), value: 'edge' }
359 ],
360 onChange: function (v) { setAttributes({ carouselProgressStyle: v }); }
361 }),
362 a.layoutStyle === 'carousel' && a.carouselIndicators === 'progress' && el(RangeControl, {
363 label: __('Progress Height', 'blockenberg'),
364 value: a.carouselProgressHeight,
365 min: 2,
366 max: 14,
367 onChange: function (v) { setAttributes({ carouselProgressHeight: v }); }
368 }),
369 a.layoutStyle === 'carousel' && a.carouselIndicators !== 'none' && el(SelectControl, {
370 label: __('Indicators Position', 'blockenberg'),
371 value: a.carouselIndicatorsPosition,
372 options: [
373 { label: __('Below', 'blockenberg'), value: 'below' },
374 { label: __('Above', 'blockenberg'), value: 'top' }
375 ],
376 onChange: function (v) { setAttributes({ carouselIndicatorsPosition: v }); }
377 }),
378 a.layoutStyle === 'carousel' && el(ToggleControl, {
379 label: __('Infinite Loop', 'blockenberg'),
380 checked: a.infiniteScroll !== false,
381 __nextHasNoMarginBottom: true,
382 onChange: function (v) { setAttributes({ infiniteScroll: !!v }); }
383 }),
384 a.layoutStyle === 'carousel' && el(ToggleControl, {
385 label: __('Auto-scroll (continuous)', 'blockenberg'),
386 help: __('Runs on the live site (frontend). Please check it there.', 'blockenberg'),
387 checked: !!a.autoScroll,
388 __nextHasNoMarginBottom: true,
389 onChange: function (v) { setAttributes({ autoScroll: !!v }); }
390 }),
391 a.layoutStyle === 'carousel' && a.autoScroll && el(RangeControl, {
392 label: __('Auto-scroll speed (px/sec)', 'blockenberg'),
393 value: a.autoScrollSpeed || 40,
394 min: 5,
395 max: 200,
396 step: 1,
397 onChange: function (v) { setAttributes({ autoScrollSpeed: v }); }
398 }),
399 a.layoutStyle === 'carousel' && a.autoScroll && el(ToggleControl, {
400 label: __('Pause on hover', 'blockenberg'),
401 checked: a.autoScrollPauseOnHover !== false,
402 __nextHasNoMarginBottom: true,
403 onChange: function (v) { setAttributes({ autoScrollPauseOnHover: !!v }); }
404 }),
405 el(SelectControl, {
406 label: __('Text Align', 'blockenberg'),
407 value: a.textAlign,
408 options: alignOptions,
409 onChange: function (v) { setAttributes({ textAlign: v }); }
410 })
411 ),
412
413 el(PanelBody, { title: __('Card', 'blockenberg'), initialOpen: false },
414 el(RangeControl, {
415 label: __('Padding', 'blockenberg'),
416 value: a.cardPadding,
417 min: 8,
418 max: 60,
419 onChange: function (v) { setAttributes({ cardPadding: v }); }
420 }),
421 el(RangeControl, {
422 label: __('Border Radius', 'blockenberg'),
423 value: a.cardRadius,
424 min: 0,
425 max: 40,
426 onChange: function (v) { setAttributes({ cardRadius: v }); }
427 }),
428 el(RangeControl, {
429 label: __('Border Width', 'blockenberg'),
430 value: a.cardBorderWidth,
431 min: 0,
432 max: 6,
433 onChange: function (v) { setAttributes({ cardBorderWidth: v }); }
434 }),
435 el(ToggleControl, {
436 label: __('Shadow', 'blockenberg'),
437 checked: a.cardShadow,
438 __nextHasNoMarginBottom: true,
439 onChange: function (v) { setAttributes({ cardShadow: v }); }
440 }),
441 el(ToggleControl, {
442 label: __('Hover Lift', 'blockenberg'),
443 checked: a.hoverLift,
444 __nextHasNoMarginBottom: true,
445 onChange: function (v) { setAttributes({ hoverLift: v }); }
446 }),
447 a.hoverLift && el(RangeControl, {
448 label: __('Lift Amount', 'blockenberg'),
449 value: a.hoverLiftAmount,
450 min: 0,
451 max: 20,
452 onChange: function (v) { setAttributes({ hoverLiftAmount: v }); }
453 })
454 ),
455
456 el(PanelBody, { title: __('Image', 'blockenberg'), initialOpen: false },
457 el(SelectControl, {
458 label: __('Shape', 'blockenberg'),
459 value: a.imageShape,
460 options: imageShapeOptions,
461 onChange: function (v) { setAttributes({ imageShape: v }); }
462 }),
463 el(RangeControl, {
464 label: __('Size', 'blockenberg'),
465 value: a.imageSize,
466 min: 40,
467 max: 200,
468 onChange: function (v) { setAttributes({ imageSize: v }); }
469 })
470 ),
471
472 el(PanelBody, { title: __('Content', 'blockenberg'), initialOpen: false },
473 el(ToggleControl, {
474 label: __('Show Role', 'blockenberg'),
475 checked: a.showRole,
476 __nextHasNoMarginBottom: true,
477 onChange: function (v) { setAttributes({ showRole: v }); }
478 }),
479 el(ToggleControl, {
480 label: __('Show Bio', 'blockenberg'),
481 checked: a.showBio,
482 __nextHasNoMarginBottom: true,
483 onChange: function (v) { setAttributes({ showBio: v }); }
484 }),
485 el(ToggleControl, {
486 label: __('Show Social Links', 'blockenberg'),
487 checked: a.showSocials,
488 __nextHasNoMarginBottom: true,
489 onChange: function (v) { setAttributes({ showSocials: v }); }
490 })
491 ),
492
493 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
494 getTypoControl()({ label: __('Name', 'blockenberg'), value: a.nameTypo, onChange: function (v) { setAttributes({ nameTypo: v }); } }),
495 getTypoControl()({ label: __('Role', 'blockenberg'), value: a.roleTypo, onChange: function (v) { setAttributes({ roleTypo: v }); } }),
496 getTypoControl()({ label: __('Bio', 'blockenberg'), value: a.bioTypo, onChange: function (v) { setAttributes({ bioTypo: v }); } }),
497 el(RangeControl, {
498 label: __('Social Icon Size', 'blockenberg'),
499 value: a.socialSize,
500 min: 12,
501 max: 30,
502 onChange: function (v) { setAttributes({ socialSize: v }); }
503 }),
504 a.layoutStyle === 'carousel' && a.carouselIndicators === 'fraction' && el(RangeControl, {
505 label: __('Fraction Text Size', 'blockenberg'),
506 value: a.carouselFractionSize,
507 min: 10,
508 max: 18,
509 onChange: function (v) { setAttributes({ carouselFractionSize: v }); }
510 })
511 ),
512
513 el(PanelColorSettings, {
514 title: __('Colors', 'blockenberg'),
515 initialOpen: false,
516 colorSettings: [
517 { value: a.cardBg, onChange: function (c) { setAttributes({ cardBg: c }); }, label: __('Card Background', 'blockenberg') },
518 { value: a.cardBorderColor, onChange: function (c) { setAttributes({ cardBorderColor: c }); }, label: __('Card Border', 'blockenberg') },
519 { value: a.nameColor, onChange: function (c) { setAttributes({ nameColor: c }); }, label: __('Name', 'blockenberg') },
520 { value: a.roleColor, onChange: function (c) { setAttributes({ roleColor: c }); }, label: __('Role', 'blockenberg') },
521 { value: a.bioColor, onChange: function (c) { setAttributes({ bioColor: c }); }, label: __('Bio', 'blockenberg') },
522 { value: a.socialColor, onChange: function (c) { setAttributes({ socialColor: c }); }, label: __('Social', 'blockenberg') },
523 { value: a.socialHoverColor, onChange: function (c) { setAttributes({ socialHoverColor: c }); }, label: __('Social Hover', 'blockenberg') },
524
525 { value: a.carouselIndicatorColor, onChange: function (c) { setAttributes({ carouselIndicatorColor: c }); }, label: __('Carousel Indicator', 'blockenberg') },
526 { value: a.carouselIndicatorActiveColor, onChange: function (c) { setAttributes({ carouselIndicatorActiveColor: c }); }, label: __('Carousel Indicator (Active)', 'blockenberg') },
527 { value: a.carouselProgressBg, onChange: function (c) { setAttributes({ carouselProgressBg: c }); }, label: __('Carousel Progress (Track)', 'blockenberg') },
528 { value: a.carouselProgressFg, onChange: function (c) { setAttributes({ carouselProgressFg: c }); }, label: __('Carousel Progress (Fill)', 'blockenberg') },
529 { value: a.carouselFractionColor, onChange: function (c) { setAttributes({ carouselFractionColor: c }); }, label: __('Carousel Fraction', 'blockenberg') }
530 ]
531 }),
532
533 el(PanelBody, { title: __('Selected Member', 'blockenberg'), initialOpen: false },
534 activeMember ? el('div', {},
535 el('div', { style: { marginBottom: '10px', fontWeight: 600 } }, __('Member', 'blockenberg') + ': ' + (activeIndex + 1)),
536 el(Button, {
537 isSecondary: true,
538 onClick: function () {
539 openMedia(function (att) {
540 updateMemberImage(activeIndex, { id: att.id, url: att.url, alt: att.alt || '' });
541 });
542 }
543 }, activeMember.image && activeMember.image.url ? __('Change Photo', 'blockenberg') : __('Select Photo', 'blockenberg')),
544 activeMember.image && activeMember.image.url && el(Button, {
545 isLink: true,
546 isDestructive: true,
547 onClick: function () { updateMemberImage(activeIndex, { id: 0, url: '', alt: '' }); }
548 }, __('Remove Photo', 'blockenberg')),
549
550 el('hr', { style: { margin: '14px 0' } }),
551
552 el('div', { style: { marginBottom: '8px', fontWeight: 600 } }, __('Social Links', 'blockenberg')),
553 (activeMember.socials || []).map(function (s, si) {
554 return el('div', { key: si, style: { marginBottom: '10px', padding: '10px', border: '1px solid #e5e7eb', borderRadius: '6px' } },
555 el(SelectControl, {
556 label: __('Type', 'blockenberg'),
557 value: s.type,
558 options: SOCIAL_TYPES.map(function (t) { return { label: t.label, value: t.value }; }),
559 onChange: function (v) { updateSocial(activeIndex, si, 'type', v); }
560 }),
561 el(TextControl, {
562 label: __('URL', 'blockenberg'),
563 value: s.url,
564 onChange: function (v) { updateSocial(activeIndex, si, 'url', v); }
565 }),
566 el(Button, {
567 isDestructive: true,
568 isSecondary: true,
569 onClick: function () { removeSocial(activeIndex, si); }
570 }, __('Remove', 'blockenberg'))
571 );
572 }),
573 el(Button, {
574 isPrimary: true,
575 onClick: function () { addSocial(activeIndex); }
576 }, __('+ Add Social Link', 'blockenberg'))
577 ) : el('div', {}, __('Select a card to edit its member settings.', 'blockenberg'))
578 )
579 );
580
581 var blockControls = el(BlockControls, {},
582 el(ToolbarGroup, {},
583 el(ToolbarButton, {
584 icon: 'plus',
585 label: __('Add Member', 'blockenberg'),
586 onClick: addMember
587 })
588 )
589 );
590
591 var styleVars = {
592 '--bkbg-tm-columns': String(a.columns),
593 '--bkbg-tm-gap': a.gap + 'px',
594 '--bkbg-tm-carousel-peek': a.carouselPeek ? '20%' : '0px',
595 '--bkbg-tm-card-bg': a.cardBg,
596 '--bkbg-tm-card-border-color': a.cardBorderColor,
597 '--bkbg-tm-card-border-width': a.cardBorderWidth + 'px',
598 '--bkbg-tm-card-radius': a.cardRadius + 'px',
599 '--bkbg-tm-card-padding': a.cardPadding + 'px',
600 '--bkbg-tm-text-align': a.textAlign,
601 '--bkbg-tm-photo-size': a.imageSize + 'px',
602 '--bkbg-tm-photo-radius': getPhotoRadius(a.imageShape, 12),
603 '--bkbg-tm-name-color': a.nameColor,
604 '--bkbg-tm-role-color': a.roleColor,
605 '--bkbg-tm-bio-color': a.bioColor,
606 '--bkbg-tm-name-size': a.nameSize + 'px',
607 '--bkbg-tm-role-size': a.roleSize + 'px',
608 '--bkbg-tm-bio-size': a.bioSize + 'px',
609 '--bkbg-tm-name-weight': String(a.nameWeight),
610 '--bkbg-tm-role-weight': String(a.roleWeight),
611 '--bkbg-tm-social-color': a.socialColor,
612 '--bkbg-tm-social-hover': a.socialHoverColor,
613 '--bkbg-tm-social-size': a.socialSize + 'px',
614 '--bkbg-tm-hover-lift': a.hoverLiftAmount + 'px',
615
616 '--bkbg-tm-indicator-size': (a.carouselIndicatorSize || 8) + 'px',
617 '--bkbg-tm-indicator-color': a.carouselIndicatorColor,
618 '--bkbg-tm-indicator-active-color': a.carouselIndicatorActiveColor,
619 '--bkbg-tm-progress-height': (a.carouselProgressHeight || 6) + 'px',
620 '--bkbg-tm-progress-bg': a.carouselProgressBg,
621 '--bkbg-tm-progress-fg': a.carouselProgressFg,
622 '--bkbg-tm-fraction-color': a.carouselFractionColor,
623 '--bkbg-tm-fraction-size': (a.carouselFractionSize || 13) + 'px'
624 };
625
626 var classes = [
627 'bkbg-tm-wrap',
628 'bkbg-tm-align-' + a.textAlign
629 ];
630 if (a.hoverLift) classes.push('bkbg-tm-hover-lift');
631 if (a.layoutStyle === 'carousel') {
632 classes.push('bkbg-tm-nav-' + (a.carouselNavStyle || 'top'));
633 classes.push('bkbg-tm-indicators-' + (a.carouselIndicators || 'none'));
634 classes.push('bkbg-tm-indicators-pos-' + (a.carouselIndicatorsPosition || 'below'));
635
636 if (a.carouselIndicators === 'dots') {
637 classes.push('bkbg-tm-dots-style-' + (a.carouselDotsStyle || 'default'));
638 }
639 if (a.carouselIndicators === 'progress') {
640 classes.push('bkbg-tm-progress-style-' + (a.carouselProgressStyle || 'default'));
641 }
642 }
643
644 var blockProps = useBlockProps((function () {
645 var _tvf = getTypoCssVars();
646 var s = Object.assign({}, styleVars);
647 if (_tvf) {
648 Object.assign(s, _tvf(a.nameTypo, '--bktm-nm-'));
649 Object.assign(s, _tvf(a.roleTypo, '--bktm-rl-'));
650 Object.assign(s, _tvf(a.bioTypo, '--bktm-bi-'));
651 }
652 return { className: 'bkbg-editor-wrap ' + classes.join(' '), style: s, 'data-block-label': 'Team' };
653 })());
654
655 var trackRef = useRef(null);
656
657 var activeSlideState = useState(0);
658 var activeSlide = activeSlideState[0];
659 var setActiveSlide = activeSlideState[1];
660
661 var progressState = useState(0);
662 var progressPct = progressState[0];
663 var setProgressPct = progressState[1];
664
665 function getSlides() {
666 if (!trackRef.current) return [];
667 return trackRef.current.querySelectorAll('.bkbg-tm-slide');
668 }
669
670 function scrollToIndex(i) {
671 if (!trackRef.current) return;
672 var slides = getSlides();
673 if (!slides.length) return;
674 var idx = Math.max(0, Math.min(slides.length - 1, i));
675 slides[idx].scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest' });
676 }
677
678 function scrollCarousel(dir) {
679 if (!trackRef.current) return;
680 var track = trackRef.current;
681 var slides = getSlides();
682 if (!slides.length) return;
683
684 var trackRect = track.getBoundingClientRect();
685 var currentIndex = 0;
686 for (var i = 0; i < slides.length; i++) {
687 var r = slides[i].getBoundingClientRect();
688 if (r.left >= trackRect.left - 10) {
689 currentIndex = i;
690 break;
691 }
692 }
693
694 scrollToIndex(currentIndex + dir);
695 }
696
697 useEffect(function () {
698 if (!trackRef.current) return;
699 var track = trackRef.current;
700
701 function getScrollPct() {
702 var max = track.scrollWidth - track.clientWidth;
703 if (max <= 0) return 0;
704 var pct = (track.scrollLeft / max) * 100;
705 if (pct < 0) pct = 0;
706 if (pct > 100) pct = 100;
707 return pct;
708 }
709
710 function updateActiveFromScroll() {
711 var slides = getSlides();
712 if (!slides.length) return;
713 var trackRect = track.getBoundingClientRect();
714 var idx = 0;
715 for (var i = 0; i < slides.length; i++) {
716 var r = slides[i].getBoundingClientRect();
717 if (r.left >= trackRect.left - 10) {
718 idx = i;
719 break;
720 }
721 }
722 setActiveSlide(idx);
723
724 // Smooth progress update
725 setProgressPct(getScrollPct());
726 }
727
728 updateActiveFromScroll();
729 track.addEventListener('scroll', updateActiveFromScroll, { passive: true });
730 return function () {
731 track.removeEventListener('scroll', updateActiveFromScroll);
732 };
733 }, [a.layoutStyle, a.members.length]);
734
735 function renderIndicators() {
736 if (a.carouselIndicators === 'none') return null;
737 if (a.carouselIndicators === 'progress') {
738 return el('div', { className: 'bkbg-tm-indicators' },
739 el('div', { className: 'bkbg-tm-progress' },
740 el('div', { className: 'bkbg-tm-progress-bar', style: { width: progressPct + '%' } })
741 )
742 );
743 }
744
745 if (a.carouselIndicators === 'fraction') {
746 var total = Math.max(1, (a.members || []).length);
747 return el('div', { className: 'bkbg-tm-indicators' },
748 el('div', { className: 'bkbg-tm-fraction', 'aria-label': __('Carousel position', 'blockenberg') },
749 el('span', { className: 'bkbg-tm-fraction-current' }, String(activeSlide + 1)),
750 el('span', { 'aria-hidden': 'true' }, '/'),
751 el('span', { className: 'bkbg-tm-fraction-total' }, String(total))
752 )
753 );
754 }
755
756 return el('div', { className: 'bkbg-tm-indicators' },
757 el('div', { className: 'bkbg-tm-dots', role: 'tablist', 'aria-label': __('Team Members Carousel', 'blockenberg') },
758 (a.members || []).map(function (_, i) {
759 return el('button', {
760 key: i,
761 type: 'button',
762 className: 'bkbg-tm-dot' + (i === activeSlide ? ' is-active' : ''),
763 'aria-label': __('Go to slide', 'blockenberg') + ' ' + (i + 1),
764 onClick: function (e) { e.preventDefault(); e.stopPropagation(); scrollToIndex(i); }
765 });
766 })
767 )
768 );
769 }
770
771 function renderPhoto(member, index) {
772 var hasImg = member.image && member.image.url;
773 if (hasImg) {
774 return el('div', {
775 className: 'bkbg-tm-photo',
776 onClick: function (e) {
777 e.preventDefault();
778 e.stopPropagation();
779 setActiveIndex(index);
780 openMedia(function (att) {
781 updateMemberImage(index, { id: att.id, url: att.url, alt: att.alt || '' });
782 });
783 },
784 title: __('Click to change photo', 'blockenberg')
785 },
786 el('img', { src: member.image.url, alt: member.image.alt || '' })
787 );
788 }
789
790 return el('div', {
791 className: 'bkbg-tm-photo',
792 onClick: function (e) {
793 e.preventDefault();
794 e.stopPropagation();
795 setActiveIndex(index);
796 openMedia(function (att) {
797 updateMemberImage(index, { id: att.id, url: att.url, alt: att.alt || '' });
798 });
799 }
800 },
801 el('div', { className: 'bkbg-tm-photo-placeholder' },
802 el('span', { className: 'dashicons dashicons-format-image' }),
803 el('div', {}, __('Add Photo', 'blockenberg'))
804 )
805 );
806 }
807
808 function renderSocials(member) {
809 if (!a.showSocials) return null;
810 var socials = (member.socials || []).filter(function (s) { return s && s.url; });
811 if (!socials.length) return null;
812
813 return el('div', { className: 'bkbg-tm-socials' },
814 socials.map(function (s, si) {
815 var href = normalizeUrl(s.type, s.url);
816 var isDirect = s.type === 'email' || s.type === 'phone';
817 return el('a', {
818 key: si,
819 className: 'bkbg-tm-social',
820 href: href,
821 rel: isDirect ? undefined : 'noopener noreferrer',
822 target: isDirect ? undefined : '_blank'
823 },
824 renderSocialIcon(s.type)
825 );
826 })
827 );
828 }
829
830 function renderMemberCard(member, index) {
831 var isActive = index === activeIndex;
832 var cardClasses = ['bkbg-tm-card'];
833 if (a.cardShadow) cardClasses.push('has-shadow');
834 if (isActive && isSelected) cardClasses.push('is-active');
835
836 return el('div', {
837 key: index,
838 className: cardClasses.join(' '),
839 onClick: function () { setActiveIndex(index); }
840 },
841 el('div', { className: 'bkbg-tm-actions' },
842 el(Button, {
843 icon: 'arrow-left-alt2',
844 label: __('Move Left', 'blockenberg'),
845 disabled: index === 0,
846 onClick: function (e) { e.preventDefault(); e.stopPropagation(); moveMember(index, -1); }
847 }),
848 el(Button, {
849 icon: 'arrow-right-alt2',
850 label: __('Move Right', 'blockenberg'),
851 disabled: index === a.members.length - 1,
852 onClick: function (e) { e.preventDefault(); e.stopPropagation(); moveMember(index, 1); }
853 }),
854 el(Button, {
855 icon: 'admin-page',
856 label: __('Duplicate', 'blockenberg'),
857 onClick: function (e) { e.preventDefault(); e.stopPropagation(); duplicateMember(index); }
858 }),
859 el(Button, {
860 icon: 'trash',
861 label: __('Remove', 'blockenberg'),
862 isDestructive: true,
863 disabled: a.members.length <= 1,
864 onClick: function (e) { e.preventDefault(); e.stopPropagation(); removeMember(index); }
865 })
866 ),
867
868 renderPhoto(member, index),
869
870 el(RichText, {
871 tagName: 'h3',
872 className: 'bkbg-tm-name',
873 value: member.name,
874 placeholder: __('Member Name', 'blockenberg'),
875 onChange: function (v) { updateMember(index, 'name', v); }
876 }),
877
878 a.showRole && el(RichText, {
879 tagName: 'div',
880 className: 'bkbg-tm-role',
881 value: member.role,
882 placeholder: __('Role / Position', 'blockenberg'),
883 onChange: function (v) { updateMember(index, 'role', v); }
884 }),
885
886 a.showBio && el(RichText, {
887 tagName: 'p',
888 className: 'bkbg-tm-bio',
889 value: member.bio,
890 placeholder: __('Short bio…', 'blockenberg'),
891 onChange: function (v) { updateMember(index, 'bio', v); }
892 }),
893
894 renderSocials(member)
895 );
896 }
897
898 function renderMembers() {
899 if (a.layoutStyle === 'carousel') {
900 var indicators = renderIndicators();
901 var nav = a.carouselNav && el('div', { className: 'bkbg-tm-nav' },
902 el('button', {
903 type: 'button',
904 className: 'bkbg-tm-nav-btn bkbg-tm-prev',
905 'aria-label': __('Previous', 'blockenberg'),
906 onClick: function (e) { e.preventDefault(); e.stopPropagation(); scrollCarousel(-1); }
907 }, el('span', { className: 'dashicons dashicons-arrow-left-alt2' })),
908 el('button', {
909 type: 'button',
910 className: 'bkbg-tm-nav-btn bkbg-tm-next',
911 'aria-label': __('Next', 'blockenberg'),
912 onClick: function (e) { e.preventDefault(); e.stopPropagation(); scrollCarousel(1); }
913 }, el('span', { className: 'dashicons dashicons-arrow-right-alt2' }))
914 );
915
916 return el('div', { className: 'bkbg-tm-carousel' + (a.carouselPeek ? ' bkbg-tm-carousel-peek' : '') },
917 (a.carouselIndicatorsPosition === 'top') && indicators,
918 el('div', { className: 'bkbg-tm-carousel-inner' },
919 nav,
920 el('div', { className: 'bkbg-tm-track', ref: trackRef },
921 a.members.map(function (member, index) {
922 return el('div', { key: index, className: 'bkbg-tm-slide' }, renderMemberCard(member, index));
923 })
924 )
925 ),
926 (a.carouselIndicatorsPosition !== 'top') && indicators
927 );
928 }
929
930 return el('div', { className: 'bkbg-tm-grid' },
931 a.members.map(function (member, index) {
932 return renderMemberCard(member, index);
933 })
934 );
935 }
936
937 return el(Fragment, {},
938 inspector,
939 blockControls,
940 el('div', blockProps,
941 renderMembers(),
942
943 el('div', { className: 'bkbg-editor-actions' },
944 el(Button, { variant: 'secondary', icon: 'plus-alt2', onClick: addMember }, __('Add Member', 'blockenberg'))
945 )
946 )
947 );
948 },
949
950 save: function (props) {
951 var a = props.attributes;
952
953 function getPhotoRadius(shape, radiusPx) {
954 if (shape === 'circle') return '999px';
955 if (shape === 'square') return '0px';
956 return (radiusPx || 12) + 'px';
957 }
958
959 function getSocialIcon(type) {
960 var map = {
961 website: 'admin-site',
962 email: 'email',
963 phone: 'phone',
964 facebook: 'facebook',
965 twitter: null,
966 instagram: 'instagram',
967 linkedin: 'linkedin',
968 github: null
969 };
970 return map[type] || 'admin-site';
971 }
972
973 function renderSocialIcon(type) {
974 if (type === 'twitter') {
975 return el('svg', {
976 viewBox: '0 0 24 24',
977 width: '24',
978 height: '24',
979 'aria-hidden': 'true',
980 focusable: 'false'
981 },
982 el('path', {
983 d: 'M18.3 2H21l-6.6 7.6L22 22h-6.2l-4.8-6.3L5.5 22H3l7.1-8.2L2 2h6.3l4.3 5.7L18.3 2Zm-1.1 18h1.4L7 3.9H5.5L17.2 20Z'
984 })
985 );
986 }
987 if (type === 'github') {
988 return el('svg', {
989 viewBox: '0 0 24 24',
990 width: '24',
991 height: '24',
992 'aria-hidden': 'true',
993 focusable: 'false'
994 },
995 el('path', {
996 d: 'M12 .5C5.65.5.5 5.82.5 12.39c0 5.24 3.44 9.68 8.2 11.25.6.11.82-.26.82-.58 0-.29-.01-1.06-.02-2.07-3.34.75-4.04-1.66-4.04-1.66-.55-1.43-1.33-1.81-1.33-1.81-1.08-.76.08-.74.08-.74 1.2.09 1.83 1.26 1.83 1.26 1.06 1.87 2.78 1.33 3.46 1.01.11-.79.42-1.33.76-1.63-2.66-.31-5.46-1.38-5.46-6.14 0-1.36.47-2.47 1.24-3.34-.12-.31-.54-1.56.12-3.25 0 0 1.01-.33 3.3 1.28a11.1 11.1 0 0 1 3.01-.42c1.02.01 2.05.14 3.01.42 2.28-1.61 3.29-1.28 3.29-1.28.66 1.69.24 2.94.12 3.25.77.87 1.24 1.98 1.24 3.34 0 4.78-2.8 5.83-5.48 6.14.43.38.82 1.13.82 2.29 0 1.65-.02 2.98-.02 3.39 0 .32.22.7.83.58 4.76-1.57 8.2-6.01 8.2-11.25C23.5 5.82 18.35.5 12 .5Z'
997 })
998 );
999 }
1000 var dash = getSocialIcon(type) || 'admin-site';
1001 return el('span', { className: 'dashicons dashicons-' + dash });
1002 }
1003
1004 function normalizeUrl(type, url) {
1005 if (!url) return '';
1006 var v = String(url).trim();
1007 if (!v) return '';
1008 if (type === 'email') {
1009 if (v.indexOf('mailto:') === 0) return v;
1010 return 'mailto:' + v;
1011 }
1012 if (type === 'phone') {
1013 if (v.indexOf('tel:') === 0) return v;
1014 return 'tel:' + v;
1015 }
1016 if (v.charAt(0) === '#') return v;
1017 if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(v)) return v;
1018 return 'https://' + v;
1019 }
1020
1021 var styleVars = {
1022 '--bkbg-tm-columns': String(a.columns),
1023 '--bkbg-tm-gap': a.gap + 'px',
1024 '--bkbg-tm-carousel-peek': a.carouselPeek ? '20%' : '0px',
1025 '--bkbg-tm-card-bg': a.cardBg,
1026 '--bkbg-tm-card-border-color': a.cardBorderColor,
1027 '--bkbg-tm-card-border-width': a.cardBorderWidth + 'px',
1028 '--bkbg-tm-card-radius': a.cardRadius + 'px',
1029 '--bkbg-tm-card-padding': a.cardPadding + 'px',
1030 '--bkbg-tm-text-align': a.textAlign,
1031 '--bkbg-tm-photo-size': a.imageSize + 'px',
1032 '--bkbg-tm-photo-radius': getPhotoRadius(a.imageShape, 12),
1033 '--bkbg-tm-name-color': a.nameColor,
1034 '--bkbg-tm-role-color': a.roleColor,
1035 '--bkbg-tm-bio-color': a.bioColor,
1036 '--bkbg-tm-social-color': a.socialColor,
1037 '--bkbg-tm-social-hover': a.socialHoverColor,
1038 '--bkbg-tm-social-size': a.socialSize + 'px',
1039 '--bkbg-tm-hover-lift': a.hoverLiftAmount + 'px',
1040
1041 '--bkbg-tm-indicator-size': (a.carouselIndicatorSize || 8) + 'px',
1042 '--bkbg-tm-indicator-color': a.carouselIndicatorColor,
1043 '--bkbg-tm-indicator-active-color': a.carouselIndicatorActiveColor,
1044 '--bkbg-tm-progress-height': (a.carouselProgressHeight || 6) + 'px',
1045 '--bkbg-tm-progress-bg': a.carouselProgressBg,
1046 '--bkbg-tm-progress-fg': a.carouselProgressFg,
1047 '--bkbg-tm-fraction-color': a.carouselFractionColor,
1048 '--bkbg-tm-fraction-size': (a.carouselFractionSize || 13) + 'px'
1049 };
1050
1051 var classes = [
1052 'bkbg-tm-wrap',
1053 'bkbg-tm-align-' + a.textAlign
1054 ];
1055 if (a.hoverLift) classes.push('bkbg-tm-hover-lift');
1056 if (a.layoutStyle === 'carousel') {
1057 classes.push('bkbg-tm-nav-' + (a.carouselNavStyle || 'top'));
1058 classes.push('bkbg-tm-indicators-' + (a.carouselIndicators || 'none'));
1059 classes.push('bkbg-tm-indicators-pos-' + (a.carouselIndicatorsPosition || 'below'));
1060
1061 if (a.carouselIndicators === 'dots') {
1062 classes.push('bkbg-tm-dots-style-' + (a.carouselDotsStyle || 'default'));
1063 }
1064 if (a.carouselIndicators === 'progress') {
1065 classes.push('bkbg-tm-progress-style-' + (a.carouselProgressStyle || 'default'));
1066 }
1067 }
1068
1069 var blockProps = (function () {
1070 var _tvf = getTypoCssVars();
1071 var s = Object.assign({}, styleVars);
1072 if (_tvf) {
1073 Object.assign(s, _tvf(a.nameTypo, '--bktm-nm-'));
1074 Object.assign(s, _tvf(a.roleTypo, '--bktm-rl-'));
1075 Object.assign(s, _tvf(a.bioTypo, '--bktm-bi-'));
1076 }
1077 return useBlockProps.save({
1078 className: classes.join(' '),
1079 style: s,
1080 'data-bkbg-infinite': a.infiniteScroll === false ? '0' : '1',
1081 'data-bkbg-autoscroll': a.autoScroll ? '1' : '0',
1082 'data-bkbg-autoscroll-speed': String(a.autoScrollSpeed || 40),
1083 'data-bkbg-autoscroll-hover': a.autoScrollPauseOnHover === false ? '0' : '1'
1084 });
1085 })();
1086
1087 function renderSocials(member) {
1088 if (!a.showSocials) return null;
1089 var socials = (member.socials || []).filter(function (s) { return s && s.url; });
1090 if (!socials.length) return null;
1091
1092 return el('div', { className: 'bkbg-tm-socials' },
1093 socials.map(function (s, si) {
1094 var href = normalizeUrl(s.type, s.url);
1095 var isDirect = s.type === 'email' || s.type === 'phone';
1096 return el('a', {
1097 key: si,
1098 className: 'bkbg-tm-social',
1099 href: href,
1100 rel: isDirect ? undefined : 'noopener noreferrer',
1101 target: isDirect ? undefined : '_blank'
1102 },
1103 renderSocialIcon(s.type)
1104 );
1105 })
1106 );
1107 }
1108
1109 return el('div', blockProps,
1110 a.layoutStyle === 'carousel'
1111 ? el('div', { className: 'bkbg-tm-carousel' + (a.carouselPeek ? ' bkbg-tm-carousel-peek' : '') },
1112 (a.carouselIndicatorsPosition === 'top') && (a.carouselIndicators !== 'none') && el('div', { className: 'bkbg-tm-indicators' },
1113 a.carouselIndicators === 'progress'
1114 ? el('div', { className: 'bkbg-tm-progress' }, el('div', { className: 'bkbg-tm-progress-bar', style: { width: '0%' } }))
1115 : a.carouselIndicators === 'fraction'
1116 ? el('div', { className: 'bkbg-tm-fraction', 'aria-label': __('Carousel position', 'blockenberg') },
1117 el('span', { className: 'bkbg-tm-fraction-current', 'data-bkbg-fraction': 'current' }, '1'),
1118 el('span', { 'aria-hidden': 'true' }, '/'),
1119 el('span', { className: 'bkbg-tm-fraction-total', 'data-bkbg-fraction': 'total' }, String(Math.max(1, (a.members || []).length)))
1120 )
1121 : el('div', { className: 'bkbg-tm-dots', role: 'tablist', 'aria-label': __('Team Members Carousel', 'blockenberg') },
1122 (a.members || []).map(function (_, i) {
1123 return el('button', {
1124 key: i,
1125 type: 'button',
1126 className: 'bkbg-tm-dot' + (i === 0 ? ' is-active' : ''),
1127 'data-bkbg-dot': String(i),
1128 'aria-label': __('Go to slide', 'blockenberg') + ' ' + (i + 1)
1129 });
1130 })
1131 )
1132 ),
1133 el('div', { className: 'bkbg-tm-carousel-inner' },
1134 a.carouselNav && el('div', { className: 'bkbg-tm-nav' },
1135 el('button', {
1136 type: 'button',
1137 className: 'bkbg-tm-nav-btn bkbg-tm-prev',
1138 'data-bkbg-nav': 'prev',
1139 'aria-label': __('Previous', 'blockenberg')
1140 }, el('span', { className: 'dashicons dashicons-arrow-left-alt2' })),
1141 el('button', {
1142 type: 'button',
1143 className: 'bkbg-tm-nav-btn bkbg-tm-next',
1144 'data-bkbg-nav': 'next',
1145 'aria-label': __('Next', 'blockenberg')
1146 }, el('span', { className: 'dashicons dashicons-arrow-right-alt2' }))
1147 ),
1148 el('div', { className: 'bkbg-tm-track' },
1149 (a.members || []).map(function (member, index) {
1150 var cardClasses = ['bkbg-tm-card'];
1151 if (a.cardShadow) cardClasses.push('has-shadow');
1152
1153 return el('div', { key: index, className: 'bkbg-tm-slide' },
1154 el('div', { className: cardClasses.join(' ') },
1155 el('div', { className: 'bkbg-tm-photo' },
1156 member.image && member.image.url
1157 ? el('img', { src: member.image.url, alt: (member.image.alt || '') })
1158 : el('div', { className: 'bkbg-tm-photo-placeholder' },
1159 el('span', { className: 'dashicons dashicons-format-image' })
1160 )
1161 ),
1162 el(RichText.Content, { tagName: 'h3', className: 'bkbg-tm-name', value: member.name }),
1163 a.showRole && el(RichText.Content, { tagName: 'div', className: 'bkbg-tm-role', value: member.role }),
1164 a.showBio && el(RichText.Content, { tagName: 'p', className: 'bkbg-tm-bio', value: member.bio }),
1165 renderSocials(member)
1166 )
1167 );
1168 })
1169 )
1170 ),
1171 (a.carouselIndicatorsPosition !== 'top') && (a.carouselIndicators !== 'none') && el('div', { className: 'bkbg-tm-indicators' },
1172 a.carouselIndicators === 'progress'
1173 ? el('div', { className: 'bkbg-tm-progress' }, el('div', { className: 'bkbg-tm-progress-bar', style: { width: '0%' } }))
1174 : a.carouselIndicators === 'fraction'
1175 ? el('div', { className: 'bkbg-tm-fraction', 'aria-label': __('Carousel position', 'blockenberg') },
1176 el('span', { className: 'bkbg-tm-fraction-current', 'data-bkbg-fraction': 'current' }, '1'),
1177 el('span', { 'aria-hidden': 'true' }, '/'),
1178 el('span', { className: 'bkbg-tm-fraction-total', 'data-bkbg-fraction': 'total' }, String(Math.max(1, (a.members || []).length)))
1179 )
1180 : el('div', { className: 'bkbg-tm-dots', role: 'tablist', 'aria-label': __('Team Members Carousel', 'blockenberg') },
1181 (a.members || []).map(function (_, i) {
1182 return el('button', {
1183 key: i,
1184 type: 'button',
1185 className: 'bkbg-tm-dot' + (i === 0 ? ' is-active' : ''),
1186 'data-bkbg-dot': String(i),
1187 'aria-label': __('Go to slide', 'blockenberg') + ' ' + (i + 1)
1188 });
1189 })
1190 )
1191 )
1192 )
1193 : el('div', { className: 'bkbg-tm-grid' },
1194 (a.members || []).map(function (member, index) {
1195 var cardClasses = ['bkbg-tm-card'];
1196 if (a.cardShadow) cardClasses.push('has-shadow');
1197
1198 return el('div', { key: index, className: cardClasses.join(' ') },
1199 el('div', { className: 'bkbg-tm-photo' },
1200 member.image && member.image.url
1201 ? el('img', { src: member.image.url, alt: (member.image.alt || '') })
1202 : el('div', { className: 'bkbg-tm-photo-placeholder' },
1203 el('span', { className: 'dashicons dashicons-format-image' })
1204 )
1205 ),
1206 el(RichText.Content, { tagName: 'h3', className: 'bkbg-tm-name', value: member.name }),
1207 a.showRole && el(RichText.Content, { tagName: 'div', className: 'bkbg-tm-role', value: member.role }),
1208 a.showBio && el(RichText.Content, { tagName: 'p', className: 'bkbg-tm-bio', value: member.bio }),
1209 renderSocials(member)
1210 );
1211 })
1212 )
1213 );
1214 }
1215 });
1216 }() );
1217