PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.14
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.14
2.0.14 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 / social-proof-section / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.14, at blocks/social-proof-section/index.js

233 lines 18.3 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 __ = wp.i18n.__;
4 var registerBlockType = wp.blocks.registerBlockType;
5 var InspectorControls = wp.blockEditor.InspectorControls;
6 var MediaUpload = wp.blockEditor.MediaUpload;
7 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
8 var useBlockProps = wp.blockEditor.useBlockProps;
9 var RichText = wp.blockEditor.RichText;
10 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
11 var PanelBody = wp.components.PanelBody;
12 var ToggleControl = wp.components.ToggleControl;
13 var RangeControl = wp.components.RangeControl;
14 var SelectControl = wp.components.SelectControl;
15 var TextControl = wp.components.TextControl;
16 var Button = wp.components.Button;
17
18 var _tc, _tv;
19 function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
20 function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
21
22 registerBlockType('blockenberg/social-proof-section', {
23 edit: function (props) {
24 var attr = props.attributes;
25 var setAttr = props.setAttributes;
26 var logos = attr.logos || [];
27 var stats = attr.stats || [];
28
29 var blockProps = useBlockProps((function () {
30 var _tv = getTypoCssVars();
31 var s = {
32 background: attr.bgColor || '#f9fafb',
33 paddingTop: attr.paddingTop + 'px',
34 paddingBottom: attr.paddingBottom + 'px'
35 };
36 if (_tv) {
37 Object.assign(s, _tv(attr.eyebrowTypo, '--bksps-ey-'));
38 Object.assign(s, _tv(attr.headingTypo, '--bksps-hd-'));
39 Object.assign(s, _tv(attr.statValueTypo, '--bksps-sv-'));
40 Object.assign(s, _tv(attr.statLabelTypo, '--bksps-sl-'));
41 Object.assign(s, _tv(attr.quoteTypo, '--bksps-qt-'));
42 }
43 return { className: 'bkbg-sps-editor', style: s };
44 })());
45
46 function updateStat(index, key, value) {
47 setAttr({ stats: stats.map(function (stat, i) {
48 if (i !== index) return stat;
49 var updated = Object.assign({}, stat);
50 updated[key] = value;
51 return updated;
52 }) });
53 }
54
55 var controls = el(InspectorControls, {},
56 el(PanelBody, { title: __('Section Header', 'blockenberg'), initialOpen: true },
57 el(ToggleControl, { label: __('Show Eyebrow', 'blockenberg'), checked: attr.showEyebrow, onChange: function (v) { setAttr({ showEyebrow: v }); }, __nextHasNoMarginBottom: true }),
58 el(TextControl, { label: __('Eyebrow Text', 'blockenberg'), value: attr.eyebrow, onChange: function (v) { setAttr({ eyebrow: v }); }, __nextHasNoMarginBottom: true }),
59 el(ToggleControl, { label: __('Show Heading', 'blockenberg'), checked: attr.showHeading, onChange: function (v) { setAttr({ showHeading: v }); }, __nextHasNoMarginBottom: true }),
60 el(ToggleControl, { label: __('Show Subtext', 'blockenberg'), checked: attr.showSubtext, onChange: function (v) { setAttr({ showSubtext: v }); }, __nextHasNoMarginBottom: true })
61 ),
62 el(PanelBody, { title: __('Client Logos', 'blockenberg'), initialOpen: false },
63 el(ToggleControl, { label: __('Show Logos', 'blockenberg'), checked: attr.showLogos, onChange: function (v) { setAttr({ showLogos: v }); }, __nextHasNoMarginBottom: true }),
64 el(SelectControl, {
65 label: __('Logo Filter', 'blockenberg'), value: attr.logoFilter,
66 options: [
67 { label: 'None (full color)', value: 'none' },
68 { label: 'Grayscale always', value: 'grayscale' },
69 { label: 'Grayscale → color on hover', value: 'grayscale-hover' }
70 ],
71 onChange: function (v) { setAttr({ logoFilter: v }); }, __nextHasNoMarginBottom: true
72 }),
73 el(RangeControl, { label: __('Logo Height (px)', 'blockenberg'), value: attr.logoHeight, min: 20, max: 80, onChange: function (v) { setAttr({ logoHeight: v }); }, __nextHasNoMarginBottom: true }),
74 logos.map(function (logo, i) {
75 return el('div', { key: i, style: { display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' } },
76 logo.imageUrl ? el('img', { src: logo.imageUrl, style: { height: '28px', objectFit: 'contain' } }) : null,
77 el(Button, { isSmall: true, isDestructive: true, onClick: function () { setAttr({ logos: logos.filter(function (_, idx) { return idx !== i; }) }); } }, '✕')
78 );
79 }),
80 el(MediaUploadCheck, {},
81 el(MediaUpload, {
82 onSelect: function (m) { setAttr({ logos: logos.concat({ imageUrl: m.url, imageId: m.id, imageAlt: m.alt || '' }) }); },
83 allowedTypes: ['image'], multiple: false,
84 render: function (ref) { return el(Button, { isSecondary: true, isSmall: true, onClick: ref.open }, '+ Add Logo'); }
85 })
86 )
87 ),
88 el(PanelBody, { title: __('Stats', 'blockenberg'), initialOpen: false },
89 el(ToggleControl, { label: __('Show Stats', 'blockenberg'), checked: attr.showStats, onChange: function (v) { setAttr({ showStats: v }); }, __nextHasNoMarginBottom: true }),
90 el(ToggleControl, { label: __('Show Stat Dividers', 'blockenberg'), checked: attr.statDivider, onChange: function (v) { setAttr({ statDivider: v }); }, __nextHasNoMarginBottom: true }),
91 stats.map(function (stat, i) {
92 return el('div', { key: i, style: { borderLeft: '3px solid #7c3aed', paddingLeft: '10px', marginBottom: '12px' } },
93 el(TextControl, { label: __('Value', 'blockenberg'), value: stat.value, onChange: function (v) { updateStat(i, 'value', v); }, __nextHasNoMarginBottom: true }),
94 el(TextControl, { label: __('Label', 'blockenberg'), value: stat.label, onChange: function (v) { updateStat(i, 'label', v); }, __nextHasNoMarginBottom: true }),
95 el(Button, { isSmall: true, isDestructive: true, onClick: function () { setAttr({ stats: stats.filter(function (_, idx) { return idx !== i; }) }); } }, '✕ Remove')
96 );
97 }),
98 el(Button, { isSecondary: true, isSmall: true, onClick: function () { setAttr({ stats: stats.concat({ value: '100+', label: 'New stat' }) }); }, style: { marginTop: '8px' } }, '+ Add Stat')
99 ),
100 el(PanelBody, { title: __('Featured Quote', 'blockenberg'), initialOpen: false },
101 el(ToggleControl, { label: __('Show Quote', 'blockenberg'), checked: attr.showQuote, onChange: function (v) { setAttr({ showQuote: v }); }, __nextHasNoMarginBottom: true }),
102 el(TextControl, { label: __('Author Name', 'blockenberg'), value: attr.quoteAuthor, onChange: function (v) { setAttr({ quoteAuthor: v }); }, __nextHasNoMarginBottom: true }),
103 el(TextControl, { label: __('Author Role & Company', 'blockenberg'), value: attr.quoteRole, onChange: function (v) { setAttr({ quoteRole: v }); }, __nextHasNoMarginBottom: true }),
104 el('p', { style: { margin: '8px 0 4px', fontSize: '11px', textTransform: 'uppercase', fontWeight: 600, color: '#9ca3af' } }, __('Author Photo', 'blockenberg')),
105 el(MediaUploadCheck, {},
106 el(MediaUpload, {
107 onSelect: function (m) { setAttr({ quoteAvatarUrl: m.url, quoteAvatarId: m.id }); },
108 allowedTypes: ['image'], value: attr.quoteAvatarId,
109 render: function (ref) {
110 return attr.quoteAvatarUrl
111 ? el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
112 el('img', { src: attr.quoteAvatarUrl, style: { width: '40px', height: '40px', borderRadius: '50%', objectFit: 'cover' } }),
113 el(Button, { isSmall: true, isDestructive: true, onClick: function () { setAttr({ quoteAvatarUrl: '', quoteAvatarId: 0 }); } }, '✕')
114 )
115 : el(Button, { isSecondary: true, isSmall: true, onClick: ref.open }, __('Upload Photo', 'blockenberg'));
116 }
117 })
118 )
119 ),
120
121 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
122 getTypoControl() && el( getTypoControl(), { label: __('Eyebrow Typography'), value: attr.eyebrowTypo || {}, onChange: function(v){ setAttr({ eyebrowTypo: v }); } }),
123 getTypoControl() && el( getTypoControl(), { label: __('Heading Typography'), value: attr.headingTypo || {}, onChange: function(v){ setAttr({ headingTypo: v }); } }),
124 getTypoControl() && el( getTypoControl(), { label: __('Stat Value Typography'), value: attr.statValueTypo || {}, onChange: function(v){ setAttr({ statValueTypo: v }); } }),
125 getTypoControl() && el( getTypoControl(), { label: __('Stat Label Typography'), value: attr.statLabelTypo || {}, onChange: function(v){ setAttr({ statLabelTypo: v }); } }),
126 getTypoControl() && el( getTypoControl(), { label: __('Quote Typography'), value: attr.quoteTypo || {}, onChange: function(v){ setAttr({ quoteTypo: v }); } })
127 ),
128 el(PanelColorSettings, {
129 title: __('Colors', 'blockenberg'), initialOpen: false,
130 colorSettings: [
131 { label: __('Background', 'blockenberg'), value: attr.bgColor, onChange: function (v) { setAttr({ bgColor: v || '#f9fafb' }); } },
132 { label: __('Eyebrow', 'blockenberg'), value: attr.eyebrowColor, onChange: function (v) { setAttr({ eyebrowColor: v || '#7c3aed' }); } },
133 { label: __('Heading', 'blockenberg'), value: attr.headingColor, onChange: function (v) { setAttr({ headingColor: v || '#111827' }); } },
134 { label: __('Stat Value', 'blockenberg'), value: attr.statValueColor, onChange: function (v) { setAttr({ statValueColor: v || '#111827' }); } },
135 { label: __('Stat Label', 'blockenberg'), value: attr.statLabelColor, onChange: function (v) { setAttr({ statLabelColor: v || '#6b7280' }); } },
136 { label: __('Quote Text', 'blockenberg'), value: attr.quoteColor, onChange: function (v) { setAttr({ quoteColor: v || '#1f2937' }); } },
137 { label: __('Quote Card BG', 'blockenberg'), value: attr.quoteBg, onChange: function (v) { setAttr({ quoteBg: v || '#ffffff' }); } },
138 { label: __('Divider', 'blockenberg'), value: attr.dividerColor, onChange: function (v) { setAttr({ dividerColor: v || '#e5e7eb' }); } },
139 { label: __('Accent', 'blockenberg'), value: attr.accentColor, onChange: function (v) { setAttr({ accentColor: v || '#7c3aed' }); } }
140 ]
141 }),
142 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: false },
143 el(SelectControl, {
144 label: __('Layout', 'blockenberg'), value: attr.layout,
145 options: [
146 { label: 'Standard (logos + stats + quote)', value: 'standard' },
147 { label: 'Logos only', value: 'logos' },
148 { label: 'Stats only', value: 'stats' },
149 { label: 'Quote + stats', value: 'quote-stats' }
150 ],
151 onChange: function (v) { setAttr({ layout: v }); }, __nextHasNoMarginBottom: true
152 }),
153 el(RangeControl, { label: __('Max Width (px)', 'blockenberg'), value: attr.maxWidth, min: 600, max: 1400, onChange: function (v) { setAttr({ maxWidth: v }); }, __nextHasNoMarginBottom: true }),
154 el(RangeControl, { label: __('Padding Top (px)', 'blockenberg'), value: attr.paddingTop, min: 0, max: 200, onChange: function (v) { setAttr({ paddingTop: v }); }, __nextHasNoMarginBottom: true }),
155 el(RangeControl, { label: __('Padding Bottom (px)', 'blockenberg'), value: attr.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttr({ paddingBottom: v }); }, __nextHasNoMarginBottom: true })
156 )
157 );
158
159 var wrapStyle = {
160 background: attr.bgColor || '#f9fafb',
161 paddingTop: attr.paddingTop + 'px',
162 paddingBottom: attr.paddingBottom + 'px'
163 };
164
165 var validLogos = logos.filter(function (l) { return l.imageUrl; });
166
167 return el('div', blockProps, controls,
168 el('div', { style: wrapStyle },
169 el('div', { style: { maxWidth: attr.maxWidth + 'px', margin: '0 auto', textAlign: 'center' } },
170 attr.showEyebrow && el('p', {
171 style: { fontSize: attr.eyebrowSize + 'px', fontWeight: '600', color: attr.eyebrowColor, textTransform: 'uppercase', letterSpacing: '0.1em', margin: '0 0 12px' }
172 }, attr.eyebrow),
173 attr.showHeading && el(RichText, {
174 tagName: 'h2', value: attr.heading,
175 style: { fontSize: attr.headingSize + 'px', color: attr.headingColor, margin: '0 0 12px', fontWeight: attr.headingFontWeight||700 },
176 onChange: function (v) { setAttr({ heading: v }); }
177 }),
178 attr.showSubtext && el(RichText, {
179 tagName: 'p', value: attr.subtext,
180 style: { fontSize: '18px', color: attr.subtextColor, margin: '0 0 32px', lineHeight: '1.6' },
181 onChange: function (v) { setAttr({ subtext: v }); }
182 }),
183 // Logos strip
184 attr.showLogos && validLogos.length > 0 && el('div', {
185 style: { display: 'flex', gap: '32px', alignItems: 'center', justifyContent: 'center', flexWrap: 'wrap', marginBottom: '40px' }
186 }, validLogos.map(function (l, i) {
187 return el('img', { key: i, src: l.imageUrl, alt: l.imageAlt || '', style: { height: attr.logoHeight + 'px', objectFit: 'contain', opacity: 0.65, filter: attr.logoFilter === 'grayscale' || attr.logoFilter === 'grayscale-hover' ? 'grayscale(1)' : 'none' } });
188 })),
189 attr.showLogos && validLogos.length === 0 && el('div', {
190 style: { color: '#9ca3af', padding: '16px', border: '1px dashed #d1d5db', borderRadius: '8px', marginBottom: '32px', fontSize: '14px' }
191 }, 'Add logos in the sidebar →'),
192 // Stats
193 attr.showStats && stats.length > 0 && el('div', {
194 style: { display: 'flex', gap: '0', justifyContent: 'center', flexWrap: 'wrap', marginBottom: '40px', borderTop: '1px solid ' + attr.dividerColor, borderBottom: '1px solid ' + attr.dividerColor, padding: '32px 0' }
195 }, stats.map(function (stat, i) {
196 return el('div', { key: i, style: { flex: '1', minWidth: '120px', padding: '0 24px', borderRight: (attr.statDivider && i < stats.length - 1) ? '1px solid ' + attr.dividerColor : 'none' } },
197 el('div', { style: { fontSize: attr.statValueSize + 'px', fontWeight: attr.statValueFontWeight||800, color: attr.statValueColor, lineHeight: 1.1 } }, stat.value),
198 el('div', { style: { fontSize: attr.statLabelSize + 'px', color: attr.statLabelColor, marginTop: '4px' } }, stat.label)
199 );
200 })),
201 // Featured quote
202 attr.showQuote && el('div', {
203 style: { background: attr.quoteBg, borderRadius: '16px', padding: '32px 40px', textAlign: 'left', boxShadow: '0 1px 3px rgba(0,0,0,0.08)', maxWidth: '700px', margin: '0 auto' }
204 },
205 el('div', { style: { fontSize: '36px', color: attr.accentColor, lineHeight: 1, marginBottom: '12px', opacity: 0.4, fontFamily: 'Georgia, serif' } }, '\u201C'),
206 el(RichText, {
207 tagName: 'p', value: attr.quote,
208 style: { fontSize: attr.quoteSize + 'px', color: attr.quoteColor, fontStyle: 'italic', lineHeight: '1.65', margin: '0 0 20px' },
209 onChange: function (v) { setAttr({ quote: v }); }
210 }),
211 el('div', { style: { display: 'flex', alignItems: 'center', gap: '12px' } },
212 attr.quoteAvatarUrl
213 ? el('img', { src: attr.quoteAvatarUrl, style: { width: '40px', height: '40px', borderRadius: '50%', objectFit: 'cover' } })
214 : el('div', { style: { width: '40px', height: '40px', borderRadius: '50%', background: attr.accentColor, opacity: 0.15 } }),
215 el('div', {},
216 el('div', { style: { fontWeight: '700', color: attr.authorColor, fontSize: '15px' } }, attr.quoteAuthor),
217 el('div', { style: { color: attr.roleColor, fontSize: '13px' } }, attr.quoteRole)
218 )
219 )
220 )
221 )
222 )
223 );
224 },
225
226 save: function (props) {
227 return el('div', wp.blockEditor.useBlockProps.save(),
228 el('div', { className: 'bkbg-sps-app', 'data-opts': JSON.stringify(props.attributes) })
229 );
230 }
231 });
232 }() );
233