| 1 |
( function () { |
| 2 |
var el = wp.element.createElement; |
| 3 |
var Fragment = wp.element.Fragment; |
| 4 |
var registerBlockType = wp.blocks.registerBlockType; |
| 5 |
var __ = wp.i18n.__; |
| 6 |
var InspectorControls = wp.blockEditor.InspectorControls; |
| 7 |
var PanelColorSettings = wp.blockEditor.PanelColorSettings; |
| 8 |
var MediaUpload = wp.blockEditor.MediaUpload; |
| 9 |
var MediaUploadCheck = wp.blockEditor.MediaUploadCheck; |
| 10 |
var useBlockProps = wp.blockEditor.useBlockProps; |
| 11 |
var PanelBody = wp.components.PanelBody; |
| 12 |
var RangeControl = wp.components.RangeControl; |
| 13 |
var SelectControl = wp.components.SelectControl; |
| 14 |
var TextControl = wp.components.TextControl; |
| 15 |
var ToggleControl = wp.components.ToggleControl; |
| 16 |
var Button = wp.components.Button; |
| 17 |
var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); } |
| 18 |
var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); } |
| 19 |
|
| 20 |
function buildWrapStyle(a) { |
| 21 |
var s = { |
| 22 |
paddingTop: a.paddingTop + 'px', |
| 23 |
paddingBottom: a.paddingBottom + 'px' |
| 24 |
}; |
| 25 |
if (a.bgColor) s.background = a.bgColor; |
| 26 |
if (a.borderTop) s.borderTop = '1px solid ' + (a.dividerColor || '#e5e7eb'); |
| 27 |
if (a.borderBottom) s.borderBottom = '1px solid ' + (a.dividerColor || '#e5e7eb'); |
| 28 |
var _tvFn = getTypoCssVars(); |
| 29 |
if (_tvFn) { |
| 30 |
Object.assign(s, _tvFn(a.ratingTypo || {}, '--bkspb-rt-')); |
| 31 |
Object.assign(s, _tvFn(a.taglineTypo || {}, '--bkspb-tg-')); |
| 32 |
} |
| 33 |
return s; |
| 34 |
} |
| 35 |
|
| 36 |
function uid() { return 'id-' + Math.random().toString(36).slice(2, 8); } |
| 37 |
|
| 38 |
// Star rating SVG row |
| 39 |
function StarRating(props) { |
| 40 |
var val = props.value || 0; |
| 41 |
var color = props.color || '#f59e0b'; |
| 42 |
var size = props.size || 16; |
| 43 |
var stars = []; |
| 44 |
for (var i = 1; i <= 5; i++) { |
| 45 |
var fill = i <= Math.floor(val) ? color : (i <= val + 0.5 ? 'url(#bksp-half-' + props.uid + ')' : '#e5e7eb'); |
| 46 |
stars.push(el('svg', { |
| 47 |
key: i, width: size, height: size, viewBox: '0 0 24 24', |
| 48 |
style: { fill: fill, flexShrink: 0 } |
| 49 |
}, el('path', { d: 'M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z' }))); |
| 50 |
} |
| 51 |
return el('div', { style: { display: 'flex', alignItems: 'center', gap: '2px' } }, stars); |
| 52 |
} |
| 53 |
|
| 54 |
// Avatar circle (initials fallback) |
| 55 |
function Avatar(props) { |
| 56 |
var av = props.avatar; |
| 57 |
var size = props.size || 40; |
| 58 |
var border = props.border || '#ffffff'; |
| 59 |
var fallbackBg = props.fallbackBg || '#6c3fb5'; |
| 60 |
|
| 61 |
var style = { |
| 62 |
width: size + 'px', height: size + 'px', borderRadius: '50%', |
| 63 |
border: '2px solid ' + border, |
| 64 |
overflow: 'hidden', flexShrink: 0, |
| 65 |
background: av.imageUrl ? 'transparent' : fallbackBg, |
| 66 |
display: 'flex', alignItems: 'center', justifyContent: 'center', |
| 67 |
color: '#fff', fontSize: Math.round(size * 0.35) + 'px', fontWeight: 700 |
| 68 |
}; |
| 69 |
|
| 70 |
if (av.imageUrl) { |
| 71 |
return el('div', { style: style }, |
| 72 |
el('img', { src: av.imageUrl, alt: av.name || '', style: { width: '100%', height: '100%', objectFit: 'cover' } }) |
| 73 |
); |
| 74 |
} |
| 75 |
return el('div', { style: style }, (av.initials || '?')); |
| 76 |
} |
| 77 |
|
| 78 |
// Logo placeholder |
| 79 |
function LogoItem(props) { |
| 80 |
var logo = props.logo; |
| 81 |
var height = props.height || 28; |
| 82 |
var opacity = (props.opacity || 50) / 100; |
| 83 |
var grayscale = props.grayscale; |
| 84 |
|
| 85 |
var imgStyle = { |
| 86 |
height: height + 'px', width: 'auto', display: 'block', |
| 87 |
opacity: opacity, |
| 88 |
filter: grayscale ? 'grayscale(100%)' : 'none' |
| 89 |
}; |
| 90 |
|
| 91 |
if (logo.imageUrl) { |
| 92 |
return el('img', { src: logo.imageUrl, alt: logo.name || '', style: imgStyle }); |
| 93 |
} |
| 94 |
// Placeholder |
| 95 |
return el('div', { |
| 96 |
style: { |
| 97 |
height: height + 'px', padding: '0 12px', |
| 98 |
background: '#e5e7eb', borderRadius: '6px', |
| 99 |
display: 'flex', alignItems: 'center', justifyContent: 'center', |
| 100 |
fontSize: '12px', color: '#9ca3af', fontWeight: 600, opacity: opacity, |
| 101 |
whiteSpace: 'nowrap' |
| 102 |
} |
| 103 |
}, logo.name || 'Logo'); |
| 104 |
} |
| 105 |
|
| 106 |
// Main preview component |
| 107 |
function ProofBarPreview(props) { |
| 108 |
var a = props.attrs; |
| 109 |
var isCenter = a.layout !== 'left' && a.layout !== 'spread'; |
| 110 |
var isSpread = a.layout === 'spread'; |
| 111 |
|
| 112 |
var wrapStyle = { |
| 113 |
display: 'flex', |
| 114 |
flexDirection: isSpread ? 'row' : 'column', |
| 115 |
alignItems: isSpread ? 'center' : 'center', |
| 116 |
justifyContent: isSpread ? 'space-between' : 'center', |
| 117 |
flexWrap: 'wrap', |
| 118 |
gap: a.gap + 'px', |
| 119 |
textAlign: isCenter ? 'center' : 'left' |
| 120 |
}; |
| 121 |
|
| 122 |
// Avatar bar + rating + tagline (left cluster) |
| 123 |
var socialPart = el('div', { |
| 124 |
style: { |
| 125 |
display: 'flex', |
| 126 |
flexDirection: isSpread ? 'column' : 'row', |
| 127 |
alignItems: 'center', |
| 128 |
gap: '12px', |
| 129 |
flexWrap: 'wrap', |
| 130 |
justifyContent: isCenter ? 'center' : 'flex-start' |
| 131 |
} |
| 132 |
}, |
| 133 |
a.showAvatars && (a.avatars || []).length > 0 && el('div', { |
| 134 |
style: { |
| 135 |
display: 'flex', |
| 136 |
flexDirection: 'row', |
| 137 |
paddingLeft: a.avatarSize / 3 + 'px' |
| 138 |
} |
| 139 |
}, |
| 140 |
(a.avatars || []).map(function (av, i) { |
| 141 |
return el('div', { |
| 142 |
key: av.id, |
| 143 |
style: { marginLeft: i === 0 ? 0 : ('-' + a.avatarOverlap + 'px') } |
| 144 |
}, el(Avatar, { avatar: av, size: a.avatarSize, border: a.avatarBorderColor, fallbackBg: a.avatarFallbackBg })); |
| 145 |
}) |
| 146 |
), |
| 147 |
a.showRating && el('div', { |
| 148 |
style: { |
| 149 |
display: 'flex', |
| 150 |
flexDirection: isSpread ? 'column' : 'column', |
| 151 |
alignItems: isCenter ? 'center' : 'flex-start', |
| 152 |
gap: '2px' |
| 153 |
} |
| 154 |
}, |
| 155 |
el('div', { style: { display: 'flex', alignItems: 'center', gap: '6px' } }, |
| 156 |
el(StarRating, { value: a.ratingValue, color: a.starColor, size: a.ratingNumSize, uid: 'ed' }), |
| 157 |
el('span', { className: 'bksp-rating-val', style: { color: a.textColor } }, a.ratingValue) |
| 158 |
), |
| 159 |
el('span', { className: 'bksp-review-text', style: { color: a.textColor, opacity: 0.7 } }, |
| 160 |
a.reviewCount + ' ' + a.ratingLabel |
| 161 |
) |
| 162 |
) |
| 163 |
); |
| 164 |
|
| 165 |
// Tagline |
| 166 |
var taglinePart = a.showTagline && el('div', { |
| 167 |
className: 'bksp-tagline-text', style: { color: a.textColor, opacity: 0.8 } |
| 168 |
}, a.tagline); |
| 169 |
|
| 170 |
// Divider |
| 171 |
var dividerPart = a.dividerStyle !== 'none' && el('div', { |
| 172 |
style: { |
| 173 |
[isSpread ? 'width' : 'height']: isSpread ? '1px' : 'auto', |
| 174 |
[isSpread ? 'height' : 'width']: isSpread ? '40px' : '1px', |
| 175 |
background: a.dividerColor || '#e5e7eb', |
| 176 |
flexShrink: 0 |
| 177 |
} |
| 178 |
}); |
| 179 |
|
| 180 |
// Logo strip |
| 181 |
var logosPart = a.showLogos && el('div', { |
| 182 |
style: { |
| 183 |
display: 'flex', |
| 184 |
flexDirection: isSpread ? 'column' : 'row', |
| 185 |
alignItems: 'center', |
| 186 |
gap: a.logoGap + 'px', |
| 187 |
flexWrap: 'wrap', |
| 188 |
justifyContent: isCenter ? 'center' : 'flex-start' |
| 189 |
} |
| 190 |
}, |
| 191 |
a.showLogosLabel && el('span', { |
| 192 |
className: 'bksp-logos-text', style: { color: a.textColor, opacity: 0.5, whiteSpace: 'nowrap' } |
| 193 |
}, a.logosLabel), |
| 194 |
(a.logos || []).map(function (logo) { |
| 195 |
return el('div', { key: logo.id }, |
| 196 |
el(LogoItem, { logo: logo, height: a.logoHeight, opacity: a.logoOpacity, grayscale: a.logoGrayscale }) |
| 197 |
); |
| 198 |
}) |
| 199 |
); |
| 200 |
|
| 201 |
if (isSpread) { |
| 202 |
return el('div', { style: wrapStyle }, socialPart, taglinePart, dividerPart, logosPart); |
| 203 |
} |
| 204 |
|
| 205 |
return el('div', { style: wrapStyle }, socialPart, taglinePart, a.showLogos && dividerPart, logosPart); |
| 206 |
} |
| 207 |
|
| 208 |
// Avatar editor item |
| 209 |
function AvatarEditor(props) { |
| 210 |
var av = props.av; |
| 211 |
var idx = props.idx; |
| 212 |
var onUpdate = props.onUpdate; |
| 213 |
var onRemove = props.onRemove; |
| 214 |
|
| 215 |
return el('div', { style: { border: '1px solid #e5e7eb', borderRadius: '6px', padding: '10px', marginBottom: '8px' } }, |
| 216 |
el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' } }, |
| 217 |
el('div', { |
| 218 |
style: { |
| 219 |
width: '32px', height: '32px', borderRadius: '50%', |
| 220 |
background: av.imageUrl ? 'transparent' : '#6c3fb5', |
| 221 |
overflow: 'hidden', flexShrink: 0, |
| 222 |
display: 'flex', alignItems: 'center', justifyContent: 'center', |
| 223 |
fontSize: '11px', color: '#fff', fontWeight: 700 |
| 224 |
} |
| 225 |
}, av.imageUrl ? el('img', { src: av.imageUrl, style: { width: '100%', height: '100%', objectFit: 'cover' } }) : (av.initials || '?')), |
| 226 |
el('span', { style: { fontSize: '13px', fontWeight: 600, flexGrow: 1 } }, av.name || ('Avatar ' + (idx + 1))) |
| 227 |
), |
| 228 |
el(MediaUploadCheck, null, |
| 229 |
el(MediaUpload, { |
| 230 |
onSelect: function (media) { onUpdate(idx, 'imageUrl', media.url); }, |
| 231 |
allowedTypes: ['image'], |
| 232 |
render: function (rp) { |
| 233 |
return el(Button, { variant: 'secondary', isSmall: true, onClick: rp.open }, |
| 234 |
av.imageUrl ? __('Change photo', 'blockenberg') : __('Upload photo', 'blockenberg')); |
| 235 |
} |
| 236 |
}) |
| 237 |
), |
| 238 |
el(TextControl, { label: __('Name', 'blockenberg'), value: av.name, onChange: function (v) { onUpdate(idx, 'name', v); } }), |
| 239 |
el(TextControl, { label: __('Initials (fallback)', 'blockenberg'), value: av.initials, onChange: function (v) { onUpdate(idx, 'initials', v); } }), |
| 240 |
el(Button, { |
| 241 |
variant: 'secondary', isDestructive: true, isSmall: true, |
| 242 |
onClick: function () { onRemove(idx); } |
| 243 |
}, __('Remove', 'blockenberg')) |
| 244 |
); |
| 245 |
} |
| 246 |
|
| 247 |
registerBlockType('blockenberg/social-proof-bar', { |
| 248 |
|
| 249 |
edit: function (props) { |
| 250 |
var attrs = props.attributes; |
| 251 |
var setAttr = props.setAttributes; |
| 252 |
var avatars = attrs.avatars || []; |
| 253 |
var logos = attrs.logos || []; |
| 254 |
|
| 255 |
function updateAvatar(i, key, val) { |
| 256 |
var next = avatars.map(function (av, j) { |
| 257 |
if (j !== i) return av; |
| 258 |
var u = Object.assign({}, av); u[key] = val; return u; |
| 259 |
}); |
| 260 |
setAttr({ avatars: next }); |
| 261 |
} |
| 262 |
|
| 263 |
function removeAvatar(i) { setAttr({ avatars: avatars.filter(function (_, j) { return j !== i; }) }); } |
| 264 |
|
| 265 |
function addAvatar() { |
| 266 |
setAttr({ avatars: avatars.concat([{ id: uid(), imageUrl: '', name: '', initials: '' }]) }); |
| 267 |
} |
| 268 |
|
| 269 |
function updateLogo(i, key, val) { |
| 270 |
var next = logos.map(function (l, j) { |
| 271 |
if (j !== i) return l; |
| 272 |
var u = Object.assign({}, l); u[key] = val; return u; |
| 273 |
}); |
| 274 |
setAttr({ logos: next }); |
| 275 |
} |
| 276 |
|
| 277 |
function removeLogo(i) { setAttr({ logos: logos.filter(function (_, j) { return j !== i; }) }); } |
| 278 |
|
| 279 |
function addLogo() { |
| 280 |
setAttr({ logos: logos.concat([{ id: uid(), imageUrl: '', name: 'Partner', url: '' }]) }); |
| 281 |
} |
| 282 |
|
| 283 |
var wrapStyle = buildWrapStyle(attrs); |
| 284 |
|
| 285 |
var blockProps = useBlockProps({ className: 'bksp-wrap', style: wrapStyle }); |
| 286 |
|
| 287 |
return el(Fragment, null, |
| 288 |
el(InspectorControls, null, |
| 289 |
|
| 290 |
el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: true }, |
| 291 |
el(SelectControl, { |
| 292 |
label: __('Layout', 'blockenberg'), |
| 293 |
value: attrs.layout, |
| 294 |
options: [ |
| 295 |
{ label: 'Centered (stacked)', value: 'centered' }, |
| 296 |
{ label: 'Left aligned', value: 'left' }, |
| 297 |
{ label: 'Spread (side by side)', value: 'spread' } |
| 298 |
], |
| 299 |
onChange: function (v) { setAttr({ layout: v }); } |
| 300 |
}), |
| 301 |
el(RangeControl, { |
| 302 |
label: __('Gap (px)', 'blockenberg'), |
| 303 |
value: attrs.gap, min: 8, max: 80, |
| 304 |
onChange: function (v) { setAttr({ gap: v }); } |
| 305 |
}), |
| 306 |
el(SelectControl, { |
| 307 |
label: __('Divider style', 'blockenberg'), |
| 308 |
value: attrs.dividerStyle, |
| 309 |
options: [ |
| 310 |
{ label: 'Line', value: 'line' }, |
| 311 |
{ label: 'Dot', value: 'dot' }, |
| 312 |
{ label: 'None', value: 'none' } |
| 313 |
], |
| 314 |
onChange: function (v) { setAttr({ dividerStyle: v }); } |
| 315 |
}), |
| 316 |
el(ToggleControl, { |
| 317 |
label: __('Border top', 'blockenberg'), |
| 318 |
checked: attrs.borderTop, |
| 319 |
onChange: function (v) { setAttr({ borderTop: v }); }, |
| 320 |
__nextHasNoMarginBottom: true |
| 321 |
}), |
| 322 |
el(ToggleControl, { |
| 323 |
label: __('Border bottom', 'blockenberg'), |
| 324 |
checked: attrs.borderBottom, |
| 325 |
onChange: function (v) { setAttr({ borderBottom: v }); }, |
| 326 |
__nextHasNoMarginBottom: true |
| 327 |
}), |
| 328 |
el(RangeControl, { |
| 329 |
label: __('Padding Top (px)', 'blockenberg'), |
| 330 |
value: attrs.paddingTop, min: 0, max: 200, |
| 331 |
onChange: function (v) { setAttr({ paddingTop: v }); } |
| 332 |
}), |
| 333 |
el(RangeControl, { |
| 334 |
label: __('Padding Bottom (px)', 'blockenberg'), |
| 335 |
value: attrs.paddingBottom, min: 0, max: 200, |
| 336 |
onChange: function (v) { setAttr({ paddingBottom: v }); } |
| 337 |
}) |
| 338 |
), |
| 339 |
|
| 340 |
el(PanelBody, { title: __('Avatars', 'blockenberg'), initialOpen: false }, |
| 341 |
el(ToggleControl, { |
| 342 |
label: __('Show avatars', 'blockenberg'), |
| 343 |
checked: attrs.showAvatars, |
| 344 |
onChange: function (v) { setAttr({ showAvatars: v }); }, |
| 345 |
__nextHasNoMarginBottom: true |
| 346 |
}), |
| 347 |
attrs.showAvatars && el(Fragment, null, |
| 348 |
el(RangeControl, { |
| 349 |
label: __('Avatar size (px)', 'blockenberg'), |
| 350 |
value: attrs.avatarSize, min: 24, max: 80, |
| 351 |
onChange: function (v) { setAttr({ avatarSize: v }); } |
| 352 |
}), |
| 353 |
el(RangeControl, { |
| 354 |
label: __('Overlap (px)', 'blockenberg'), |
| 355 |
value: attrs.avatarOverlap, min: 0, max: 30, |
| 356 |
onChange: function (v) { setAttr({ avatarOverlap: v }); } |
| 357 |
}), |
| 358 |
avatars.map(function (av, i) { |
| 359 |
return el(AvatarEditor, { key: av.id, av: av, idx: i, onUpdate: updateAvatar, onRemove: removeAvatar }); |
| 360 |
}), |
| 361 |
el(Button, { |
| 362 |
variant: 'secondary', isSmall: true, |
| 363 |
style: { width: '100%', justifyContent: 'center', marginTop: '6px' }, |
| 364 |
onClick: addAvatar |
| 365 |
}, __('+ Add avatar', 'blockenberg')) |
| 366 |
) |
| 367 |
), |
| 368 |
|
| 369 |
el(PanelBody, { title: __('Rating', 'blockenberg'), initialOpen: false }, |
| 370 |
el(ToggleControl, { |
| 371 |
label: __('Show rating', 'blockenberg'), |
| 372 |
checked: attrs.showRating, |
| 373 |
onChange: function (v) { setAttr({ showRating: v }); }, |
| 374 |
__nextHasNoMarginBottom: true |
| 375 |
}), |
| 376 |
attrs.showRating && el(Fragment, null, |
| 377 |
el(RangeControl, { |
| 378 |
label: __('Rating value', 'blockenberg'), |
| 379 |
value: attrs.ratingValue, min: 1, max: 5, step: 0.1, |
| 380 |
onChange: function (v) { setAttr({ ratingValue: v }); } |
| 381 |
}), |
| 382 |
el(TextControl, { |
| 383 |
label: __('Review count', 'blockenberg'), |
| 384 |
value: attrs.reviewCount, |
| 385 |
onChange: function (v) { setAttr({ reviewCount: v }); } |
| 386 |
}), |
| 387 |
el(TextControl, { |
| 388 |
label: __('Rating label', 'blockenberg'), |
| 389 |
value: attrs.ratingLabel, |
| 390 |
onChange: function (v) { setAttr({ ratingLabel: v }); } |
| 391 |
}) |
| 392 |
) |
| 393 |
), |
| 394 |
|
| 395 |
el(PanelBody, { title: __('Tagline', 'blockenberg'), initialOpen: false }, |
| 396 |
el(ToggleControl, { |
| 397 |
label: __('Show tagline', 'blockenberg'), |
| 398 |
checked: attrs.showTagline, |
| 399 |
onChange: function (v) { setAttr({ showTagline: v }); }, |
| 400 |
__nextHasNoMarginBottom: true |
| 401 |
}), |
| 402 |
attrs.showTagline && el(TextControl, { |
| 403 |
label: __('Tagline text', 'blockenberg'), |
| 404 |
value: attrs.tagline, |
| 405 |
onChange: function (v) { setAttr({ tagline: v }); } |
| 406 |
}) |
| 407 |
), |
| 408 |
|
| 409 |
el(PanelBody, { title: __('Logos', 'blockenberg'), initialOpen: false }, |
| 410 |
el(ToggleControl, { |
| 411 |
label: __('Show logos', 'blockenberg'), |
| 412 |
checked: attrs.showLogos, |
| 413 |
onChange: function (v) { setAttr({ showLogos: v }); }, |
| 414 |
__nextHasNoMarginBottom: true |
| 415 |
}), |
| 416 |
attrs.showLogos && el(Fragment, null, |
| 417 |
el(ToggleControl, { |
| 418 |
label: __('Show "As seen in" label', 'blockenberg'), |
| 419 |
checked: attrs.showLogosLabel, |
| 420 |
onChange: function (v) { setAttr({ showLogosLabel: v }); }, |
| 421 |
__nextHasNoMarginBottom: true |
| 422 |
}), |
| 423 |
attrs.showLogosLabel && el(TextControl, { |
| 424 |
label: __('Label text', 'blockenberg'), |
| 425 |
value: attrs.logosLabel, |
| 426 |
onChange: function (v) { setAttr({ logosLabel: v }); } |
| 427 |
}), |
| 428 |
el(RangeControl, { |
| 429 |
label: __('Logo height (px)', 'blockenberg'), |
| 430 |
value: attrs.logoHeight, min: 16, max: 80, |
| 431 |
onChange: function (v) { setAttr({ logoHeight: v }); } |
| 432 |
}), |
| 433 |
el(RangeControl, { |
| 434 |
label: __('Logo opacity (%)', 'blockenberg'), |
| 435 |
value: attrs.logoOpacity, min: 10, max: 100, |
| 436 |
onChange: function (v) { setAttr({ logoOpacity: v }); } |
| 437 |
}), |
| 438 |
el(ToggleControl, { |
| 439 |
label: __('Grayscale logos', 'blockenberg'), |
| 440 |
checked: attrs.logoGrayscale, |
| 441 |
onChange: function (v) { setAttr({ logoGrayscale: v }); }, |
| 442 |
__nextHasNoMarginBottom: true |
| 443 |
}), |
| 444 |
el(RangeControl, { |
| 445 |
label: __('Logo gap (px)', 'blockenberg'), |
| 446 |
value: attrs.logoGap, min: 8, max: 80, |
| 447 |
onChange: function (v) { setAttr({ logoGap: v }); } |
| 448 |
}), |
| 449 |
logos.map(function (logo, i) { |
| 450 |
return el('div', { |
| 451 |
key: logo.id, |
| 452 |
style: { border: '1px solid #e5e7eb', borderRadius: '6px', padding: '10px', marginBottom: '8px' } |
| 453 |
}, |
| 454 |
el(TextControl, { label: __('Name', 'blockenberg'), value: logo.name, onChange: function (v) { updateLogo(i, 'name', v); } }), |
| 455 |
el(MediaUploadCheck, null, |
| 456 |
el(MediaUpload, { |
| 457 |
onSelect: function (media) { updateLogo(i, 'imageUrl', media.url); }, |
| 458 |
allowedTypes: ['image'], |
| 459 |
render: function (rp) { |
| 460 |
return el(Button, { variant: 'secondary', isSmall: true, onClick: rp.open }, |
| 461 |
logo.imageUrl ? __('Change logo', 'blockenberg') : __('Upload logo', 'blockenberg')); |
| 462 |
} |
| 463 |
}) |
| 464 |
), |
| 465 |
el(TextControl, { label: __('Link URL', 'blockenberg'), value: logo.url, type: 'url', onChange: function (v) { updateLogo(i, 'url', v); } }), |
| 466 |
el(Button, { |
| 467 |
variant: 'secondary', isDestructive: true, isSmall: true, style: { marginTop: '6px' }, |
| 468 |
onClick: function () { removeLogo(i); } |
| 469 |
}, __('Remove', 'blockenberg')) |
| 470 |
); |
| 471 |
}), |
| 472 |
el(Button, { |
| 473 |
variant: 'secondary', isSmall: true, |
| 474 |
style: { width: '100%', justifyContent: 'center', marginTop: '6px' }, |
| 475 |
onClick: addLogo |
| 476 |
}, __('+ Add logo', 'blockenberg')) |
| 477 |
) |
| 478 |
), |
| 479 |
|
| 480 |
el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false }, |
| 481 |
getTypoControl() && el(getTypoControl(), { |
| 482 |
label: __('Rating Number', 'blockenberg'), |
| 483 |
value: attrs.ratingTypo || {}, |
| 484 |
onChange: function (v) { setAttr({ ratingTypo: v }); } |
| 485 |
}), |
| 486 |
getTypoControl() && el(getTypoControl(), { |
| 487 |
label: __('Tagline / Labels', 'blockenberg'), |
| 488 |
value: attrs.taglineTypo || {}, |
| 489 |
onChange: function (v) { setAttr({ taglineTypo: v }); } |
| 490 |
}) |
| 491 |
), |
| 492 |
|
| 493 |
el(PanelColorSettings, { |
| 494 |
title: __('Colors', 'blockenberg'), |
| 495 |
initialOpen: false, |
| 496 |
colorSettings: [ |
| 497 |
{ label: __('Text Color', 'blockenberg'), value: attrs.textColor, onChange: function (v) { setAttr({ textColor: v || '#374151' }); } }, |
| 498 |
{ label: __('Star Color', 'blockenberg'), value: attrs.starColor, onChange: function (v) { setAttr({ starColor: v || '#f59e0b' }); } }, |
| 499 |
{ label: __('Avatar Border', 'blockenberg'), value: attrs.avatarBorderColor, onChange: function (v) { setAttr({ avatarBorderColor: v || '#ffffff' }); } }, |
| 500 |
{ label: __('Avatar Fallback BG', 'blockenberg'), value: attrs.avatarFallbackBg, onChange: function (v) { setAttr({ avatarFallbackBg: v || '#6c3fb5' }); } }, |
| 501 |
{ label: __('Divider / Border', 'blockenberg'), value: attrs.dividerColor, onChange: function (v) { setAttr({ dividerColor: v || '#e5e7eb' }); } }, |
| 502 |
{ label: __('Background', 'blockenberg'), value: attrs.bgColor, onChange: function (v) { setAttr({ bgColor: v || '' }); } } |
| 503 |
] |
| 504 |
}) |
| 505 |
), |
| 506 |
|
| 507 |
el('div', blockProps, |
| 508 |
el(ProofBarPreview, { attrs: attrs }) |
| 509 |
) |
| 510 |
); |
| 511 |
}, |
| 512 |
|
| 513 |
save: function (props) { |
| 514 |
var a = props.attributes; |
| 515 |
var hasTypo = a.ratingTypo !== undefined; |
| 516 |
|
| 517 |
var wrapStyle = buildWrapStyle(a); |
| 518 |
|
| 519 |
var isSpread = a.layout === 'spread'; |
| 520 |
var isCenter = a.layout !== 'left' && a.layout !== 'spread'; |
| 521 |
|
| 522 |
var blockProps = wp.blockEditor.useBlockProps.save({ |
| 523 |
className: 'bksp-wrap bksp-layout--' + a.layout, |
| 524 |
style: wrapStyle |
| 525 |
}); |
| 526 |
|
| 527 |
// Stars |
| 528 |
var starNodes = []; |
| 529 |
for (var si = 1; si <= 5; si++) { |
| 530 |
var filled = si <= a.ratingValue; |
| 531 |
starNodes.push(el('svg', { |
| 532 |
key: si, width: a.ratingNumSize, height: a.ratingNumSize, viewBox: '0 0 24 24', |
| 533 |
style: { fill: filled ? (a.starColor || '#f59e0b') : '#e5e7eb', flexShrink: 0 } |
| 534 |
}, el('path', { d: 'M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z' }))); |
| 535 |
} |
| 536 |
|
| 537 |
var avatarNodes = (a.avatars || []).map(function (av, i) { |
| 538 |
var avStyle = { |
| 539 |
width: a.avatarSize + 'px', height: a.avatarSize + 'px', borderRadius: '50%', |
| 540 |
border: '2px solid ' + (a.avatarBorderColor || '#ffffff'), |
| 541 |
overflow: 'hidden', flexShrink: 0, |
| 542 |
background: av.imageUrl ? 'transparent' : (a.avatarFallbackBg || '#6c3fb5'), |
| 543 |
display: 'inline-flex', alignItems: 'center', justifyContent: 'center', |
| 544 |
color: '#fff', fontSize: Math.round(a.avatarSize * 0.35) + 'px', fontWeight: 700, |
| 545 |
marginLeft: i === 0 ? 0 : ('-' + a.avatarOverlap + 'px'), |
| 546 |
position: 'relative', zIndex: 10 - i |
| 547 |
}; |
| 548 |
return el('div', { key: av.id, className: 'bksp-avatar', style: avStyle }, |
| 549 |
av.imageUrl |
| 550 |
? el('img', { src: av.imageUrl, alt: av.name || '', style: { width: '100%', height: '100%', objectFit: 'cover' } }) |
| 551 |
: el('span', null, av.initials || '?') |
| 552 |
); |
| 553 |
}); |
| 554 |
|
| 555 |
var logoNodes = (a.logos || []).map(function (logo) { |
| 556 |
var imgStyle = { |
| 557 |
height: a.logoHeight + 'px', width: 'auto', |
| 558 |
opacity: (a.logoOpacity || 50) / 100, |
| 559 |
filter: a.logoGrayscale ? 'grayscale(100%)' : 'none', |
| 560 |
display: 'block' |
| 561 |
}; |
| 562 |
var content = logo.imageUrl |
| 563 |
? el('img', { src: logo.imageUrl, alt: logo.name || '', style: imgStyle }) |
| 564 |
: el('div', { style: Object.assign({}, imgStyle, { padding: '0 12px', background: '#e5e7eb', borderRadius: '6px', display: 'flex', alignItems: 'center', fontSize: '12px', color: '#9ca3af', fontWeight: 600, whiteSpace: 'nowrap' }) }, logo.name); |
| 565 |
return logo.url |
| 566 |
? el('a', { key: logo.id, href: logo.url, rel: 'noopener noreferrer', target: '_blank', className: 'bksp-logo' }, content) |
| 567 |
: el('div', { key: logo.id, className: 'bksp-logo' }, content); |
| 568 |
}); |
| 569 |
|
| 570 |
var innerFlex = { display: 'flex', flexWrap: 'wrap', gap: a.gap + 'px', alignItems: 'center', justifyContent: isCenter ? 'center' : (isSpread ? 'space-between' : 'flex-start') }; |
| 571 |
|
| 572 |
return el('div', blockProps, |
| 573 |
el('div', { className: 'bksp-inner', style: innerFlex }, |
| 574 |
|
| 575 |
// Social cluster (avatars + rating) |
| 576 |
el('div', { className: 'bksp-social', style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '12px', justifyContent: isCenter ? 'center' : 'flex-start' } }, |
| 577 |
a.showAvatars && avatarNodes.length > 0 && el('div', { className: 'bksp-avatars', style: { display: 'flex', alignItems: 'center' } }, avatarNodes), |
| 578 |
a.showRating && el('div', { className: 'bksp-rating' }, |
| 579 |
el('div', { style: { display: 'flex', alignItems: 'center', gap: '4px' } }, |
| 580 |
el('div', { style: { display: 'flex', gap: '2px' } }, starNodes), |
| 581 |
hasTypo |
| 582 |
? el('span', { className: 'bksp-rating-val', style: { color: a.textColor } }, a.ratingValue) |
| 583 |
: el('span', { style: { fontSize: a.ratingNumSize + 'px', fontWeight: 700, color: a.textColor } }, a.ratingValue) |
| 584 |
), |
| 585 |
hasTypo |
| 586 |
? el('div', { className: 'bksp-review-text', style: { color: a.textColor, opacity: 0.7 } }, a.reviewCount + ' ' + a.ratingLabel) |
| 587 |
: el('div', { style: { fontSize: a.taglineSize + 'px', color: a.textColor, opacity: 0.7 } }, a.reviewCount + ' ' + a.ratingLabel) |
| 588 |
) |
| 589 |
), |
| 590 |
|
| 591 |
a.showTagline && (hasTypo |
| 592 |
? el('p', { className: 'bksp-tagline', style: { color: a.textColor, margin: 0 } }, a.tagline) |
| 593 |
: el('p', { className: 'bksp-tagline', style: { fontSize: a.taglineSize + 'px', color: a.textColor, margin: 0, fontStyle: 'italic' } }, a.tagline) |
| 594 |
), |
| 595 |
|
| 596 |
a.showLogos && a.dividerStyle !== 'none' && el('div', { className: 'bksp-divider', 'aria-hidden': 'true' }), |
| 597 |
|
| 598 |
a.showLogos && el('div', { className: 'bksp-logos', style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: a.logoGap + 'px', justifyContent: isCenter ? 'center' : 'flex-start' } }, |
| 599 |
a.showLogosLabel && (hasTypo |
| 600 |
? el('span', { className: 'bksp-logos-text', style: { color: a.textColor, opacity: 0.5 } }, a.logosLabel) |
| 601 |
: el('span', { style: { fontSize: a.taglineSize + 'px', color: a.textColor, opacity: 0.5, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.08em' } }, a.logosLabel) |
| 602 |
), |
| 603 |
logoNodes |
| 604 |
) |
| 605 |
) |
| 606 |
); |
| 607 |
}, |
| 608 |
|
| 609 |
deprecated: [{ |
| 610 |
attributes: {"layout":{"type":"string","default":"centered"},"showAvatars":{"type":"boolean","default":true},"avatars":{"type":"array","default":[{"id":"a1","imageUrl":"","name":"User 1","initials":"JD"},{"id":"a2","imageUrl":"","name":"User 2","initials":"AM"},{"id":"a3","imageUrl":"","name":"User 3","initials":"SK"},{"id":"a4","imageUrl":"","name":"User 4","initials":"RL"}]},"avatarSize":{"type":"number","default":40},"avatarOverlap":{"type":"number","default":10},"avatarBorderColor":{"type":"string","default":"#ffffff"},"avatarFallbackBg":{"type":"string","default":"#6c3fb5"},"showRating":{"type":"boolean","default":true},"ratingValue":{"type":"number","default":4.9},"reviewCount":{"type":"string","default":"2,400+"},"ratingLabel":{"type":"string","default":"reviews"},"starColor":{"type":"string","default":"#f59e0b"},"showTagline":{"type":"boolean","default":true},"tagline":{"type":"string","default":"Trusted by 10,000+ marketers worldwide"},"dividerStyle":{"type":"string","default":"line"},"showLogos":{"type":"boolean","default":true},"logosLabel":{"type":"string","default":"As seen in"},"showLogosLabel":{"type":"boolean","default":true},"logos":{"type":"array","default":[{"id":"l1","imageUrl":"","name":"Forbes","url":""},{"id":"l2","imageUrl":"","name":"TechCrunch","url":""},{"id":"l3","imageUrl":"","name":"Wired","url":""},{"id":"l4","imageUrl":"","name":"Product Hunt","url":""}]},"logoHeight":{"type":"number","default":28},"logoOpacity":{"type":"number","default":50},"logoGrayscale":{"type":"boolean","default":true},"logoGap":{"type":"number","default":40},"gap":{"type":"number","default":32},"borderRadius":{"type":"number","default":0},"borderTop":{"type":"boolean","default":false},"borderBottom":{"type":"boolean","default":false},"taglineSize":{"type":"number","default":14},"ratingNumSize":{"type":"number","default":16},"bgColor":{"type":"string","default":""},"textColor":{"type":"string","default":"#374151"},"dividerColor":{"type":"string","default":"#e5e7eb"},"paddingTop":{"type":"number","default":32},"paddingBottom":{"type":"number","default":32},"ratingNumFontWeight":{"type":"number","default":700},"taglineFontWeight":{"type":"number","default":600}}, |
| 611 |
save: function (props) { |
| 612 |
/* delegates to current save — hasTypo will be false for old attrs */ |
| 613 |
return wp.blocks.getBlockType('blockenberg/social-proof-bar').save(props); |
| 614 |
} |
| 615 |
}] |
| 616 |
}); |
| 617 |
}() ); |
| 618 |
|