| 1 |
( function () { |
| 2 |
var el = wp.element.createElement; |
| 3 |
var Fragment = wp.element.Fragment; |
| 4 |
var useState = wp.element.useState; |
| 5 |
var __ = wp.i18n.__; |
| 6 |
var registerBlockType = wp.blocks.registerBlockType; |
| 7 |
var InspectorControls = wp.blockEditor.InspectorControls; |
| 8 |
var RichText = wp.blockEditor.RichText; |
| 9 |
var MediaUpload = wp.blockEditor.MediaUpload; |
| 10 |
var MediaUploadCheck = wp.blockEditor.MediaUploadCheck; |
| 11 |
var useBlockProps = wp.blockEditor.useBlockProps; |
| 12 |
var PanelBody = wp.components.PanelBody; |
| 13 |
var Button = wp.components.Button; |
| 14 |
var ToggleControl = wp.components.ToggleControl; |
| 15 |
var RangeControl = wp.components.RangeControl; |
| 16 |
var SelectControl = wp.components.SelectControl; |
| 17 |
var TextControl = wp.components.TextControl; |
| 18 |
var ColorPicker = wp.components.ColorPicker; |
| 19 |
var Popover = wp.components.Popover; |
| 20 |
|
| 21 |
var _tc, _tv; |
| 22 |
function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); } |
| 23 |
function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); } |
| 24 |
var IP = function () { return window.bkbgIconPicker; }; |
| 25 |
|
| 26 |
function makeId() { return 'lb' + Math.random().toString(36).substr(2, 5); } |
| 27 |
|
| 28 |
var LINK_STYLE_OPTIONS = [ |
| 29 |
{ label: __('Filled', 'blockenberg'), value: 'filled' }, |
| 30 |
{ label: __('Outline', 'blockenberg'), value: 'outline' }, |
| 31 |
{ label: __('Ghost', 'blockenberg'), value: 'ghost' }, |
| 32 |
]; |
| 33 |
|
| 34 |
function buildWrapStyle(a) { |
| 35 |
var _tvFn = getTypoCssVars(); |
| 36 |
var s = { |
| 37 |
'--bkbg-lib-accent': a.accentColor, |
| 38 |
'--bkbg-lib-name-color': a.nameColor, |
| 39 |
'--bkbg-lib-title-color': a.titleColor, |
| 40 |
'--bkbg-lib-bio-color': a.bioColor, |
| 41 |
'--bkbg-lib-btn-bg': a.btnBg, |
| 42 |
'--bkbg-lib-btn-color': a.btnColor, |
| 43 |
'--bkbg-lib-btn-border': a.btnBorderColor, |
| 44 |
'--bkbg-lib-btn-r': a.buttonRadius + 'px', |
| 45 |
'--bkbg-lib-btn-gap': a.buttonGap + 'px', |
| 46 |
'--bkbg-lib-btn-max-w': a.buttonMaxWidth + 'px', |
| 47 |
'--bkbg-lib-btn-pad-v': a.buttonPaddingV + 'px', |
| 48 |
'--bkbg-lib-avatar-sz': a.avatarSize + 'px', |
| 49 |
'--bkbg-lib-avatar-r': a.avatarRadius + '%', |
| 50 |
'--bkbg-lib-avatar-border-w': a.avatarBorderWidth + 'px', |
| 51 |
'--bkbg-lib-avatar-border-c': a.avatarBorderColor, |
| 52 |
paddingTop: a.paddingTop + 'px', |
| 53 |
paddingBottom: a.paddingBottom + 'px', |
| 54 |
backgroundColor: a.bgColor || undefined, |
| 55 |
}; |
| 56 |
if (_tvFn) { |
| 57 |
Object.assign(s, _tvFn(a.nameTypo, '--bkbg-lib-n-')); |
| 58 |
Object.assign(s, _tvFn(a.taglineTypo, '--bkbg-lib-tl-')); |
| 59 |
Object.assign(s, _tvFn(a.bioTypo, '--bkbg-lib-b-')); |
| 60 |
Object.assign(s, _tvFn(a.buttonTypo, '--bkbg-lib-bt-')); |
| 61 |
} |
| 62 |
return s; |
| 63 |
} |
| 64 |
|
| 65 |
function renderColorControl(key, label, value, onChange, openKey, setOpenKey) { |
| 66 |
var isOpen = openKey === key; |
| 67 |
return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } }, |
| 68 |
el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label), |
| 69 |
el('div', { style: { position: 'relative', flexShrink: 0 } }, |
| 70 |
el('button', { type: 'button', title: value || 'default', onClick: function () { setOpenKey(isOpen ? null : key); }, |
| 71 |
style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#cccccc' } |
| 72 |
}), |
| 73 |
isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } }, |
| 74 |
el('div', { style: { padding: '8px' } }, |
| 75 |
el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange }) |
| 76 |
) |
| 77 |
) |
| 78 |
) |
| 79 |
); |
| 80 |
} |
| 81 |
|
| 82 |
/* ───────────── Link button preview ─────────────────────────────── */ |
| 83 |
function LinkButton(props) { |
| 84 |
var link = props.link; |
| 85 |
var a = props.a; |
| 86 |
var style = link.style || a.buttonStyle; |
| 87 |
var isFilled = style === 'filled'; |
| 88 |
var isOutline = style === 'outline'; |
| 89 |
var bg = isFilled ? a.btnBg : 'transparent'; |
| 90 |
var color = isFilled ? a.btnColor : a.btnBg; |
| 91 |
var border = (isFilled ? 'none' : '2px solid ' + (isOutline ? a.btnBorderColor || a.btnBg : 'transparent')); |
| 92 |
return el('div', { className: 'bkbg-lib-btn bkbg-lib-btn--' + style, |
| 93 |
style: { |
| 94 |
display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px', |
| 95 |
background: bg, color: color, border: border, |
| 96 |
borderRadius: a.buttonRadius + 'px', padding: a.buttonPaddingV + 'px 20px', |
| 97 |
cursor: 'default', |
| 98 |
width: '100%', boxSizing: 'border-box', |
| 99 |
}}, |
| 100 |
a.showIcons && link.icon && el('span', { 'aria-hidden': 'true' }, (link.iconType || 'custom-char') !== 'custom-char' && IP() ? IP().buildEditorIcon(link.iconType, link.icon, link.iconDashicon, link.iconImageUrl, link.iconDashiconColor) : link.icon), |
| 101 |
el('span', null, link.label || __('Link', 'blockenberg')) |
| 102 |
); |
| 103 |
} |
| 104 |
|
| 105 |
registerBlockType('blockenberg/link-in-bio', { |
| 106 |
title: __('Link in Bio', 'blockenberg'), |
| 107 |
icon: 'admin-links', |
| 108 |
category: 'bkbg-business', |
| 109 |
|
| 110 |
edit: function (props) { |
| 111 |
var a = props.attributes; |
| 112 |
var setAttributes = props.setAttributes; |
| 113 |
|
| 114 |
var openColorKeyState = useState(null); |
| 115 |
var openColorKey = openColorKeyState[0]; |
| 116 |
var setOpenColorKey = openColorKeyState[1]; |
| 117 |
|
| 118 |
var blockProps = useBlockProps({ style: buildWrapStyle(a) }); |
| 119 |
|
| 120 |
function cc(key, label, attrKey) { |
| 121 |
return renderColorControl(key, label, a[attrKey], function (val) { |
| 122 |
var upd = {}; upd[attrKey] = val; setAttributes(upd); |
| 123 |
}, openColorKey, setOpenColorKey); |
| 124 |
} |
| 125 |
|
| 126 |
function updateLink(id, key, val) { |
| 127 |
setAttributes({ links: a.links.map(function (l) { if (l.id !== id) return l; var u = Object.assign({}, l); u[key] = val; return u; }) }); |
| 128 |
} |
| 129 |
|
| 130 |
var avatarEl = el('div', { className: 'bkbg-lib-avatar-wrap', style: { textAlign: 'center', marginBottom: '20px' } }, |
| 131 |
el(MediaUploadCheck, null, |
| 132 |
el(MediaUpload, { |
| 133 |
onSelect: function (m) { setAttributes({ avatarUrl: m.url, avatarId: m.id }); }, |
| 134 |
allowedTypes: ['image'], value: a.avatarId, |
| 135 |
render: function (p) { |
| 136 |
return el('div', { style: { display: 'inline-block', cursor: 'pointer' }, onClick: p.open }, |
| 137 |
a.avatarUrl |
| 138 |
? el('img', { src: a.avatarUrl, style: { width: a.avatarSize + 'px', height: a.avatarSize + 'px', borderRadius: a.avatarRadius + '%', objectFit: 'cover', border: a.avatarBorderWidth + 'px solid ' + a.avatarBorderColor, display: 'block' } }) |
| 139 |
: el('div', { style: { width: a.avatarSize + 'px', height: a.avatarSize + 'px', borderRadius: a.avatarRadius + '%', background: '#e5e7eb', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '36px', cursor: 'pointer', border: a.avatarBorderWidth + 'px solid ' + a.avatarBorderColor } }, '👤') |
| 140 |
); |
| 141 |
} |
| 142 |
}) |
| 143 |
) |
| 144 |
); |
| 145 |
|
| 146 |
var linksEl = el('div', { className: 'bkbg-lib-links', style: { display: 'flex', flexDirection: 'column', gap: a.buttonGap + 'px', maxWidth: a.buttonMaxWidth + 'px', margin: '0 auto', width: '100%' } }, |
| 147 |
a.links.map(function (link) { |
| 148 |
return el('div', { key: link.id }, el(LinkButton, { link: link, a: a })); |
| 149 |
}) |
| 150 |
); |
| 151 |
|
| 152 |
return el(Fragment, null, |
| 153 |
el(InspectorControls, null, |
| 154 |
el(PanelBody, { title: __('Avatar', 'blockenberg'), initialOpen: true }, |
| 155 |
el(RangeControl, { label: __('Size (px)', 'blockenberg'), value: a.avatarSize, min: 48, max: 180, onChange: function (v) { setAttributes({ avatarSize: v }); } }), |
| 156 |
el(RangeControl, { label: __('Border radius (%)', 'blockenberg'), value: a.avatarRadius, min: 0, max: 50, onChange: function (v) { setAttributes({ avatarRadius: v }); } }), |
| 157 |
el(RangeControl, { label: __('Border width (px)', 'blockenberg'), value: a.avatarBorderWidth, min: 0, max: 8, onChange: function (v) { setAttributes({ avatarBorderWidth: v }); } }), |
| 158 |
renderColorControl('avatarBorderColor', __('Border color', 'blockenberg'), a.avatarBorderColor, function (v) { setAttributes({ avatarBorderColor: v }); }, openColorKey, setOpenColorKey), |
| 159 |
el(MediaUploadCheck, null, |
| 160 |
el(MediaUpload, { |
| 161 |
onSelect: function (m) { setAttributes({ avatarUrl: m.url, avatarId: m.id }); }, |
| 162 |
allowedTypes: ['image'], value: a.avatarId, |
| 163 |
render: function (p) { return el(Button, { onClick: p.open, variant: a.avatarUrl ? 'secondary' : 'primary', size: 'compact' }, a.avatarUrl ? __('Replace avatar', 'blockenberg') : __('Set avatar', 'blockenberg')); } |
| 164 |
}) |
| 165 |
) |
| 166 |
), |
| 167 |
el(PanelBody, { title: __('Profile', 'blockenberg'), initialOpen: false }, |
| 168 |
el(ToggleControl, { label: __('Show title / tagline', 'blockenberg'), checked: a.showTitle, onChange: function (v) { setAttributes({ showTitle: v }); }, __nextHasNoMarginBottom: true }), |
| 169 |
el(ToggleControl, { label: __('Show bio', 'blockenberg'), checked: a.showBio, onChange: function (v) { setAttributes({ showBio: v }); }, __nextHasNoMarginBottom: true }) |
| 170 |
), |
| 171 |
el(PanelBody, { title: __('Links', 'blockenberg'), initialOpen: false }, |
| 172 |
a.links.map(function (link, li) { |
| 173 |
return el(PanelBody, { key: link.id, title: (link.icon ? link.icon + ' ' : '') + (link.label || 'Link ' + (li + 1)), initialOpen: false }, |
| 174 |
IP() && el(IP().IconPickerControl, { |
| 175 |
iconType: link.iconType || 'custom-char', |
| 176 |
customChar: link.icon || '', |
| 177 |
dashicon: link.iconDashicon || '', |
| 178 |
imageUrl: link.iconImageUrl || '', |
| 179 |
onChangeType: function (v) { updateLink(link.id, 'iconType', v); }, |
| 180 |
onChangeChar: function (v) { updateLink(link.id, 'icon', v); }, |
| 181 |
onChangeDashicon: function (v) { updateLink(link.id, 'iconDashicon', v); }, |
| 182 |
onChangeImageUrl: function (v) { updateLink(link.id, 'iconImageUrl', v); } |
| 183 |
}), |
| 184 |
el(TextControl, { label: __('Label', 'blockenberg'), value: link.label, onChange: function (v) { updateLink(link.id, 'label', v); } }), |
| 185 |
el(TextControl, { label: __('URL', 'blockenberg'), value: link.url, onChange: function (v) { updateLink(link.id, 'url', v); } }), |
| 186 |
el(SelectControl, { label: __('Button style', 'blockenberg'), value: link.style || 'filled', options: LINK_STYLE_OPTIONS, onChange: function (v) { updateLink(link.id, 'style', v); } }), |
| 187 |
el(ToggleControl, { label: __('Open in new tab', 'blockenberg'), checked: link.newTab, onChange: function (v) { updateLink(link.id, 'newTab', v); }, __nextHasNoMarginBottom: true }), |
| 188 |
el(Button, { onClick: function () { setAttributes({ links: a.links.filter(function (l) { return l.id !== link.id; }) }); }, isDestructive: true, variant: 'tertiary', size: 'compact', style: { marginTop: '6px' } }, __('Remove link', 'blockenberg')) |
| 189 |
); |
| 190 |
}), |
| 191 |
el(Button, { variant: 'primary', onClick: function () { setAttributes({ links: a.links.concat([{ id: makeId(), icon: '🔗', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '', label: __('My Link', 'blockenberg'), url: '', newTab: false, style: 'filled' }]) }); }, style: { marginTop: '8px' } }, __('+ Add Link', 'blockenberg')) |
| 192 |
), |
| 193 |
el(PanelBody, { title: __('Button Styling', 'blockenberg'), initialOpen: false }, |
| 194 |
el(SelectControl, { label: __('Default button style', 'blockenberg'), value: a.buttonStyle, options: LINK_STYLE_OPTIONS, onChange: function (v) { setAttributes({ buttonStyle: v }); } }), |
| 195 |
el(RangeControl, { label: __('Border radius (px)', 'blockenberg'), value: a.buttonRadius, min: 0, max: 99, onChange: function (v) { setAttributes({ buttonRadius: v }); } }), |
| 196 |
el(RangeControl, { label: __('Gap between buttons', 'blockenberg'), value: a.buttonGap, min: 4, max: 32, onChange: function (v) { setAttributes({ buttonGap: v }); } }), |
| 197 |
el(RangeControl, { label: __('Max width (px)', 'blockenberg'), value: a.buttonMaxWidth, min: 240, max: 700, onChange: function (v) { setAttributes({ buttonMaxWidth: v }); } }), |
| 198 |
el(RangeControl, { label: __('Vertical padding (px)','blockenberg'), value: a.buttonPaddingV, min: 8, max: 28, onChange: function (v) { setAttributes({ buttonPaddingV: v }); } }), |
| 199 |
el(ToggleControl, { label: __('Show icons', 'blockenberg'), checked: a.showIcons, onChange: function (v) { setAttributes({ showIcons: v }); }, __nextHasNoMarginBottom: true }) |
| 200 |
), |
| 201 |
el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false }, |
| 202 |
getTypoControl() && el(getTypoControl(), { label: __('Name'), value: a.nameTypo || {}, onChange: function (v) { setAttributes({ nameTypo: v }); } }), |
| 203 |
getTypoControl() && el(getTypoControl(), { label: __('Tagline'), value: a.taglineTypo || {}, onChange: function (v) { setAttributes({ taglineTypo: v }); } }), |
| 204 |
getTypoControl() && el(getTypoControl(), { label: __('Bio'), value: a.bioTypo || {}, onChange: function (v) { setAttributes({ bioTypo: v }); } }), |
| 205 |
getTypoControl() && el(getTypoControl(), { label: __('Button'), value: a.buttonTypo || {}, onChange: function (v) { setAttributes({ buttonTypo: v }); } }) |
| 206 |
), |
| 207 |
el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false }, |
| 208 |
cc('accentColor', __('Accent', 'blockenberg'), 'accentColor'), |
| 209 |
cc('nameColor', __('Name', 'blockenberg'), 'nameColor'), |
| 210 |
cc('titleColor', __('Title / tagline', 'blockenberg'), 'titleColor'), |
| 211 |
cc('bioColor', __('Bio text', 'blockenberg'), 'bioColor'), |
| 212 |
cc('btnBg', __('Button background','blockenberg'), 'btnBg'), |
| 213 |
cc('btnColor', __('Button text', 'blockenberg'), 'btnColor'), |
| 214 |
cc('btnBorderColor',__('Button border', 'blockenberg'), 'btnBorderColor'), |
| 215 |
cc('bgColor', __('Section background','blockenberg'), 'bgColor') |
| 216 |
), |
| 217 |
el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false }, |
| 218 |
el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }), |
| 219 |
el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } }) |
| 220 |
) |
| 221 |
), |
| 222 |
|
| 223 |
el('div', blockProps, |
| 224 |
el('div', { className: 'bkbg-lib-inner', style: { display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', maxWidth: (a.buttonMaxWidth + 80) + 'px', margin: '0 auto' } }, |
| 225 |
avatarEl, |
| 226 |
el(RichText, { tagName: 'h2', className: 'bkbg-lib-name', value: a.name, onChange: function (v) { setAttributes({ name: v }); }, placeholder: __('Your Name', 'blockenberg'), style: { color: a.nameColor, margin: '0 0 6px', textAlign: 'center' } }), |
| 227 |
a.showTitle && el(RichText, { tagName: 'p', className: 'bkbg-lib-title', value: a.title, onChange: function (v) { setAttributes({ title: v }); }, placeholder: __('Your tagline', 'blockenberg'), style: { color: a.titleColor, margin: '0 0 12px', textAlign: 'center' } }), |
| 228 |
a.showBio && el(RichText, { tagName: 'p', className: 'bkbg-lib-bio', value: a.bio, onChange: function (v) { setAttributes({ bio: v }); }, placeholder: __('A short bio…', 'blockenberg'), style: { color: a.bioColor, margin: '0 0 24px', textAlign: 'center' } }), |
| 229 |
linksEl |
| 230 |
) |
| 231 |
) |
| 232 |
); |
| 233 |
}, |
| 234 |
|
| 235 |
save: function (props) { |
| 236 |
var a = props.attributes; |
| 237 |
return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-lib-wrapper', style: buildWrapStyle(a) }), |
| 238 |
el('div', { className: 'bkbg-lib-inner' }, |
| 239 |
el('div', { className: 'bkbg-lib-avatar-wrap' }, |
| 240 |
a.avatarUrl && el('img', { src: a.avatarUrl, alt: a.name || '', loading: 'lazy', className: 'bkbg-lib-avatar' }) |
| 241 |
), |
| 242 |
el(RichText.Content, { tagName: 'h2', className: 'bkbg-lib-name', value: a.name }), |
| 243 |
a.showTitle && el(RichText.Content, { tagName: 'p', className: 'bkbg-lib-title', value: a.title }), |
| 244 |
a.showBio && el(RichText.Content, { tagName: 'p', className: 'bkbg-lib-bio', value: a.bio }), |
| 245 |
el('div', { className: 'bkbg-lib-links' }, |
| 246 |
a.links.map(function (link) { |
| 247 |
var style = link.style || 'filled'; |
| 248 |
return el('a', { key: link.id, href: link.url || '#', className: 'bkbg-lib-btn bkbg-lib-btn--' + style, target: link.newTab ? '_blank' : undefined, rel: link.newTab ? 'noopener noreferrer' : undefined }, |
| 249 |
a.showIcons && link.icon && el('span', { className: 'bkbg-lib-btn-icon', 'aria-hidden': 'true' }, (link.iconType || 'custom-char') !== 'custom-char' && IP() ? IP().buildSaveIcon(link.iconType, link.icon, link.iconDashicon, link.iconImageUrl, link.iconDashiconColor) : link.icon), |
| 250 |
el('span', { className: 'bkbg-lib-btn-label' }, link.label) |
| 251 |
); |
| 252 |
}) |
| 253 |
) |
| 254 |
) |
| 255 |
); |
| 256 |
} |
| 257 |
}); |
| 258 |
}() ); |
| 259 |
|