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 / video-grid / index.js

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

363 lines 27.1 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 RichText = wp.blockEditor.RichText;
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 TextControl = wp.components.TextControl;
17 var ColorPicker = wp.components.ColorPicker;
18 var Popover = wp.components.Popover;
19
20 var _tc, _tvf;
21 Object.defineProperty(window, '_tc', { get: function () { return _tc || (_tc = window.bkbgTypographyControl); } });
22 Object.defineProperty(window, '_tvf', { get: function () { return _tvf || (_tvf = window.bkbgTypoCssVars); } });
23 function getTypoControl(label, key, attrs, setA) { return _tc(label, key, attrs, setA); }
24 function getTypoCssVars(attrs) {
25 var v = {};
26 _tvf(v, 'sectionTitleTypo', attrs, '--bkvg-stt-');
27 _tvf(v, 'cardTitleTypo', attrs, '--bkvg-ct-');
28 _tvf(v, 'descTypo', attrs, '--bkvg-ds-');
29 return v;
30 }
31
32 var COLUMNS_OPTIONS = [
33 { label: '1', value: 1 },
34 { label: '2', value: 2 },
35 { label: '3', value: 3 },
36 { label: '4', value: 4 },
37 ];
38
39 var ASPECT_OPTIONS = [
40 { label: '16:9', value: '16/9' },
41 { label: '4:3', value: '4/3' },
42 { label: '1:1', value: '1/1' },
43 ];
44
45 function makeId() { return 'vg' + Math.random().toString(36).substr(2, 5); }
46
47 /* Extract YouTube video ID from any YouTube URL */
48 function getYoutubeId(url) {
49 if (!url) return null;
50 var match = url.match(/(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))([\w-]{11})/);
51 return match ? match[1] : null;
52 }
53
54 function getThumbUrl(video) {
55 if (video.thumbUrl) return video.thumbUrl;
56 var ytId = getYoutubeId(video.url);
57 if (ytId) return 'https://img.youtube.com/vi/' + ytId + '/mqdefault.jpg';
58 return '';
59 }
60
61 function buildWrapStyle(a) {
62 var s = getTypoCssVars(a);
63 s['--bkbg-vg-accent'] = a.accentColor;
64 s['--bkbg-vg-play-btn-bg'] = a.playBtnBg;
65 s['--bkbg-vg-play-btn-color'] = a.playBtnColor;
66 s['--bkbg-vg-card-bg'] = a.cardBg;
67 s['--bkbg-vg-card-border'] = a.cardBorder;
68 s['--bkbg-vg-dur-bg'] = a.durationBg;
69 s['--bkbg-vg-dur-color'] = a.durationColor;
70 s['--bkbg-vg-filter-active-bg'] = a.filterActiveBg;
71 s['--bkbg-vg-filter-active-c'] = a.filterActiveColor;
72 s['--bkbg-vg-filter-bg'] = a.filterInactiveBg;
73 s['--bkbg-vg-filter-c'] = a.filterInactiveColor;
74 s['--bkbg-vg-title-color'] = a.sectionTitleColor;
75 s['--bkbg-vg-card-title-c'] = a.titleColor;
76 s['--bkbg-vg-desc-color'] = a.descColor;
77 s['--bkbg-vg-cat-color'] = a.categoryColor;
78 s['--bkbg-vg-card-r'] = a.cardRadius + 'px';
79 s['--bkbg-vg-thumb-r'] = a.thumbRadius + 'px';
80 s['--bkbg-vg-play-size'] = a.playBtnSize + 'px';
81 s.paddingTop = a.paddingTop + 'px';
82 s.paddingBottom = a.paddingBottom + 'px';
83 s.backgroundColor = a.bgColor || undefined;
84 return s;
85 }
86
87 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
88 var isOpen = openKey === key;
89 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
90 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
91 el('div', { style: { position: 'relative', flexShrink: 0 } },
92 el('button', { type: 'button', onClick: function () { setOpenKey(isOpen ? null : key); }, style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#ccc' } }),
93 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
94 el('div', { style: { padding: '8px' } },
95 el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange })
96 )
97 )
98 )
99 );
100 }
101
102 /* ── Video Card preview ─────────────────────────────────────────── */
103 function VideoCard(props) {
104 var video = props.video;
105 var a = props.a;
106 var thumbUrl = getThumbUrl(video);
107 var ar = a.aspectRatio.replace('/', '/'); /* keep as-is for aspect-ratio CSS */
108
109 return el('div', { className: 'bkbg-vg-card', style: { background: a.cardBg, border: '1px solid ' + a.cardBorder, borderRadius: a.cardRadius + 'px', overflow: 'hidden' } },
110 /* Thumbnail */
111 el('div', { className: 'bkbg-vg-thumb-wrap', style: { position: 'relative', aspectRatio: a.aspectRatio, background: '#111', overflow: 'hidden', borderRadius: a.thumbRadius + 'px' } },
112 thumbUrl
113 ? el('img', { src: thumbUrl, alt: video.title, style: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' } })
114 : el('div', { style: { width: '100%', height: '100%', background: '#374151', display: 'flex', alignItems: 'center', justifyContent: 'center' } },
115 el('span', { style: { fontSize: '28px' } }, '🎥')
116 ),
117 /* Play button */
118 el('div', { className: 'bkbg-vg-play-btn', style: { position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', width: a.playBtnSize + 'px', height: a.playBtnSize + 'px', borderRadius: '50%', background: a.playBtnBg, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 4px 20px rgba(0,0,0,0.3)' } },
119 el('span', { style: { color: a.playBtnColor, fontSize: a.playBtnSize * 0.4 + 'px', marginLeft: '3px' } }, '')
120 ),
121 /* Duration */
122 a.showDuration && video.duration && el('div', { className: 'bkbg-vg-duration', style: { position: 'absolute', bottom: '8px', right: '8px', background: a.durationBg, color: a.durationColor, fontSize: '11px', fontWeight: 700, padding: '2px 7px', borderRadius: '5px' } }, video.duration),
123 /* Category pill */
124 a.showCategory && video.category && el('div', { className: 'bkbg-vg-cat', style: { position: 'absolute', top: '8px', left: '8px', background: a.accentColor, color: '#fff', fontSize: '11px', fontWeight: 700, padding: '2px 8px', borderRadius: '99px' } }, video.category)
125 ),
126 /* Card body */
127 el('div', { className: 'bkbg-vg-card-body', style: { padding: '12px 14px' } },
128 el('p', { className: 'bkbg-vg-card-title', style: { margin: '0 0 4px', color: a.titleColor } }, video.title || __('Untitled', 'blockenberg')),
129 a.showDescription && video.description && el('p', { className: 'bkbg-vg-desc', style: { margin: 0, color: a.descColor } }, video.description)
130 )
131 );
132 }
133
134 registerBlockType('blockenberg/video-grid', {
135 title: __('Video Grid', 'blockenberg'),
136 icon: 'video-alt3',
137 category: 'bkbg-media',
138
139 edit: function (props) {
140 var a = props.attributes;
141 var setAttributes = props.setAttributes;
142
143 var openColorKeyState = useState(null);
144 var openColorKey = openColorKeyState[0];
145 var setOpenColorKey = openColorKeyState[1];
146
147 var editingVideoState = useState(null);
148 var editingVideo = editingVideoState[0];
149 var setEditingVideo = editingVideoState[1];
150
151 var blockProps = useBlockProps({ style: buildWrapStyle(a) });
152
153 function cc(key, label, attrKey) {
154 return renderColorControl(key, label, a[attrKey], function (val) {
155 var upd = {}; upd[attrKey] = val; setAttributes(upd);
156 }, openColorKey, setOpenColorKey);
157 }
158
159 function updateVideo(id, key, val) {
160 setAttributes({ videos: a.videos.map(function (v) {
161 if (v.id !== id) return v;
162 var u = Object.assign({}, v); u[key] = val; return u;
163 }) });
164 }
165
166 function removeVideo(id) {
167 setAttributes({ videos: a.videos.filter(function (v) { return v.id !== id; }) });
168 if (editingVideo === id) setEditingVideo(null);
169 }
170
171 function addVideo() {
172 var newId = makeId();
173 setAttributes({ videos: a.videos.concat([{ id: newId, title: __('New Video', 'blockenberg'), url: '', thumbUrl: '', thumbId: 0, duration: '', category: '', description: '' }]) });
174 setEditingVideo(newId);
175 }
176
177 /* Get unique categories for filter preview */
178 var categories = a.videos.reduce(function (acc, v) {
179 if (v.category && acc.indexOf(v.category) === -1) acc.push(v.category);
180 return acc;
181 }, []);
182
183 return el(Fragment, null,
184 el(InspectorControls, null,
185 el(PanelBody, { title: __('Videos', 'blockenberg'), initialOpen: true },
186 a.videos.map(function (video, idx) {
187 var isEditing = editingVideo === video.id;
188 return el('div', { key: video.id, style: { border: '1px solid #e0e0e0', borderRadius: '8px', marginBottom: '8px', overflow: 'hidden' } },
189 /* Collapsed header */
190 el('div', { onClick: function () { setEditingVideo(isEditing ? null : video.id); }, style: { display: 'flex', alignItems: 'center', gap: '8px', padding: '8px 10px', cursor: 'pointer', background: isEditing ? '#f0e9ff' : '#fafafa', borderBottom: isEditing ? '1px solid #e0e0e0' : 'none' } },
191 el('span', { style: { fontSize: '12px', fontWeight: 700, color: '#555', minWidth: '18px' } }, (idx + 1) + '.'),
192 el('span', { style: { flex: 1, fontSize: '12px', fontWeight: 600, color: '#333', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, video.title || __('Untitled', 'blockenberg')),
193 el('span', { style: { fontSize: '12px', color: '#6c3fb5', fontWeight: 700 } }, isEditing ? '' : '')
194 ),
195 isEditing && el('div', { style: { padding: '10px' } },
196 el(TextControl, { label: __('Title', 'blockenberg'), value: video.title, onChange: function (v) { updateVideo(video.id, 'title', v); } }),
197 el(TextControl, { label: __('Video URL (YouTube/Vimeo)', 'blockenberg'), value: video.url, onChange: function (v) { updateVideo(video.id, 'url', v); } }),
198 el(TextControl, { label: __('Duration', 'blockenberg'), value: video.duration, onChange: function (v) { updateVideo(video.id, 'duration', v); }, placeholder: '12:34' }),
199 el(TextControl, { label: __('Category', 'blockenberg'), value: video.category, onChange: function (v) { updateVideo(video.id, 'category', v); } }),
200 el(TextControl, { label: __('Short description', 'blockenberg'), value: video.description, onChange: function (v) { updateVideo(video.id, 'description', v); } }),
201 el('div', { style: { marginBottom: '8px' } },
202 el('p', { style: { fontSize: '12px', fontWeight: 600, color: '#1e1e1e', marginBottom: '4px' } }, __('Thumbnail', 'blockenberg')),
203 video.thumbUrl && el('img', { src: video.thumbUrl, alt: '', style: { width: '100%', borderRadius: '6px', marginBottom: '6px', display: 'block' } }),
204 !video.thumbUrl && el('p', { style: { fontSize: '11px', color: '#999', marginBottom: '6px' } }, __('Auto-generated from YouTube URL, or upload custom thumb.', 'blockenberg')),
205 el(MediaUploadCheck, null,
206 el(MediaUpload, { onSelect: function (media) { setAttributes({ videos: a.videos.map(function (v) { return v.id !== video.id ? v : Object.assign({}, v, { thumbUrl: media.url, thumbId: media.id }); }) }); }, allowedTypes: ['image'], value: video.thumbId,
207 render: function (renderProps) {
208 return el(Button, { variant: 'secondary', size: 'compact', onClick: renderProps.open }, video.thumbUrl ? __('Change thumbnail', 'blockenberg') : __('Upload thumbnail', 'blockenberg'));
209 }
210 })
211 ),
212 video.thumbUrl && el(Button, { variant: 'tertiary', isDestructive: true, size: 'compact', onClick: function () { updateVideo(video.id, 'thumbUrl', ''); updateVideo(video.id, 'thumbId', 0); }, style: { marginLeft: '6px' } }, __('Remove thumb', 'blockenberg'))
213 ),
214 el(Button, { isDestructive: true, variant: 'tertiary', size: 'compact', onClick: function () { removeVideo(video.id); } }, __('Remove video', 'blockenberg'))
215 )
216 );
217 }),
218 el(Button, { variant: 'secondary', onClick: addVideo, style: { width: '100%', justifyContent: 'center' } }, '+ ' + __('Add Video', 'blockenberg'))
219 ),
220 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: false },
221 el('fieldset', { style: { border: 'none', padding: 0, margin: '0 0 12px' } },
222 el('legend', { style: { fontSize: '12px', fontWeight: 600, color: '#1e1e1e', marginBottom: '6px' } }, __('Columns', 'blockenberg')),
223 el('div', { style: { display: 'flex', gap: '6px' } },
224 COLUMNS_OPTIONS.map(function (opt) {
225 return el('button', { key: opt.value, type: 'button', onClick: function () { setAttributes({ columns: opt.value }); },
226 style: { flex: 1, padding: '6px', border: a.columns === opt.value ? '2px solid #6c3fb5' : '1px solid #ddd', borderRadius: '6px', background: a.columns === opt.value ? '#f0e9ff' : '#fff', cursor: 'pointer', fontWeight: 700, color: a.columns === opt.value ? '#6c3fb5' : '#555' }
227 }, opt.label);
228 })
229 )
230 ),
231 el('fieldset', { style: { border: 'none', padding: 0, margin: '0 0 12px' } },
232 el('legend', { style: { fontSize: '12px', fontWeight: 600, color: '#1e1e1e', marginBottom: '6px' } }, __('Aspect ratio', 'blockenberg')),
233 el('div', { style: { display: 'flex', gap: '6px' } },
234 ASPECT_OPTIONS.map(function (opt) {
235 return el('button', { key: opt.value, type: 'button', onClick: function () { setAttributes({ aspectRatio: opt.value }); },
236 style: { flex: 1, padding: '6px', border: a.aspectRatio === opt.value ? '2px solid #6c3fb5' : '1px solid #ddd', borderRadius: '6px', background: a.aspectRatio === opt.value ? '#f0e9ff' : '#fff', cursor: 'pointer', fontWeight: 700, color: a.aspectRatio === opt.value ? '#6c3fb5' : '#555' }
237 }, opt.label);
238 })
239 )
240 ),
241 el(RangeControl, { label: __('Gap (px)', 'blockenberg'), value: a.gap, min: 8, max: 48, onChange: function (v) { setAttributes({ gap: v }); } })
242 ),
243 el(PanelBody, { title: __('Display', 'blockenberg'), initialOpen: false },
244 el(ToggleControl, { label: __('Show category filter bar', 'blockenberg'), checked: a.showFilter, onChange: function (v) { setAttributes({ showFilter: v }); }, __nextHasNoMarginBottom: true }),
245 el(ToggleControl, { label: __('Show category pill on card', 'blockenberg'), checked: a.showCategory, onChange: function (v) { setAttributes({ showCategory: v }); }, __nextHasNoMarginBottom: true }),
246 el(ToggleControl, { label: __('Show duration badge', 'blockenberg'), checked: a.showDuration, onChange: function (v) { setAttributes({ showDuration: v }); }, __nextHasNoMarginBottom: true }),
247 el(ToggleControl, { label: __('Show description', 'blockenberg'), checked: a.showDescription, onChange: function (v) { setAttributes({ showDescription: v }); }, __nextHasNoMarginBottom: true })
248 ),
249 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
250 getTypoControl(__('Section Title', 'blockenberg'), 'sectionTitleTypo', a, setAttributes),
251 getTypoControl(__('Card Title', 'blockenberg'), 'cardTitleTypo', a, setAttributes),
252 getTypoControl(__('Description', 'blockenberg'), 'descTypo', a, setAttributes)
253 ),
254 el(PanelBody, { title: __('Appearance', 'blockenberg'), initialOpen: false },
255 el(RangeControl, { label: __('Card radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 24, onChange: function (v) { setAttributes({ cardRadius: v }); } }),
256 el(RangeControl, { label: __('Thumb radius (px)', 'blockenberg'), value: a.thumbRadius, min: 0, max: 24, onChange: function (v) { setAttributes({ thumbRadius: v }); } }),
257 el(RangeControl, { label: __('Play button size (px)','blockenberg'), value: a.playBtnSize, min: 32, max: 96, onChange: function (v) { setAttributes({ playBtnSize: v }); } })
258 ),
259 el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false },
260 cc('accentColor', __('Accent', 'blockenberg'), 'accentColor'),
261 cc('sectionTitleColor', __('Section title', 'blockenberg'), 'sectionTitleColor'),
262 cc('titleColor', __('Card title', 'blockenberg'), 'titleColor'),
263 cc('descColor', __('Description', 'blockenberg'), 'descColor'),
264 cc('categoryColor', __('Category text', 'blockenberg'), 'categoryColor'),
265 cc('cardBg', __('Card bg', 'blockenberg'), 'cardBg'),
266 cc('cardBorder', __('Card border', 'blockenberg'), 'cardBorder'),
267 cc('playBtnBg', __('Play btn bg', 'blockenberg'), 'playBtnBg'),
268 cc('playBtnColor', __('Play btn icon', 'blockenberg'), 'playBtnColor'),
269 cc('durationBg', __('Duration badge bg', 'blockenberg'), 'durationBg'),
270 cc('durationColor', __('Duration text', 'blockenberg'), 'durationColor'),
271 cc('filterActiveBg', __('Filter active bg', 'blockenberg'), 'filterActiveBg'),
272 cc('filterActiveColor', __('Filter active text','blockenberg'), 'filterActiveColor'),
273 cc('filterInactiveBg', __('Filter inactive bg','blockenberg'), 'filterInactiveBg'),
274 cc('filterInactiveColor', __('Filter inactive', 'blockenberg'), 'filterInactiveColor'),
275 cc('bgColor', __('Section bg', 'blockenberg'), 'bgColor')
276 ),
277 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
278 el(RangeControl, { label: __('Padding top', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
279 el(RangeControl, { label: __('Padding bottom', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
280 )
281 ),
282
283 el('div', blockProps,
284 /* Section title */
285 (a.title || a.subtitle) && el('div', { className: 'bkbg-vg-section-hdr', style: { textAlign: 'center', marginBottom: '28px' } },
286 el(RichText, { tagName: 'h2', className: 'bkbg-vg-section-title', value: a.title, onChange: function (v) { setAttributes({ title: v }); }, placeholder: __('Grid title…', 'blockenberg'), style: { color: a.sectionTitleColor, margin: '0 0 8px' } }),
287 el(RichText, { tagName: 'p', className: 'bkbg-vg-section-sub', value: a.subtitle, onChange: function (v) { setAttributes({ subtitle: v }); }, placeholder: __('Subtitle…', 'blockenberg'), style: { color: a.descColor, margin: 0 } })
288 ),
289 /* Filter bar preview */
290 a.showFilter && categories.length > 0 && el('div', { className: 'bkbg-vg-filter-bar', style: { display: 'flex', flexWrap: 'wrap', gap: '8px', marginBottom: '24px' } },
291 el('button', { type: 'button', className: 'bkbg-vg-filter-btn is-active', style: { padding: '7px 18px', borderRadius: '99px', border: 'none', background: a.filterActiveBg, color: a.filterActiveColor, fontSize: '13px', fontWeight: 700, cursor: 'pointer' } }, __('All', 'blockenberg')),
292 categories.map(function (cat) {
293 return el('button', { key: cat, type: 'button', className: 'bkbg-vg-filter-btn', style: { padding: '7px 18px', borderRadius: '99px', border: 'none', background: a.filterInactiveBg, color: a.filterInactiveColor, fontSize: '13px', fontWeight: 600, cursor: 'pointer' } }, cat);
294 })
295 ),
296 /* Grid */
297 el('div', { className: 'bkbg-vg-grid', style: { display: 'grid', gridTemplateColumns: 'repeat(' + a.columns + ', 1fr)', gap: a.gap + 'px' } },
298 a.videos.map(function (video) {
299 return el(VideoCard, { key: video.id, video: video, a: a });
300 }),
301 a.videos.length === 0 && el('div', { style: { gridColumn: '1/-1', textAlign: 'center', padding: '48px', color: '#aaa', background: '#fafafa', borderRadius: '8px', border: '2px dashed #ddd' } },
302 el('span', { style: { fontSize: '32px', display: 'block', marginBottom: '10px' } }, '🎬'),
303 el('p', { style: { margin: 0, fontWeight: 700 } }, __('Add your first video →', 'blockenberg'))
304 )
305 )
306 )
307 );
308 },
309
310 save: function (props) {
311 var a = props.attributes;
312 var categories = a.videos.reduce(function (acc, v) {
313 if (v.category && acc.indexOf(v.category) === -1) acc.push(v.category);
314 return acc;
315 }, []);
316
317 return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-vg-wrapper', style: buildWrapStyle(a) }),
318 (a.title || a.subtitle) && el('div', { className: 'bkbg-vg-section-hdr' },
319 el(RichText.Content, { tagName: 'h2', className: 'bkbg-vg-section-title', value: a.title }),
320 el(RichText.Content, { tagName: 'p', className: 'bkbg-vg-section-sub', value: a.subtitle })
321 ),
322 a.showFilter && categories.length > 0 && el('div', { className: 'bkbg-vg-filter-bar' },
323 el('button', { type: 'button', className: 'bkbg-vg-filter-btn is-active', 'data-category': '' }, __('All', 'blockenberg')),
324 categories.map(function (cat) {
325 return el('button', { key: cat, type: 'button', className: 'bkbg-vg-filter-btn', 'data-category': cat }, cat);
326 })
327 ),
328 el('div', { className: 'bkbg-vg-grid', style: { '--bkbg-vg-cols': a.columns, gap: a.gap + 'px' } },
329 a.videos.map(function (video) {
330 var thumbUrl = getThumbUrl(video);
331 var ytId = getYoutubeId(video.url);
332 var embedUrl = ytId ? 'https://www.youtube.com/embed/' + ytId + '?autoplay=1' : video.url;
333 return el('div', { key: video.id, className: 'bkbg-vg-card', 'data-embed-url': embedUrl, 'data-category': video.category || '' },
334 el('div', { className: 'bkbg-vg-thumb-wrap' },
335 thumbUrl
336 ? el('img', { src: thumbUrl, alt: video.title, loading: 'lazy', className: 'bkbg-vg-thumb' })
337 : el('div', { className: 'bkbg-vg-thumb-placeholder' }),
338 el('button', { type: 'button', className: 'bkbg-vg-play-btn', 'aria-label': __('Play video', 'blockenberg') },
339 el('span', { className: 'bkbg-vg-play-icon', 'aria-hidden': 'true' }, '')
340 ),
341 a.showDuration && video.duration && el('div', { className: 'bkbg-vg-duration' }, video.duration),
342 a.showCategory && video.category && el('div', { className: 'bkbg-vg-cat-pill' }, video.category)
343 ),
344 el('div', { className: 'bkbg-vg-card-body' },
345 el('p', { className: 'bkbg-vg-card-title' }, video.title),
346 a.showDescription && video.description && el('p', { className: 'bkbg-vg-desc' }, video.description)
347 )
348 );
349 })
350 ),
351 /* Lightbox modal */
352 el('div', { className: 'bkbg-vg-modal', role: 'dialog', 'aria-modal': 'true', 'aria-label': __('Video player', 'blockenberg'), hidden: true },
353 el('div', { className: 'bkbg-vg-modal-overlay' }),
354 el('div', { className: 'bkbg-vg-modal-content' },
355 el('button', { type: 'button', className: 'bkbg-vg-modal-close', 'aria-label': __('Close', 'blockenberg') }, ''),
356 el('div', { className: 'bkbg-vg-modal-iframe-wrap' })
357 )
358 )
359 );
360 }
361 });
362 }() );
363