PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
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-feed / index.js

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

331 lines 24.9 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 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 MediaUpload = wp.blockEditor.MediaUpload;
9 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
10 var useBlockProps = wp.blockEditor.useBlockProps;
11 var PanelBody = wp.components.PanelBody;
12 var Button = wp.components.Button;
13 var ToggleControl = wp.components.ToggleControl;
14 var RangeControl = wp.components.RangeControl;
15 var SelectControl = wp.components.SelectControl;
16 var TextControl = wp.components.TextControl;
17 var TextareaControl = wp.components.TextareaControl;
18 var ColorPicker = wp.components.ColorPicker;
19 var Popover = wp.components.Popover;
20 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
21 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
22
23 var PLATFORM_OPTIONS = [
24 { label: 'Instagram', value: 'instagram' },
25 { label: 'X / Twitter', value: 'twitter' },
26 { label: 'LinkedIn', value: 'linkedin' },
27 { label: 'Facebook', value: 'facebook' },
28 { label: 'TikTok', value: 'tiktok' },
29 ];
30 var CARD_STYLE_OPTIONS = [
31 { label: __('Card (shadow)', 'blockenberg'), value: 'card' },
32 { label: __('Bordered', 'blockenberg'), value: 'bordered' },
33 { label: __('Flat', 'blockenberg'), value: 'flat' },
34 ];
35 var HOVER_OPTIONS = [
36 { label: __('Lift', 'blockenberg'), value: 'lift' },
37 { label: __('None', 'blockenberg'), value: 'none' },
38 ];
39 var RATIO_OPTIONS = [
40 { label: '1 / 1', value: '1/1' },
41 { label: '4 / 3', value: '4/3' },
42 { label: '16 / 9', value: '16/9' },
43 { label: '3 / 2', value: '3/2' },
44 ];
45 var COLS_OPTIONS = [
46 { label: '1', value: 1 }, { label: '2', value: 2 },
47 { label: '3', value: 3 }, { label: '4', value: 4 },
48 ];
49
50 var PLATFORM_ICONS = {
51 instagram: '📸',
52 twitter: '🐦',
53 linkedin: '💼',
54 facebook: '📘',
55 tiktok: '🎵',
56 };
57 var PLATFORM_COLORS = {
58 instagram: '#e1306c',
59 twitter: '#1da1f2',
60 linkedin: '#0077b5',
61 facebook: '#1877f2',
62 tiktok: '#010101',
63 };
64
65 function makeId() { return 'sf' + Math.random().toString(36).substr(2, 5); }
66
67 function buildWrapStyle(a) {
68 var s = {
69 '--bkbg-sf-accent': a.accentColor,
70 '--bkbg-sf-card-bg': a.cardBg,
71 '--bkbg-sf-card-border': a.cardBorderColor,
72 '--bkbg-sf-text-color': a.textColor,
73 '--bkbg-sf-username': a.usernameColor,
74 '--bkbg-sf-metrics': a.metricsColor,
75 '--bkbg-sf-content-sz': a.contentSize + 'px',
76 '--bkbg-sf-username-sz': a.usernameSize + 'px',
77 '--bkbg-sf-metrics-sz': a.metricsSize + 'px',
78 '--bkbg-sf-card-r': a.cardRadius + 'px',
79 '--bkbg-sf-card-pad': a.cardPadding + 'px',
80 '--bkbg-sf-img-r': a.imageRadius + 'px',
81 '--bkbg-sf-cols': a.columns,
82 '--bkbg-sf-gap': a.gap + 'px',
83 '--bkbg-sf-content-lines':a.contentLines,
84 paddingTop: a.paddingTop + 'px',
85 paddingBottom: a.paddingBottom + 'px',
86 backgroundColor: a.bgColor || undefined,
87 };
88 var _tvFn = getTypoCssVars();
89 if (_tvFn) {
90 Object.assign(s, _tvFn(a.usernameTypo || {}, '--bksf-un-'));
91 Object.assign(s, _tvFn(a.contentTypo || {}, '--bksf-ct-'));
92 Object.assign(s, _tvFn(a.metricsTypo || {}, '--bksf-mt-'));
93 }
94 return s;
95 }
96
97 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
98 var isOpen = openKey === key;
99 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
100 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
101 el('div', { style: { position: 'relative', flexShrink: 0 } },
102 el('button', { type: 'button', title: value || 'default', onClick: function () { setOpenKey(isOpen ? null : key); },
103 style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#ccc' }
104 }),
105 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
106 el('div', { style: { padding: '8px' } },
107 el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange })
108 )
109 )
110 )
111 );
112 }
113
114 function ratioPercent(r) {
115 var p = r.split('/');
116 return (parseInt(p[1], 10) / parseInt(p[0], 10) * 100).toFixed(2) + '%';
117 }
118
119 /* ── Single post card ───────────────────────────────────────────── */
120 function PostCard(props) {
121 var post = props.post;
122 var a = props.a;
123 var isEditor = props.isEditor;
124 var pColor = PLATFORM_COLORS[post.platform] || a.accentColor;
125 var pIcon = PLATFORM_ICONS[post.platform] || '🌐';
126 var hasTypo = a.usernameTypo !== undefined;
127
128 var cardStyle = {
129 background: a.cardBg,
130 borderRadius: a.cardRadius + 'px',
131 padding: a.cardPadding + 'px',
132 border: a.cardStyle === 'bordered' ? ('1.5px solid ' + a.cardBorderColor) : 'none',
133 boxShadow: a.cardStyle === 'card' ? '0 4px 20px rgba(0,0,0,0.08)' : 'none',
134 display: 'flex',
135 flexDirection: 'column',
136 gap: '12px',
137 overflow: 'hidden',
138 };
139
140 return el('div', { className: 'bkbg-sf-card bkbg-sf-card--' + a.cardStyle + ' bkbg-sf-hover--' + a.hoverEffect, style: cardStyle },
141 /* Header: avatar + username + platform badge */
142 el('div', { className: 'bkbg-sf-card-header', style: { display: 'flex', alignItems: 'center', gap: '10px' } },
143 a.showAvatar && el('div', { className: 'bkbg-sf-avatar', style: { width: '42px', height: '42px', borderRadius: '50%', flexShrink: 0, overflow: 'hidden', background: pColor + '22', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '20px' } },
144 post.avatarUrl
145 ? el('img', { src: post.avatarUrl, alt: post.username, style: { width: '100%', height: '100%', objectFit: 'cover' } })
146 : el('span', null, pIcon)
147 ),
148 el('div', { style: { flex: 1, minWidth: 0 } },
149 a.showUsername && el('div', { className: 'bkbg-sf-username', style: hasTypo ? { color: a.usernameColor, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } : { fontSize: a.usernameSize + 'px', fontWeight: a.usernameFontWeight||700, color: a.usernameColor, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, post.username),
150 a.showTimeAgo && el('div', { className: 'bkbg-sf-time', style: hasTypo ? { color: a.metricsColor } : { fontSize: (a.metricsSize) + 'px', color: a.metricsColor } }, post.timeAgo)
151 ),
152 a.showPlatformBadge && el('div', { className: 'bkbg-sf-badge', style: { width: '32px', height: '32px', borderRadius: '8px', background: pColor + '18', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '16px', flexShrink: 0 } }, pIcon)
153 ),
154
155 /* Image */
156 a.showImage && post.imageUrl && el('div', { className: 'bkbg-sf-image', style: { borderRadius: a.imageRadius + 'px', overflow: 'hidden', position: 'relative' } },
157 el('div', { style: { paddingBottom: ratioPercent(a.imageRatio) } }),
158 el('img', { src: post.imageUrl, alt: '', loading: 'lazy', style: { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' } })
159 ),
160
161 /* Content text */
162 el('p', { className: 'bkbg-sf-content', style: hasTypo ? { color: a.textColor, margin: 0, lineHeight: 1.6, flex: 1 } : { fontSize: a.contentSize + 'px', color: a.textColor, margin: 0, lineHeight: 1.6, flex: 1 } }, post.content),
163
164 /* Metrics: likes + comments */
165 a.showMetrics && el('div', { className: 'bkbg-sf-metrics', style: hasTypo ? { display: 'flex', gap: '16px', paddingTop: '4px', borderTop: '1px solid ' + (a.cardBorderColor || '#f3f4f6'), color: a.metricsColor } : { display: 'flex', gap: '16px', paddingTop: '4px', borderTop: '1px solid ' + (a.cardBorderColor || '#f3f4f6'), fontSize: a.metricsSize + 'px', color: a.metricsColor } },
166 el('span', { style: { display: 'flex', alignItems: 'center', gap: '5px' } }, '❤️ ', post.likes),
167 el('span', { style: { display: 'flex', alignItems: 'center', gap: '5px' } }, '💬 ', post.comments)
168 )
169 );
170 }
171
172 registerBlockType('blockenberg/social-feed', {
173 title: __('Social Feed', 'blockenberg'),
174 icon: 'share',
175 category: 'bkbg-marketing',
176
177 edit: function (props) {
178 var a = props.attributes;
179 var setAttributes = props.setAttributes;
180
181 var openColorKeyState = useState(null);
182 var openColorKey = openColorKeyState[0];
183 var setOpenColorKey = openColorKeyState[1];
184
185 var blockProps = useBlockProps({ style: buildWrapStyle(a) });
186
187 function cc(key, label, attrKey) {
188 return renderColorControl(key, label, a[attrKey], function (val) {
189 var upd = {}; upd[attrKey] = val; setAttributes(upd);
190 }, openColorKey, setOpenColorKey);
191 }
192
193 function updatePost(id, key, val) {
194 setAttributes({ posts: a.posts.map(function (p) {
195 if (p.id !== id) return p;
196 var u = Object.assign({}, p); u[key] = val; return u;
197 }) });
198 }
199
200 var gridStyle = { display: 'grid', gridTemplateColumns: 'repeat(' + a.columns + ', 1fr)', gap: a.gap + 'px' };
201
202 return el(Fragment, null,
203 el(InspectorControls, null,
204 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: true },
205 el(SelectControl, { label: __('Columns (desktop)', 'blockenberg'), value: a.columns, options: COLS_OPTIONS, onChange: function (v) { setAttributes({ columns: parseInt(v,10) }); } }),
206 el(SelectControl, { label: __('Columns (tablet)', 'blockenberg'), value: a.columnsTablet, options: COLS_OPTIONS, onChange: function (v) { setAttributes({ columnsTablet: parseInt(v,10) }); } }),
207 el(SelectControl, { label: __('Columns (mobile)', 'blockenberg'), value: a.columnsMobile, options: COLS_OPTIONS.slice(0,2), onChange: function (v) { setAttributes({ columnsMobile: parseInt(v,10) }); } }),
208 el(RangeControl, { label: __('Gap (px)', 'blockenberg'), value: a.gap, min: 8, max: 48, onChange: function (v) { setAttributes({ gap: v }); } })
209 ),
210 el(PanelBody, { title: __('Card Style', 'blockenberg'), initialOpen: false },
211 el(SelectControl, { label: __('Card style', 'blockenberg'), value: a.cardStyle, options: CARD_STYLE_OPTIONS, onChange: function (v) { setAttributes({ cardStyle: v }); } }),
212 el(SelectControl, { label: __('Hover effect', 'blockenberg'), value: a.hoverEffect, options: HOVER_OPTIONS, onChange: function (v) { setAttributes({ hoverEffect: v }); } }),
213 el(RangeControl, { label: __('Padding (px)', 'blockenberg'), value: a.cardPadding, min: 10, max: 40, onChange: function (v) { setAttributes({ cardPadding: v }); } }),
214 el(RangeControl, { label: __('Radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 32, onChange: function (v) { setAttributes({ cardRadius: v }); } })
215 ),
216 el(PanelBody, { title: __('Display', 'blockenberg'), initialOpen: false },
217 el(ToggleControl, { label: __('Show platform badge', 'blockenberg'), checked: a.showPlatformBadge, onChange: function (v) { setAttributes({ showPlatformBadge: v }); }, __nextHasNoMarginBottom: true }),
218 el(ToggleControl, { label: __('Show avatar', 'blockenberg'), checked: a.showAvatar, onChange: function (v) { setAttributes({ showAvatar: v }); }, __nextHasNoMarginBottom: true }),
219 el(ToggleControl, { label: __('Show username', 'blockenberg'), checked: a.showUsername, onChange: function (v) { setAttributes({ showUsername: v }); }, __nextHasNoMarginBottom: true }),
220 el(ToggleControl, { label: __('Show time ago', 'blockenberg'), checked: a.showTimeAgo, onChange: function (v) { setAttributes({ showTimeAgo: v }); }, __nextHasNoMarginBottom: true }),
221 el(ToggleControl, { label: __('Show post image', 'blockenberg'), checked: a.showImage, onChange: function (v) { setAttributes({ showImage: v }); }, __nextHasNoMarginBottom: true }),
222 el(ToggleControl, { label: __('Show metrics', 'blockenberg'), checked: a.showMetrics, onChange: function (v) { setAttributes({ showMetrics: v }); }, __nextHasNoMarginBottom: true }),
223 a.showImage && el(SelectControl, { label: __('Image ratio', 'blockenberg'), value: a.imageRatio, options: RATIO_OPTIONS, onChange: function (v) { setAttributes({ imageRatio: v }); } }),
224 a.showImage && el(RangeControl, { label: __('Image radius (px)', 'blockenberg'), value: a.imageRadius, min: 0, max: 24, onChange: function (v) { setAttributes({ imageRadius: v }); } }),
225 el(RangeControl, { label: __('Content max lines', 'blockenberg'), value: a.contentLines, min: 2, max: 10, onChange: function (v) { setAttributes({ contentLines: v }); } })
226 ),
227 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
228 getTypoControl() && el(getTypoControl(), {
229 label: __('Username', 'blockenberg'),
230 value: a.usernameTypo || {},
231 onChange: function (v) { setAttributes({ usernameTypo: v }); }
232 }),
233 getTypoControl() && el(getTypoControl(), {
234 label: __('Content', 'blockenberg'),
235 value: a.contentTypo || {},
236 onChange: function (v) { setAttributes({ contentTypo: v }); }
237 }),
238 getTypoControl() && el(getTypoControl(), {
239 label: __('Metrics', 'blockenberg'),
240 value: a.metricsTypo || {},
241 onChange: function (v) { setAttributes({ metricsTypo: v }); }
242 })
243 ),
244 el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false },
245 cc('accentColor', __('Accent', 'blockenberg'), 'accentColor'),
246 cc('cardBg', __('Card background', 'blockenberg'), 'cardBg'),
247 cc('cardBorderColor', __('Card border', 'blockenberg'), 'cardBorderColor'),
248 cc('usernameColor', __('Username text', 'blockenberg'), 'usernameColor'),
249 cc('textColor', __('Content text', 'blockenberg'), 'textColor'),
250 cc('metricsColor', __('Metrics / meta', 'blockenberg'), 'metricsColor'),
251 cc('bgColor', __('Section bg', 'blockenberg'), 'bgColor')
252 ),
253 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
254 el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
255 el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
256 ),
257 el(PanelBody, { title: __('Posts', 'blockenberg'), initialOpen: false },
258 a.posts.map(function (post, pi) {
259 return el(PanelBody, { key: post.id, title: (PLATFORM_ICONS[post.platform] || '🌐') + ' ' + (post.username || 'Post ' + (pi + 1)), initialOpen: false },
260 el(SelectControl, { label: __('Platform', 'blockenberg'), value: post.platform, options: PLATFORM_OPTIONS, onChange: function (v) { updatePost(post.id, 'platform', v); } }),
261 el(TextControl, { label: __('Username', 'blockenberg'), value: post.username, onChange: function (v) { updatePost(post.id, 'username', v); } }),
262 el(TextareaControl, { label: __('Content', 'blockenberg'), value: post.content, onChange: function (v) { updatePost(post.id, 'content', v); }, rows: 3 }),
263 el(TextControl, { label: __('Likes', 'blockenberg'), value: post.likes, onChange: function (v) { updatePost(post.id, 'likes', v); } }),
264 el(TextControl, { label: __('Comments', 'blockenberg'), value: post.comments, onChange: function (v) { updatePost(post.id, 'comments', v); } }),
265 el(TextControl, { label: __('Time ago', 'blockenberg'), value: post.timeAgo, onChange: function (v) { updatePost(post.id, 'timeAgo', v); } }),
266 el('p', { style: { fontSize: '12px', margin: '4px 0 4px', fontWeight: 600 } }, __('Post image', 'blockenberg')),
267 el(MediaUploadCheck, null,
268 el(MediaUpload, {
269 onSelect: function (m) { updatePost(post.id, 'imageUrl', m.url); updatePost(post.id, 'imageId', m.id); },
270 allowedTypes: ['image'], value: post.imageId,
271 render: function (p) { return el('div', null,
272 post.imageUrl && el('img', { src: post.imageUrl, style: { width: '100%', borderRadius: '6px', marginBottom: '4px' } }),
273 el(Button, { onClick: p.open, variant: post.imageUrl ? 'secondary' : 'primary', size: 'compact' }, post.imageUrl ? __('Replace image', 'blockenberg') : __('Add image', 'blockenberg'))
274 ); }
275 })
276 ),
277 el('p', { style: { fontSize: '12px', margin: '8px 0 4px', fontWeight: 600 } }, __('Avatar', 'blockenberg')),
278 el(MediaUploadCheck, null,
279 el(MediaUpload, {
280 onSelect: function (m) { updatePost(post.id, 'avatarUrl', m.url); updatePost(post.id, 'avatarId', m.id); },
281 allowedTypes: ['image'], value: post.avatarId,
282 render: function (p) { return el(Button, { onClick: p.open, variant: post.avatarUrl ? 'secondary' : 'tertiary', size: 'compact' }, post.avatarUrl ? __('Replace avatar', 'blockenberg') : __('Set avatar', 'blockenberg')); }
283 })
284 ),
285 el(Button, { onClick: function () { setAttributes({ posts: a.posts.filter(function (p) { return p.id !== post.id; }) }); }, isDestructive: true, variant: 'tertiary', size: 'compact', style: { marginTop: '8px' } }, __('Remove post', 'blockenberg'))
286 );
287 }),
288 el(Button, { variant: 'primary', onClick: function () {
289 setAttributes({ posts: a.posts.concat([{ id: makeId(), platform: 'instagram', username: '@newpost', avatarUrl: '', avatarId: 0, content: __('Add your post content here…', 'blockenberg'), imageUrl: '', imageId: 0, likes: '0', comments: '0', timeAgo: 'Just now' }]) });
290 }, style: { marginTop: '8px' } }, __('+ Add Post', 'blockenberg'))
291 )
292 ),
293
294 el('div', blockProps,
295 el('div', { className: 'bkbg-sf-grid', style: gridStyle, 'data-cols-tablet': a.columnsTablet, 'data-cols-mobile': a.columnsMobile },
296 a.posts.map(function (post) {
297 return el(PostCard, { key: post.id, post: post, a: a, isEditor: true });
298 })
299 )
300 )
301 );
302 },
303
304 save: function (props) {
305 var a = props.attributes;
306 return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-sf-wrapper', style: buildWrapStyle(a) }),
307 el('div', { className: 'bkbg-sf-grid', style: { display: 'grid', gridTemplateColumns: 'repeat(' + a.columns + ', 1fr)', gap: a.gap + 'px' }, 'data-cols-tablet': a.columnsTablet, 'data-cols-mobile': a.columnsMobile },
308 a.posts.map(function (post) {
309 return el(PostCard, { key: post.id, post: post, a: a, isEditor: false });
310 })
311 )
312 );
313 },
314
315 deprecated: [{
316 attributes: {"posts":{"type":"array","default":[{"id":"sf001","platform":"instagram","username":"@studio.design","avatarUrl":"","avatarId":0,"content":"Just launched our new design system 🎨","imageUrl":"","imageId":0,"likes":"4.2k","comments":"138","timeAgo":"2h ago"},{"id":"sf002","platform":"twitter","username":"@devteam","avatarUrl":"","avatarId":0,"content":"Hot take: the best code is the code you never have to write again.","imageUrl":"","imageId":0,"likes":"891","comments":"74","timeAgo":"5h ago"},{"id":"sf003","platform":"linkedin","username":"Creative Agency","avatarUrl":"","avatarId":0,"content":"Excited to announce we've crossed 10,000 clients worldwide!","imageUrl":"","imageId":0,"likes":"2.1k","comments":"312","timeAgo":"1d ago"}]},"columns":{"type":"integer","default":3},"columnsTablet":{"type":"integer","default":2},"columnsMobile":{"type":"integer","default":1},"gap":{"type":"integer","default":20},"cardStyle":{"type":"string","default":"card"},"cardPadding":{"type":"integer","default":20},"cardRadius":{"type":"integer","default":16},"imageRatio":{"type":"string","default":"1/1"},"imageRadius":{"type":"integer","default":12},"contentLines":{"type":"integer","default":4},"showImage":{"type":"boolean","default":true},"showPlatformBadge":{"type":"boolean","default":true},"showAvatar":{"type":"boolean","default":true},"showUsername":{"type":"boolean","default":true},"showTimeAgo":{"type":"boolean","default":true},"showMetrics":{"type":"boolean","default":true},"hoverEffect":{"type":"string","default":"lift"},"accentColor":{"type":"string","default":"#6c3fb5"},"cardBg":{"type":"string","default":"#ffffff"},"cardBorderColor":{"type":"string","default":"#e5e7eb"},"textColor":{"type":"string","default":"#374151"},"usernameColor":{"type":"string","default":"#111827"},"metricsColor":{"type":"string","default":"#9ca3af"},"contentSize":{"type":"integer","default":14},"usernameSize":{"type":"integer","default":14},"metricsSize":{"type":"integer","default":13},"bgColor":{"type":"string","default":""},"paddingTop":{"type":"integer","default":60},"paddingBottom":{"type":"integer","default":60},"usernameFontWeight":{"type":"number","default":600}},
317 save: function (props) {
318 var a = props.attributes;
319 /* old save — PostCard with inline font styles, no typo CSS vars */
320 return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-sf-wrapper', style: buildWrapStyle(a) }),
321 el('div', { className: 'bkbg-sf-grid', style: { display: 'grid', gridTemplateColumns: 'repeat(' + a.columns + ', 1fr)', gap: a.gap + 'px' }, 'data-cols-tablet': a.columnsTablet, 'data-cols-mobile': a.columnsMobile },
322 a.posts.map(function (post) {
323 return el(PostCard, { key: post.id, post: post, a: a, isEditor: false });
324 })
325 )
326 );
327 }
328 }]
329 });
330 }() );
331