PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.12
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.12
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.12, at blocks/social-proof-section/index.js

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