( function () { var el = wp.element.createElement; var Fragment = wp.element.Fragment; var __ = wp.i18n.__; var registerBlockType = wp.blocks.registerBlockType; var InspectorControls = wp.blockEditor.InspectorControls; var useBlockProps = wp.blockEditor.useBlockProps; var RichText = wp.blockEditor.RichText; var MediaUpload = wp.blockEditor.MediaUpload; var PanelBody = wp.components.PanelBody; var PanelColorSettings = wp.blockEditor.PanelColorSettings; var Button = wp.components.Button; var ToggleControl = wp.components.ToggleControl; var RangeControl = wp.components.RangeControl; var SelectControl = wp.components.SelectControl; var TextControl = wp.components.TextControl; /* ── Typography lazy getters ───────────────────────────────────────── */ var _Typo, _tv; Object.defineProperty(window, '__bkbgAbTypoReady', { get: function () { if (!_Typo) _Typo = window.bkbgTypographyControl; if (!_tv) _tv = window.bkbgTypoCssVars; return !!(_Typo && _tv); }}); function getTypoCssVars() { window.__bkbgAbTypoReady; return _tv; } function getTypoComponent() { window.__bkbgAbTypoReady; return _Typo; } /* ── Shared wrap style ─────────────────────────────────────────────── */ function buildWrapStyle(a) { var tv = getTypoCssVars(); var s = { '--bkbg-ab-size': a.avatarSize + 'px', '--bkbg-ab-pad': a.padding + 'px', '--bkbg-ab-gap': a.gap + 'px', '--bkbg-ab-bg': a.bgColor, '--bkbg-ab-border': a.borderColor, '--bkbg-ab-radius': a.borderRadius + 'px', '--bkbg-ab-name-size': a.nameSize + 'px', '--bkbg-ab-name-w': a.nameWeight, '--bkbg-ab-name-clr': a.nameColor, '--bkbg-ab-role-size': a.roleSize + 'px', '--bkbg-ab-role-clr': a.roleColor, '--bkbg-ab-bio-size': a.bioSize + 'px', '--bkbg-ab-bio-clr': a.bioColor, '--bkbg-ab-bio-lh': a.bioLineHeight, '--bkbg-ab-link-clr': a.linkColor, '--bkbg-ab-link-hov': a.linkHoverColor }; if (tv) { Object.assign(s, tv(a.nameTypo || {}, '--bkbg-ab-name-')); Object.assign(s, tv(a.roleTypo || {}, '--bkbg-ab-role-')); Object.assign(s, tv(a.bioTypo || {}, '--bkbg-ab-bio-')); } return s; } var fontWeightOptions = [ { label: '400', value: 400 }, { label: '500', value: 500 }, { label: '600', value: 600 }, { label: '700', value: 700 }, { label: '800', value: 800 }, { label: '900', value: 900 } ]; var platformOptions = [ { label: 'Twitter / X', value: 'twitter' }, { label: 'LinkedIn', value: 'linkedin' }, { label: 'Facebook', value: 'facebook' }, { label: 'Instagram', value: 'instagram' }, { label: 'YouTube', value: 'youtube' }, { label: 'GitHub', value: 'github' }, { label: 'Website', value: 'website' }, { label: 'Email', value: 'email' } ]; /* Platform SVG icons */ var platformIcons = { twitter: '', linkedin: '', facebook: '', instagram: '', youtube: '', github: '', website: '', email: '' }; function uid() { return Math.random().toString(36).slice(2, 7); } function defaultLink() { return { id: uid(), platform: 'website', url: '', label: 'Website' }; } function AvatarPlaceholder(_ref) { var size = _ref.size; return el('div', { className: 'bkbg-ab-avatar-placeholder', style: { width: size + 'px', height: size + 'px' } }, el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' }, el('path', { d: 'M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2M12 11a4 4 0 100-8 4 4 0 000 8z', stroke: 'currentColor', strokeWidth: 2, fill: 'none' }) ) ); } registerBlockType('blockenberg/author-box', { title: __('Author Box', 'blockenberg'), description: __('Blog author profile card with avatar, bio and social links.', 'blockenberg'), category: 'bkbg-business', icon: el('svg', { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' }, el('path', { d: 'M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2M12 11a4 4 0 100-8 4 4 0 000 8z', stroke: 'currentColor', strokeWidth: 2, fill: 'none' }) ), attributes: { name: { type: 'string', default: 'Jane Smith' }, role: { type: 'string', default: 'Content Writer' }, bio: { type: 'string', default: 'Jane writes about technology, design, and the future of the web. She has 10+ years of experience crafting compelling stories for top-tier publications.' }, avatarUrl: { type: 'string', default: '' }, avatarId: { type: 'number', default: 0 }, avatarSize: { type: 'number', default: 88 }, avatarShape: { type: 'string', default: 'circle' }, layout: { type: 'string', default: 'horizontal' }, showRole: { type: 'boolean', default: true }, links: { type: 'array', default: [ { id: 'l1', platform: 'twitter', url: '', label: 'Twitter' }, { id: 'l2', platform: 'linkedin', url: '', label: 'LinkedIn' }, { id: 'l3', platform: 'website', url: '', label: 'Website' } ]}, showLinks: { type: 'boolean', default: true }, padding: { type: 'number', default: 28 }, gap: { type: 'number', default: 24 }, bgColor: { type: 'string', default: '#f9fafb' }, borderColor: { type: 'string', default: '#e5e7eb' }, borderRadius: { type: 'number', default: 14 }, showBorder: { type: 'boolean', default: true }, nameSize: { type: 'number', default: 20 }, nameWeight: { type: 'number', default: 700 }, nameColor: { type: 'string', default: '#111827' }, roleSize: { type: 'number', default: 14 }, roleColor: { type: 'string', default: '#6b7280' }, bioSize: { type: 'number', default: 15 }, bioColor: { type: 'string', default: '#374151' }, bioLineHeight: { type: 'string', default: '1.7' }, linkColor: { type: 'string', default: '#2563eb' }, linkHoverColor:{ type: 'string', default: '#1d4ed8' } }, edit: function (props) { var a = props.attributes; var setAttr = props.setAttributes; var links = a.links; function updateLink(i, field, val) { setAttr({ links: links.map(function (l, j) { return j === i ? Object.assign({}, l, { [field]: val }) : l; })}); } function addLink() { setAttr({ links: links.concat(defaultLink()) }); } function removeLink(i) { setAttr({ links: links.filter(function (_, j) { return j !== i; }) }); } function moveLink(i, dir) { var arr = links.slice(); var t = i + dir; if (t < 0 || t >= arr.length) return; var tmp = arr[i]; arr[i] = arr[t]; arr[t] = tmp; setAttr({ links: arr }); } var wrapStyle = buildWrapStyle(a); var blockProps = useBlockProps({ className: 'bkbg-ab-wrap bkbg-ab-layout--' + a.layout + (a.showBorder ? ' bkbg-ab-bordered' : ''), style: wrapStyle }); var inspector = el(InspectorControls, null, el(PanelBody, { title: __('Avatar', 'blockenberg'), initialOpen: true }, el(MediaUpload, { onSelect: function (m) { setAttr({ avatarUrl: m.url, avatarId: m.id }); }, type: 'image', value: a.avatarId, render: function (p) { return el(Fragment, null, a.avatarUrl && el('img', { src: a.avatarUrl, style: { width: 60, height: 60, borderRadius: '50%', objectFit: 'cover', display: 'block', marginBottom: 8 } }), el(Button, { variant: a.avatarUrl ? 'secondary' : 'primary', isSmall: true, onClick: p.open }, a.avatarUrl ? __('Change Avatar', 'blockenberg') : __('Upload Avatar', 'blockenberg')), a.avatarUrl && el(Button, { variant: 'tertiary', isSmall: true, isDestructive: true, onClick: function () { setAttr({ avatarUrl: '', avatarId: 0 }); }, style: { marginLeft: 8 } }, __('Remove', 'blockenberg')) ); } }), el(RangeControl, { label: __('Avatar size (px)', 'blockenberg'), value: a.avatarSize, min: 40, max: 200, onChange: function (v) { setAttr({ avatarSize: v }); } }), el(SelectControl, { label: __('Avatar shape', 'blockenberg'), value: a.avatarShape, options: [ { label: 'Circle', value: 'circle' }, { label: 'Rounded', value: 'rounded' }, { label: 'Square', value: 'square' } ], onChange: function (v) { setAttr({ avatarShape: v }); } }) ), el(PanelBody, { title: __('Layout & Style', 'blockenberg'), initialOpen: false }, el(SelectControl, { label: __('Layout', 'blockenberg'), value: a.layout, options: [ { label: 'Horizontal (avatar left)', value: 'horizontal' }, { label: 'Vertical (avatar centered)',value: 'vertical' } ], onChange: function (v) { setAttr({ layout: v }); } }), el(RangeControl, { label: __('Padding (px)', 'blockenberg'), value: a.padding, min: 8, max: 64, onChange: function (v) { setAttr({ padding: v }); } }), el(RangeControl, { label: __('Gap (px)', 'blockenberg'), value: a.gap, min: 8, max: 64, onChange: function (v) { setAttr({ gap: v }); } }), el(RangeControl, { label: __('Border radius (px)', 'blockenberg'), value: a.borderRadius, min: 0, max: 40, onChange: function (v) { setAttr({ borderRadius: v }); } }), el(ToggleControl, { label: __('Show border', 'blockenberg'), checked: a.showBorder, onChange: function (v) { setAttr({ showBorder: v }); }, __nextHasNoMarginBottom: true }), el(ToggleControl, { label: __('Show role / position', 'blockenberg'), checked: a.showRole, onChange: function (v) { setAttr({ showRole: v }); }, __nextHasNoMarginBottom: true }) ), el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false }, getTypoComponent() && el(getTypoComponent(), { label: __('Name Typography', 'blockenberg'), value: a.nameTypo || {}, onChange: function (v) { setAttr({ nameTypo: v }); } }), getTypoComponent() && el(getTypoComponent(), { label: __('Role Typography', 'blockenberg'), value: a.roleTypo || {}, onChange: function (v) { setAttr({ roleTypo: v }); } }), getTypoComponent() && el(getTypoComponent(), { label: __('Bio Typography', 'blockenberg'), value: a.bioTypo || {}, onChange: function (v) { setAttr({ bioTypo: v }); } }) ), el(PanelBody, { title: __('Social Links', 'blockenberg'), initialOpen: false }, el(ToggleControl, { label: __('Show social links', 'blockenberg'), checked: a.showLinks, onChange: function (v) { setAttr({ showLinks: v }); }, __nextHasNoMarginBottom: true }), a.showLinks && el(Fragment, null, links.map(function (link, i) { return el('div', { key: link.id, className: 'bkbg-ab-link-row' }, el(SelectControl, { label: __('Platform', 'blockenberg'), value: link.platform, options: platformOptions, onChange: function (v) { updateLink(i, 'platform', v); } }), el(TextControl, { label: __('URL', 'blockenberg'), type: 'url', value: link.url, onChange: function (v) { updateLink(i, 'url', v); } }), el('div', { style: { display: 'flex', gap: 4, marginBottom: 12 } }, i > 0 && el(Button, { isSmall: true, variant: 'tertiary', onClick: function () { moveLink(i, -1); } }, '↑'), i < links.length - 1 && el(Button, { isSmall: true, variant: 'tertiary', onClick: function () { moveLink(i, 1); } }, '↓'), el(Button, { isSmall: true, variant: 'tertiary', isDestructive: true, onClick: function () { removeLink(i); } }, '✕') ) ); }), el(Button, { variant: 'secondary', isSmall: true, onClick: addLink }, __('+ Add Link', 'blockenberg')) ) ), el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false }, el(PanelColorSettings, { title: __('Colors', 'blockenberg'), initialOpen: false, colorSettings: [ { label: __('Background', 'blockenberg'), value: a.bgColor, onChange: function(v){ setAttr({ bgColor: v||'#f9fafb' }); } }, { label: __('Border', 'blockenberg'), value: a.borderColor, onChange: function(v){ setAttr({ borderColor: v||'#e5e7eb' }); } }, { label: __('Name', 'blockenberg'), value: a.nameColor, onChange: function(v){ setAttr({ nameColor: v||'#111827' }); } }, { label: __('Role', 'blockenberg'), value: a.roleColor, onChange: function(v){ setAttr({ roleColor: v||'#6b7280' }); } }, { label: __('Bio text', 'blockenberg'), value: a.bioColor, onChange: function(v){ setAttr({ bioColor: v||'#374151' }); } }, { label: __('Link color', 'blockenberg'), value: a.linkColor, onChange: function(v){ setAttr({ linkColor: v||'#2563eb' }); } }, { label: __('Link (hover)', 'blockenberg'), value: a.linkHoverColor, onChange: function(v){ setAttr({ linkHoverColor: v||'#1d4ed8' }); } } ] }) ) ); /* ── Avatar image ── */ var avatarEl; if (a.avatarUrl) { avatarEl = el(MediaUpload, { onSelect: function (m) { setAttr({ avatarUrl: m.url, avatarId: m.id }); }, type: 'image', value: a.avatarId, render: function (p) { return el('img', { src: a.avatarUrl, alt: a.name, className: 'bkbg-ab-avatar bkbg-ab-avatar--' + a.avatarShape, style: { width: a.avatarSize + 'px', height: a.avatarSize + 'px', cursor: 'pointer' }, onClick: p.open, title: __('Click to change avatar', 'blockenberg') }); } }); } else { avatarEl = el(AvatarPlaceholder, { size: a.avatarSize }); } /* ── Social links ── */ var linksEl = a.showLinks && el('div', { className: 'bkbg-ab-links' }, links.filter(function (l) { return l.url; }).map(function (l) { return el('a', { key: l.id, href: '#', className: 'bkbg-ab-link bkbg-ab-link--' + l.platform, title: l.label || l.platform, dangerouslySetInnerHTML: { __html: platformIcons[l.platform] || '' } }); }), links.filter(function (l) { return !l.url; }).map(function (l) { return el('span', { key: l.id, className: 'bkbg-ab-link bkbg-ab-link--' + l.platform + ' bkbg-ab-link--empty', title: (l.label || l.platform) + ' (no URL set)', style: { opacity: 0.35 }, dangerouslySetInnerHTML: { __html: platformIcons[l.platform] || '' } }); }) ); return el(Fragment, null, inspector, el('div', blockProps, el('div', { className: 'bkbg-ab-inner' }, el('div', { className: 'bkbg-ab-avatar-col' }, avatarEl), el('div', { className: 'bkbg-ab-content' }, el(TextControl, { label: __('Name', 'blockenberg'), value: a.name, className: 'bkbg-ab-name-input', onChange: function (v) { setAttr({ name: v }); } }), a.showRole && el(TextControl, { label: __('Role', 'blockenberg'), value: a.role, className: 'bkbg-ab-role-input', onChange: function (v) { setAttr({ role: v }); } }), el(RichText, { tagName: 'p', className: 'bkbg-ab-bio', value: a.bio, onChange: function (v) { setAttr({ bio: v }); }, placeholder: __('Author bio…', 'blockenberg'), allowedFormats: ['core/bold', 'core/italic', 'core/link'] }), linksEl ) ) ) ); }, save: function (props) { var a = props.attributes; var blockProps = wp.blockEditor.useBlockProps.save({ className: 'bkbg-ab-wrap bkbg-ab-layout--' + a.layout + (a.showBorder ? ' bkbg-ab-bordered' : ''), style: buildWrapStyle(a) }); return el('div', blockProps, el('div', { className: 'bkbg-ab-inner' }, el('div', { className: 'bkbg-ab-avatar-col' }, a.avatarUrl ? el('img', { src: a.avatarUrl, alt: a.name, className: 'bkbg-ab-avatar bkbg-ab-avatar--' + a.avatarShape, loading: 'lazy' }) : el('div', { className: 'bkbg-ab-avatar-placeholder bkbg-ab-avatar--' + a.avatarShape }) ), el('div', { className: 'bkbg-ab-content' }, el('h3', { className: 'bkbg-ab-name' }, a.name), a.showRole && el('p', { className: 'bkbg-ab-role' }, a.role), el(RichText.Content, { tagName: 'p', className: 'bkbg-ab-bio', value: a.bio }), a.showLinks && el('div', { className: 'bkbg-ab-links' }, a.links.filter(function (l) { return l.url; }).map(function (l) { return el('a', { key: l.id, href: l.platform === 'email' ? 'mailto:' + l.url : l.url, className: 'bkbg-ab-link bkbg-ab-link--' + l.platform, target: l.platform !== 'email' ? '_blank' : undefined, rel: l.platform !== 'email' ? 'noopener noreferrer' : undefined, 'aria-label': l.label || l.platform }); }) ) ) ) ); } }); }() );