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 / bio-card / index.js

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

368 lines 31.2 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 registerBlockType = wp.blocks.registerBlockType;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var MediaUpload = wp.blockEditor.MediaUpload;
11 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
12 var RichText = wp.blockEditor.RichText;
13 var PanelBody = wp.components.PanelBody;
14 var RangeControl = wp.components.RangeControl;
15 var ToggleControl = wp.components.ToggleControl;
16 var TextControl = wp.components.TextControl;
17 var SelectControl = wp.components.SelectControl;
18 var Button = wp.components.Button;
19
20 function getTypographyControl() { return window.bkbgTypographyControl; }
21 function getTypoCssVars() { return window.bkbgTypoCssVars; }
22
23 var LAYOUT_OPTIONS = [
24 { label: __('Card – Centered', 'blockenberg'), value: 'card-center' },
25 { label: __('Card – Left', 'blockenberg'), value: 'card-left' },
26 { label: __('Horizontal', 'blockenberg'), value: 'horizontal' },
27 { label: __('Minimal', 'blockenberg'), value: 'minimal' },
28 ];
29 var SHAPE_OPTIONS = [
30 { label: __('Circle', 'blockenberg'), value: 'circle' },
31 { label: __('Rounded', 'blockenberg'), value: 'rounded' },
32 { label: __('Square', 'blockenberg'), value: 'square' },
33 ];
34 var STATUS_OPTIONS = [
35 { label: __('Available', 'blockenberg'), value: 'available' },
36 { label: __('Busy', 'blockenberg'), value: 'busy' },
37 { label: __('Unavailable', 'blockenberg'), value: 'unavailable' },
38 ];
39 var STATUS_COLORS = { available: '#16a34a', busy: '#f59e0b', unavailable: '#ef4444' };
40 var HEADING_OPTIONS = [
41 { label: 'H2', value: 'h2' }, { label: 'H3', value: 'h3' },
42 { label: 'H4', value: 'h4' }, { label: 'p', value: 'p' },
43 ];
44 var SOCIAL_ICONS = {
45 twitter: 'M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z',
46 linkedin: 'M16 8a6 6 0 016 6v7h-4v-7a2 2 0 00-2-2 2 2 0 00-2 2v7h-4v-7a6 6 0 016-6zM2 9h4v12H2z M2 6.5a2 2 0 114 0 2 2 0 01-4 0z',
47 github: 'M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.746 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z',
48 instagram: 'M16 11.37A4 4 0 1112.63 8 4 4 0 0116 11.37z M17.5 6.5h.01 M7.55 3h8.9C18.44 3 21 5.56 21 7.55v8.9C21 18.44 18.44 21 16.45 21H7.55C5.56 21 3 18.44 3 16.45V7.55C3 5.56 5.56 3 7.55 3z',
49 website: 'M12 2a10 10 0 100 20A10 10 0 0012 2zM2 12h20M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z',
50 email: 'M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z M22 6l-10 7L2 6',
51 youtube: 'M22.54 6.42a2.78 2.78 0 00-1.95-1.97C18.88 4 12 4 12 4s-6.88 0-8.59.46A2.78 2.78 0 001.46 6.42 29 29 0 001 12a29 29 0 00.46 5.58A2.78 2.78 0 003.41 19.6C5.12 20 12 20 12 20s6.88 0 8.59-.46a2.78 2.78 0 001.95-1.95A29 29 0 0023 12a29 29 0 00-.46-5.58z M9.75 15.02l5.75-3.02-5.75-3.02v6.04z',
52 dribbble: 'M12 2a10 10 0 100 20A10 10 0 0012 2z M8.56 2.75c4.37 6.03 6.02 9.42 8.03 17.72m2.54-15.38c-3.72 4.35-8.94 5.66-16.88 5.85m19.5 1.9c-3.5-.93-6.63-.82-8.94 0-2.58.92-5.01 2.86-7.44 6.32',
53 };
54 var SOCIAL_OPTIONS = [
55 { label: 'Twitter / X', value: 'twitter' },
56 { label: 'LinkedIn', value: 'linkedin' },
57 { label: 'GitHub', value: 'github' },
58 { label: 'Instagram', value: 'instagram' },
59 { label: 'Website', value: 'website' },
60 { label: 'Email', value: 'email' },
61 { label: 'YouTube', value: 'youtube' },
62 { label: 'Dribbble', value: 'dribbble' },
63 ];
64
65 function makeId() { return 'bc' + Math.random().toString(36).substr(2, 6); }
66
67 /* Photo radius helper */
68 function photoRadius(shape, size) {
69 if (shape === 'circle') return '50%';
70 if (shape === 'rounded') return Math.round(size * 0.18) + 'px';
71 return '4px';
72 }
73
74 /* Social icon SVG */
75 function SocialIcon(props) {
76 var platform = props.platform;
77 var size = props.size || 18;
78 var color = props.color;
79 var d = SOCIAL_ICONS[platform] || SOCIAL_ICONS.website;
80 var isStroked = ['linkedin', 'instagram', 'website', 'email', 'youtube', 'dribbble'].indexOf(platform) !== -1;
81 return el('svg', { width: size, height: size, viewBox: '0 0 24 24', fill: isStroked ? 'none' : color, stroke: isStroked ? color : 'none', strokeWidth: isStroked ? 2 : 0, strokeLinecap: 'round', strokeLinejoin: 'round' },
82 el('path', { d: d })
83 );
84 }
85
86 /* Render card preview */
87 function BioCardPreview(props) {
88 var a = props.a;
89 var onNameChange = props.onNameChange;
90 var onRoleChange = props.onRoleChange;
91 var onBioChange = props.onBioChange;
92 var isEditor = props.isEditor;
93
94 var isCentered = a.layout === 'card-center' || a.layout === 'minimal';
95 var isHoriz = a.layout === 'horizontal';
96 var align = isCentered ? 'center' : 'flex-start';
97
98 var cardStyle = {
99 maxWidth: a.maxWidth + 'px',
100 margin: '0 auto',
101 background: a.cardBg,
102 borderRadius: a.cardRadius + 'px',
103 padding: a.layout === 'minimal' ? '0' : a.cardPadding + 'px',
104 boxShadow: a.showShadow && a.layout !== 'minimal' ? '0 8px 40px rgba(0,0,0,0.10)' : 'none',
105 display: 'flex',
106 flexDirection: isHoriz ? 'row' : 'column',
107 alignItems: isHoriz ? 'flex-start' : align,
108 gap: isHoriz ? '32px' : '16px',
109 position: 'relative',
110 };
111
112 var photoEl = (a.photoUrl
113 ? el('img', { src: a.photoUrl, alt: a.name, style: { width: a.photoSize + 'px', height: a.photoSize + 'px', objectFit: 'cover', borderRadius: photoRadius(a.photoShape, a.photoSize), border: a.photoBorderWidth + 'px solid ' + a.photoBorderColor, display: 'block', flexShrink: 0 } })
114 : el('div', { style: { width: a.photoSize + 'px', height: a.photoSize + 'px', borderRadius: photoRadius(a.photoShape, a.photoSize), background: a.accentColor, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: Math.round(a.photoSize * 0.4) + 'px', fontWeight: 700, color: '#fff', flexShrink: 0, border: a.photoBorderWidth + 'px solid ' + a.photoBorderColor } },
115 (a.name || 'A').charAt(0).toUpperCase()
116 )
117 );
118
119 return el('div', { className: 'bkbg-bio-card bkbg-bio-card--' + a.layout, style: cardStyle },
120 /* Photo */
121 el('div', { style: { display: 'flex', flexDirection: 'column', alignItems: align, gap: '12px', flexShrink: 0 } },
122 photoEl,
123 /* Availability */
124 a.showAvailability && el('div', { style: { display: 'inline-flex', alignItems: 'center', gap: '6px', background: STATUS_COLORS[a.availabilityStatus] + '18', borderRadius: '99px', padding: '3px 10px 3px 6px' } },
125 el('span', { style: { width: '8px', height: '8px', borderRadius: '50%', background: STATUS_COLORS[a.availabilityStatus], flexShrink: 0 } }),
126 el('span', { style: { fontSize: '12px', fontWeight: 600, color: STATUS_COLORS[a.availabilityStatus] } }, a.availabilityLabel)
127 )
128 ),
129
130 /* Main content */
131 el('div', { style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: isCentered ? 'center' : 'flex-start', textAlign: isCentered ? 'center' : 'left', gap: '4px' } },
132 /* Name */
133 isEditor
134 ? el(RichText, { tagName: a.nameTag, className: 'bkbg-bio-name', value: a.name, onChange: onNameChange, placeholder: __('Name', 'blockenberg'), style: { color: a.nameColor, margin: 0, padding: 0 } })
135 : el(a.nameTag, { className: 'bkbg-bio-name', style: { color: a.nameColor, margin: '0 0 2px' } }, a.name),
136
137 /* Role */
138 isEditor
139 ? el(RichText, { tagName: 'p', className: 'bkbg-bio-role', value: a.role, onChange: onRoleChange, placeholder: __('Role', 'blockenberg'), style: { color: a.roleColor, margin: 0, padding: 0 } })
140 : el('p', { className: 'bkbg-bio-role', style: { color: a.roleColor, margin: '0 0 2px' } }, a.role),
141
142 /* Company */
143 a.company && el('p', { style: { fontSize: (a.roleSize - 1) + 'px', color: a.accentColor, margin: '0 0 8px', fontWeight: 600, letterSpacing: '0.02em' } }, a.company),
144
145 /* Bio */
146 el('div', { style: { marginTop: '8px', marginBottom: '8px' } },
147 isEditor
148 ? el(RichText, { tagName: 'p', className: 'bkbg-bio-bio', value: a.bio, onChange: onBioChange, placeholder: __('Bio text…', 'blockenberg'), style: { color: a.bioColor, margin: 0, padding: 0 } })
149 : el('p', { className: 'bkbg-bio-bio', style: { color: a.bioColor, margin: 0 } }, a.bio)
150 ),
151
152 /* Skills */
153 a.showSkills && a.skills.length > 0 && el('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '6px', justifyContent: isCentered ? 'center' : 'flex-start', marginBottom: '12px' } },
154 a.skills.map(function (skill) {
155 return el('span', { key: skill.id, style: { background: (skill.color || a.accentColor) + '18', color: skill.color || a.accentColor, borderRadius: a.skillTagRadius + 'px', padding: '3px 10px', fontSize: a.skillTagSize + 'px', fontWeight: 600 } }, skill.label);
156 })
157 ),
158
159 /* Social links */
160 a.showSocial && a.socialLinks.length > 0 && el('div', { style: { display: 'flex', gap: '12px', flexWrap: 'wrap', justifyContent: isCentered ? 'center' : 'flex-start', marginBottom: '16px' } },
161 a.socialLinks.map(function (link) {
162 return el('a', { key: link.id, href: link.url || '#', style: { color: a.accentColor, display: 'flex', alignItems: 'center', gap: '4px', textDecoration: 'none', opacity: 0.8 } },
163 el(SocialIcon, { platform: link.platform, size: 18, color: a.accentColor })
164 );
165 })
166 ),
167
168 /* CTA Button */
169 a.showCta && el('a', {
170 href: a.ctaUrl || '#',
171 style: {
172 display: 'inline-flex', alignItems: 'center', gap: '6px',
173 background: a.ctaStyle === 'filled' ? a.accentColor : 'transparent',
174 color: a.ctaStyle === 'filled' ? '#fff' : a.accentColor,
175 border: '2px solid ' + a.accentColor,
176 borderRadius: '8px', padding: '10px 22px',
177 fontSize: '14px', fontWeight: 700, textDecoration: 'none',
178 }
179 }, a.ctaText)
180 )
181 );
182 }
183
184 registerBlockType('blockenberg/bio-card', {
185 edit: function (props) {
186 var a = props.attributes;
187 var setAttributes = props.setAttributes;
188 var skillsState = useState(false);
189 var socialState = useState(false);
190 var _tv = getTypoCssVars();
191 var bpStyle = { paddingTop: a.paddingTop + 'px', paddingBottom: a.paddingBottom + 'px', backgroundColor: a.bgColor || undefined };
192 if (_tv) {
193 Object.assign(bpStyle, _tv(a.nameTypo || {}, '--bkbg-bio-name-'));
194 Object.assign(bpStyle, _tv(a.roleTypo || {}, '--bkbg-bio-role-'));
195 Object.assign(bpStyle, _tv(a.bioTypo || {}, '--bkbg-bio-bio-'));
196 }
197 var blockProps = useBlockProps({ style: bpStyle });
198
199 function addSkill() { setAttributes({ skills: a.skills.concat([{ id: makeId(), label: 'New Skill', color: a.accentColor }]) }); }
200 function removeSkill(id) { setAttributes({ skills: a.skills.filter(function (s) { return s.id !== id; }) }); }
201 function setSkill(id, patch) { setAttributes({ skills: a.skills.map(function (s) { return s.id === id ? Object.assign({}, s, patch) : s; }) }); }
202
203 function addLink() { setAttributes({ socialLinks: a.socialLinks.concat([{ id: makeId(), platform: 'website', url: '' }]) }); }
204 function removeLink(id) { setAttributes({ socialLinks: a.socialLinks.filter(function (l) { return l.id !== id; }) }); }
205 function setLink(id, patch) { setAttributes({ socialLinks: a.socialLinks.map(function (l) { return l.id === id ? Object.assign({}, l, patch) : l; }) }); }
206
207 return el(Fragment, null,
208 el(InspectorControls, null,
209 el(PanelBody, { title: __('Identity', 'blockenberg'), initialOpen: true },
210 el(SelectControl, { label: __('Layout', 'blockenberg'), value: a.layout, options: LAYOUT_OPTIONS, onChange: function (v) { setAttributes({ layout: v }); } }),
211 el(SelectControl, { label: __('Name heading tag', 'blockenberg'), value: a.nameTag, options: HEADING_OPTIONS, onChange: function (v) { setAttributes({ nameTag: v }); } }),
212 el(TextControl, { label: __('Company', 'blockenberg'), value: a.company, onChange: function (v) { setAttributes({ company: v }); } }),
213 el('p', { style: { margin: '8px 0 4px', fontWeight: 600, fontSize: '11px', textTransform: 'uppercase', color: '#757575' } }, __('Photo', 'blockenberg')),
214 el(MediaUploadCheck, null,
215 el(MediaUpload, {
216 onSelect: function (media) { setAttributes({ photoUrl: media.url, photoId: media.id }); },
217 allowedTypes: ['image'],
218 value: a.photoId,
219 render: function (ref) { return el(Button, { onClick: ref.open, variant: 'secondary', size: 'compact' }, a.photoUrl ? __('Change photo', 'blockenberg') : __('Upload photo', 'blockenberg')); }
220 })
221 ),
222 a.photoUrl && el(Button, { onClick: function () { setAttributes({ photoUrl: '', photoId: 0 }); }, variant: 'tertiary', isDestructive: true, size: 'compact', style: { marginTop: '4px', display: 'block' } }, __('Remove photo', 'blockenberg')),
223 el(SelectControl, { label: __('Photo shape', 'blockenberg'), value: a.photoShape, options: SHAPE_OPTIONS, onChange: function (v) { setAttributes({ photoShape: v }); } }),
224 el(RangeControl, { label: __('Photo size (px)', 'blockenberg'), value: a.photoSize, min: 60, max: 200, onChange: function (v) { setAttributes({ photoSize: v }); } }),
225 el(RangeControl, { label: __('Border width (px)', 'blockenberg'), value: a.photoBorderWidth, min: 0, max: 8, onChange: function (v) { setAttributes({ photoBorderWidth: v }); } })
226 ),
227 el(PanelBody, { title: __('Availability', 'blockenberg'), initialOpen: false },
228 el(ToggleControl, { label: __('Show availability badge', 'blockenberg'), checked: a.showAvailability, onChange: function (v) { setAttributes({ showAvailability: v }); }, __nextHasNoMarginBottom: true }),
229 a.showAvailability && el(Fragment, null,
230 el(SelectControl, { label: __('Status', 'blockenberg'), value: a.availabilityStatus, options: STATUS_OPTIONS, onChange: function (v) { setAttributes({ availabilityStatus: v }); } }),
231 el(TextControl, { label: __('Badge label', 'blockenberg'), value: a.availabilityLabel, onChange: function (v) { setAttributes({ availabilityLabel: v }); } })
232 )
233 ),
234 el(PanelBody, { title: __('Skills / Tags', 'blockenberg'), initialOpen: false },
235 el(ToggleControl, { label: __('Show skills', 'blockenberg'), checked: a.showSkills, onChange: function (v) { setAttributes({ showSkills: v }); }, __nextHasNoMarginBottom: true }),
236 ),
237 el(PanelBody, { title: __('Social Links', 'blockenberg'), initialOpen: false },
238 el(ToggleControl, { label: __('Show social links', 'blockenberg'), checked: a.showSocial, onChange: function (v) { setAttributes({ showSocial: v }); }, __nextHasNoMarginBottom: true }),
239 a.showSocial && el(Fragment, null,
240 a.socialLinks.map(function (link) {
241 return el('div', { key: link.id, style: { marginBottom: '10px', padding: '10px', background: '#f9fafb', borderRadius: '8px' } },
242 el(SelectControl, { label: __('Platform', 'blockenberg'), value: link.platform, options: SOCIAL_OPTIONS, onChange: function (v) { setLink(link.id, { platform: v }); } }),
243 el(TextControl, { label: __('URL', 'blockenberg'), value: link.url, onChange: function (v) { setLink(link.id, { url: v }); } }),
244 el(Button, { onClick: function () { removeLink(link.id); }, variant: 'tertiary', isDestructive: true, size: 'compact' }, __('Remove', 'blockenberg'))
245 );
246 }),
247 el(Button, { onClick: addLink, variant: 'secondary', size: 'compact' }, __('+ Add Link', 'blockenberg'))
248 )
249 ),
250 el(PanelBody, { title: __('CTA Button', 'blockenberg'), initialOpen: false },
251 el(ToggleControl, { label: __('Show CTA button', 'blockenberg'), checked: a.showCta, onChange: function (v) { setAttributes({ showCta: v }); }, __nextHasNoMarginBottom: true }),
252 a.showCta && el(Fragment, null,
253 el(TextControl, { label: __('Button text', 'blockenberg'), value: a.ctaText, onChange: function (v) { setAttributes({ ctaText: v }); } }),
254 el(TextControl, { label: __('Button URL', 'blockenberg'), value: a.ctaUrl, onChange: function (v) { setAttributes({ ctaUrl: v }); } }),
255 el(ToggleControl, { label: __('Open in new tab', 'blockenberg'), checked: a.ctaTarget, onChange: function (v) { setAttributes({ ctaTarget: v }); }, __nextHasNoMarginBottom: true }),
256 el(SelectControl, { label: __('Button style', 'blockenberg'), value: a.ctaStyle, options: [{ label: 'Filled', value: 'filled' }, { label: 'Outline', value: 'outline' }], onChange: function (v) { setAttributes({ ctaStyle: v }); } })
257 )
258 ),
259 el(PanelBody, { title: __('Card Style', 'blockenberg'), initialOpen: false },
260 el(RangeControl, { label: __('Max width (px)', 'blockenberg'), value: a.maxWidth, min: 280, max: 900, onChange: function (v) { setAttributes({ maxWidth: v }); } }),
261 el(RangeControl, { label: __('Card radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 40, onChange: function (v) { setAttributes({ cardRadius: v }); } }),
262 el(RangeControl, { label: __('Card padding (px)', 'blockenberg'), value: a.cardPadding, min: 16, max: 80, onChange: function (v) { setAttributes({ cardPadding: v }); } }),
263 el(ToggleControl, { label: __('Show shadow', 'blockenberg'), checked: a.showShadow, onChange: function (v) { setAttributes({ showShadow: v }); }, __nextHasNoMarginBottom: true })
264 ),
265 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
266 (function () { var TC = getTypographyControl(); return TC ? el(TC, { label: __('Name', 'blockenberg'), value: a.nameTypo || {}, onChange: function (v) { setAttributes({ nameTypo: v }); } }) : null; })(),
267 (function () { var TC = getTypographyControl(); return TC ? el(TC, { label: __('Role', 'blockenberg'), value: a.roleTypo || {}, onChange: function (v) { setAttributes({ roleTypo: v }); } }) : null; })(),
268 (function () { var TC = getTypographyControl(); return TC ? el(TC, { label: __('Bio', 'blockenberg'), value: a.bioTypo || {}, onChange: function (v) { setAttributes({ bioTypo: v }); } }) : null; })(),
269 a.showSkills && el(Fragment, null,
270 a.skills.map(function (skill) {
271 return el('div', { key: skill.id, style: { display: 'flex', gap: '6px', marginBottom: '8px', alignItems: 'center' } },
272 el(TextControl, { value: skill.label, onChange: function (v) { setSkill(skill.id, { label: v }); }, style: { flex: 1, margin: 0 } }),
273 el(Button, { onClick: function () { removeSkill(skill.id); }, variant: 'tertiary', isDestructive: true, size: 'compact' }, '')
274 );
275 }),
276 el(RangeControl, { label: __('Tag size (px)', 'blockenberg'), value: a.skillTagSize, min: 10, max: 18, onChange: function (v) { setAttributes({ skillTagSize: v }); } }),
277 el(RangeControl, { label: __('Tag radius (px)', 'blockenberg'), value: a.skillTagRadius, min: 0, max: 99, onChange: function (v) { setAttributes({ skillTagRadius: v }); } }),
278 el(Button, { onClick: addSkill, variant: 'secondary', size: 'compact' }, __('+ Add Tag', 'blockenberg'))
279 )
280 ),
281 el(PanelColorSettings, {
282 title: __('Colors', 'blockenberg'), initialOpen: false,
283 colorSettings: [
284 { value: a.accentColor, onChange: function (v) { setAttributes({ accentColor: v || '' }); }, label: __('Accent', 'blockenberg') },
285 { value: a.cardBg, onChange: function (v) { setAttributes({ cardBg: v || '' }); }, label: __('Card background', 'blockenberg') },
286 { value: a.nameColor, onChange: function (v) { setAttributes({ nameColor: v || '' }); }, label: __('Name', 'blockenberg') },
287 { value: a.roleColor, onChange: function (v) { setAttributes({ roleColor: v || '' }); }, label: __('Role', 'blockenberg') },
288 { value: a.bioColor, onChange: function (v) { setAttributes({ bioColor: v || '' }); }, label: __('Bio', 'blockenberg') },
289 { value: a.photoBorderColor, onChange: function (v) { setAttributes({ photoBorderColor: v || '' }); }, label: __('Photo border', 'blockenberg') },
290 { value: a.bgColor, onChange: function (v) { setAttributes({ bgColor: v || '' }); }, label: __('Section background', 'blockenberg') },
291 ]
292 }),
293 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
294 el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
295 el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
296 )
297 ),
298
299 el('div', blockProps,
300 el(BioCardPreview, {
301 a: a,
302 isEditor: true,
303 onNameChange: function (v) { setAttributes({ name: v }); },
304 onRoleChange: function (v) { setAttributes({ role: v }); },
305 onBioChange: function (v) { setAttributes({ bio: v }); },
306 })
307 )
308 );
309 },
310
311 save: function (props) {
312 var a = props.attributes;
313 var _tv = getTypoCssVars();
314 var saveStyle = { paddingTop: a.paddingTop + 'px', paddingBottom: a.paddingBottom + 'px', backgroundColor: a.bgColor || undefined };
315 if (_tv) {
316 Object.assign(saveStyle, _tv(a.nameTypo || {}, '--bkbg-bio-name-'));
317 Object.assign(saveStyle, _tv(a.roleTypo || {}, '--bkbg-bio-role-'));
318 Object.assign(saveStyle, _tv(a.bioTypo || {}, '--bkbg-bio-bio-'));
319 }
320 var blockProps = wp.blockEditor.useBlockProps.save({ className: 'bkbg-bio-card-wrap', style: saveStyle });
321 var isCentered = a.layout === 'card-center' || a.layout === 'minimal';
322 var isHoriz = a.layout === 'horizontal';
323 var align = isCentered ? 'center' : 'flex-start';
324
325 function socialPath(platform) { return SOCIAL_ICONS[platform] || SOCIAL_ICONS.website; }
326 function isSVGStroked(p) { return ['linkedin', 'instagram', 'website', 'email', 'youtube', 'dribbble'].indexOf(p) !== -1; }
327
328 return el('div', blockProps,
329 el('div', { className: 'bkbg-bio-card bkbg-bio-card--' + a.layout, style: { maxWidth: a.maxWidth + 'px', margin: '0 auto', background: a.cardBg, borderRadius: a.cardRadius + 'px', padding: a.layout === 'minimal' ? '0' : a.cardPadding + 'px', boxShadow: a.showShadow && a.layout !== 'minimal' ? '0 8px 40px rgba(0,0,0,0.10)' : 'none', display: 'flex', flexDirection: isHoriz ? 'row' : 'column', alignItems: isHoriz ? 'flex-start' : align, gap: isHoriz ? '32px' : '16px' } },
330 el('div', { style: { display: 'flex', flexDirection: 'column', alignItems: align, gap: '12px', flexShrink: 0 } },
331 a.photoUrl
332 ? el('img', { src: a.photoUrl, alt: a.name, width: a.photoSize, height: a.photoSize, style: { width: a.photoSize + 'px', height: a.photoSize + 'px', objectFit: 'cover', borderRadius: photoRadius(a.photoShape, a.photoSize), border: a.photoBorderWidth + 'px solid ' + a.photoBorderColor, display: 'block', flexShrink: 0 } })
333 : el('div', { 'aria-hidden': 'true', style: { width: a.photoSize + 'px', height: a.photoSize + 'px', borderRadius: photoRadius(a.photoShape, a.photoSize), background: a.accentColor, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: Math.round(a.photoSize * 0.4) + 'px', fontWeight: 700, color: '#fff', flexShrink: 0, border: a.photoBorderWidth + 'px solid ' + a.photoBorderColor } }, (a.name || 'A').charAt(0).toUpperCase()),
334 a.showAvailability && el('div', { style: { display: 'inline-flex', alignItems: 'center', gap: '6px', background: STATUS_COLORS[a.availabilityStatus] + '18', borderRadius: '99px', padding: '3px 10px 3px 6px' } },
335 el('span', { style: { width: '8px', height: '8px', borderRadius: '50%', background: STATUS_COLORS[a.availabilityStatus], flexShrink: 0 } }),
336 el('span', { style: { fontSize: '12px', fontWeight: 600, color: STATUS_COLORS[a.availabilityStatus] } }, a.availabilityLabel)
337 )
338 ),
339 el('div', { style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: isCentered ? 'center' : 'flex-start', textAlign: isCentered ? 'center' : 'left', gap: '4px' } },
340 el(a.nameTag, { className: 'bkbg-bio-name', style: { color: a.nameColor, margin: '0 0 2px' } }, a.name),
341 el('p', { className: 'bkbg-bio-role', style: { color: a.roleColor, margin: '0 0 2px' } }, a.role),
342 a.company && el('p', { style: { fontSize: (a.roleSize - 1) + 'px', color: a.accentColor, margin: '0 0 8px', fontWeight: 600, letterSpacing: '0.02em' } }, a.company),
343 el('div', { style: { marginTop: '8px', marginBottom: '8px' } },
344 el(RichText.Content, { tagName: 'p', className: 'bkbg-bio-bio', value: a.bio, style: { color: a.bioColor, margin: 0 } })
345 ),
346 a.showSkills && a.skills.length > 0 && el('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '6px', justifyContent: isCentered ? 'center' : 'flex-start', marginBottom: '12px' } },
347 a.skills.map(function (skill) {
348 return el('span', { key: skill.id, style: { background: (skill.color || a.accentColor) + '18', color: skill.color || a.accentColor, borderRadius: a.skillTagRadius + 'px', padding: '3px 10px', fontSize: a.skillTagSize + 'px', fontWeight: 600 } }, skill.label);
349 })
350 ),
351 a.showSocial && a.socialLinks.length > 0 && el('div', { style: { display: 'flex', gap: '12px', flexWrap: 'wrap', justifyContent: isCentered ? 'center' : 'flex-start', marginBottom: '16px' } },
352 a.socialLinks.map(function (link) {
353 var stroked = isSVGStroked(link.platform);
354 return el('a', { key: link.id, href: link.url || '#', target: a.ctaTarget ? '_blank' : undefined, rel: a.ctaTarget ? 'noopener noreferrer' : undefined, 'aria-label': link.platform, style: { color: a.accentColor, display: 'flex', alignItems: 'center', textDecoration: 'none', opacity: 0.8 } },
355 el('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: stroked ? 'none' : a.accentColor, stroke: stroked ? a.accentColor : 'none', strokeWidth: stroked ? 2 : 0, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': 'true' },
356 el('path', { d: socialPath(link.platform) })
357 )
358 );
359 })
360 ),
361 a.showCta && el('a', { href: a.ctaUrl || '#', target: a.ctaTarget ? '_blank' : undefined, rel: a.ctaTarget ? 'noopener noreferrer' : undefined, style: { display: 'inline-flex', alignItems: 'center', background: a.ctaStyle === 'filled' ? a.accentColor : 'transparent', color: a.ctaStyle === 'filled' ? '#fff' : a.accentColor, border: '2px solid ' + a.accentColor, borderRadius: '8px', padding: '10px 22px', fontSize: '14px', fontWeight: 700, textDecoration: 'none' } }, a.ctaText)
362 )
363 )
364 );
365 }
366 });
367 }() );
368