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

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

316 lines 21.0 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 RichText = wp.blockEditor.RichText;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var MediaUpload = wp.blockEditor.MediaUpload;
11 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
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 SelectControl = wp.components.SelectControl;
17 var TextControl = wp.components.TextControl;
18 var ColorPicker = wp.components.ColorPicker;
19 var Popover = wp.components.Popover;
20
21 var _tc, _tvf;
22 Object.defineProperty(window, '_tc', { get: function () { return _tc || (_tc = window.bkbgTypographyControl); } });
23 Object.defineProperty(window, '_tvf', { get: function () { return _tvf || (_tvf = window.bkbgTypoCssVars); } });
24 function getTypoControl(label, key, attrs, setA) { return _tc(label, key, attrs, setA); }
25 function getTypoCssVars(attrs) {
26 var v = {};
27 _tvf(v, 'titleTypo', attrs, '--bkvf-tt-');
28 _tvf(v, 'subtitleTypo', attrs, '--bkvf-st-');
29 _tvf(v, 'captionTypo', attrs, '--bkvf-cp-');
30 return v;
31 }
32
33 var ASPECT_RATIOS = {
34 '16-9': 56.25,
35 '4-3': 75,
36 '21-9': 42.86,
37 '1-1': 100,
38 };
39
40 /* ── Helpers ──────────────────────────────────────────────────── */
41 function extractVideoInfo(url) {
42 url = (url || '').trim();
43 if (!url) return { provider: 'youtube', id: '' };
44
45 /* YouTube */
46 var ytMatch = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)([A-Za-z0-9_-]{11})/);
47 if (ytMatch) return { provider: 'youtube', id: ytMatch[1] };
48
49 /* Vimeo */
50 var vmMatch = url.match(/vimeo\.com\/(?:video\/)?(\d+)/);
51 if (vmMatch) return { provider: 'vimeo', id: vmMatch[1] };
52
53 return { provider: 'youtube', id: '' };
54 }
55
56 function getAutoThumb(provider, videoId) {
57 if (provider === 'youtube' && videoId) {
58 return 'https://img.youtube.com/vi/' + videoId + '/maxresdefault.jpg';
59 }
60 return '';
61 }
62
63 function hexToRgba(hex, alpha) {
64 hex = (hex || '#000000').replace('#', '');
65 if (hex.length === 3) hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
66 var r = parseInt(hex.substr(0,2),16), g = parseInt(hex.substr(2,2),16), b = parseInt(hex.substr(4,2),16);
67 return 'rgba('+r+','+g+','+b+','+(alpha/100)+')';
68 }
69
70 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
71 var isOpen = openKey === key;
72 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
73 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
74 el('div', { style: { position: 'relative', flexShrink: 0 } },
75 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' } }),
76 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
77 el('div', { style: { padding: '8px' } },
78 el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange })
79 )
80 )
81 )
82 );
83 }
84
85 /* ── Play icon SVG ────────────────────────────────────────────── */
86 function PlayIcon(props) {
87 var size = props.size || 72;
88 var color = props.color || '#fff';
89 var bg = props.bg || '#6c3fb5';
90 var style = props.style || 'circle';
91 var pulsing = props.pulsing;
92
93 var inner = el('svg', { xmlns: 'http://www.w3.org/2000/svg', width: size * 0.45, height: size * 0.45, viewBox: '0 0 24 24', fill: color },
94 el('path', { d: 'M8 5v14l11-7z' })
95 );
96
97 if (style === 'minimal') {
98 return el('div', { style: { width: size + 'px', height: size + 'px', display: 'flex', alignItems: 'center', justifyContent: 'center', border: '3px solid ' + color, borderRadius: '50%', cursor: 'pointer' } }, inner);
99 }
100 if (style === 'oval') {
101 return el('div', { style: { padding: '14px 24px', display: 'flex', alignItems: 'center', gap: '10px', background: bg, borderRadius: '99px', cursor: 'pointer' } },
102 inner,
103 el('span', { style: { color: color, fontWeight: 700, fontSize: '16px', letterSpacing: '0.02em' } }, __('Watch', 'blockenberg'))
104 );
105 }
106 /* circle (default) */
107 return el('div', {
108 style: {
109 width: size + 'px', height: size + 'px',
110 borderRadius: '50%',
111 background: bg,
112 display: 'flex', alignItems: 'center', justifyContent: 'center',
113 cursor: 'pointer',
114 boxShadow: '0 8px 32px rgba(0,0,0,0.25)',
115 animation: pulsing ? 'bkbg-vf-pulse 2s ease-in-out infinite' : 'none',
116 }
117 }, inner);
118 }
119
120 /* ── Editor preview ───────────────────────────────────────────── */
121 function VideoPreview(props) {
122 var a = props.a;
123 var thumbSrc = a.thumbnailUrl || (a.autoThumb ? getAutoThumb(a.videoProvider, a.videoId) : '');
124 var ratio = ASPECT_RATIOS[a.aspectRatio] || 56.25;
125
126 return el('div', {
127 style: {
128 position: 'relative',
129 width: '100%',
130 paddingBottom: ratio + '%',
131 borderRadius: a.borderRadius + 'px',
132 overflow: 'hidden',
133 boxShadow: a.showShadow ? '0 12px 48px rgba(0,0,0,0.18)' : 'none',
134 background: '#111',
135 cursor: 'pointer',
136 }
137 },
138 /* Thumbnail */
139 thumbSrc && el('img', {
140 src: thumbSrc, alt: '',
141 style: { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }
142 }),
143 !thumbSrc && el('div', { style: { position: 'absolute', inset: 0, background: '#1e1e2e', display: 'flex', alignItems: 'center', justifyContent: 'center' } },
144 el('span', { style: { color: '#6b7280', fontSize: '14px', fontWeight: 500 } }, a.videoId ? '⏳ Thumbnail loading...' : '🎬 ' + __('Enter a YouTube or Vimeo URL in the panel →', 'blockenberg'))
145 ),
146
147 /* Overlay */
148 el('div', { style: { position: 'absolute', inset: 0, background: hexToRgba(a.overlayColor, a.overlayOpacity) } }),
149
150 /* Title / subtitle overlay */
151 (a.showTitle || a.showSubtitle) && el('div', { style: { position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-end', padding: '32px 24px', textAlign: 'center' } },
152 a.showTitle && el('p', { className: 'bkbg-vf-title', style: { margin: 0, color: a.titleColor, textShadow: '0 2px 8px rgba(0,0,0,0.4)' } }, a.title || __('Video Title', 'blockenberg')),
153 a.showSubtitle && el('p', { className: 'bkbg-vf-subtitle', style: { margin: '6px 0 0', color: a.subtitleColor, textShadow: '0 1px 4px rgba(0,0,0,0.3)' } }, a.subtitle || __('Subtitle text', 'blockenberg'))
154 ),
155
156 /* Play button centered */
157 el('div', { style: { position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' } },
158 el(PlayIcon, { size: a.playSize, color: a.playColor, bg: a.playBg, style: a.playStyle, pulsing: a.playPulsing })
159 )
160 );
161 }
162
163 registerBlockType('blockenberg/video-facade', {
164 title: __('Video Facade', 'blockenberg'),
165 icon: 'video-alt3',
166 category: 'bkbg-media',
167
168 edit: function (props) {
169 var a = props.attributes;
170 var setAttributes = props.setAttributes;
171
172 var openColorKeyState = useState(null);
173 var openColorKey = openColorKeyState[0];
174 var setOpenColorKey = openColorKeyState[1];
175
176 var blockProps = useBlockProps((function () {
177 var s = getTypoCssVars(a);
178 s.backgroundColor = a.bgColor || undefined;
179 s.paddingTop = a.paddingTop + 'px';
180 s.paddingBottom = a.paddingBottom + 'px';
181 return { style: s };
182 })());
183
184 function cc(key, label, value, attrKey) {
185 return renderColorControl(key, label, value, function (v) {
186 var upd = {}; upd[attrKey] = v; setAttributes(upd);
187 }, openColorKey, setOpenColorKey);
188 }
189
190 function handleUrlChange(url) {
191 var info = extractVideoInfo(url);
192 setAttributes({ videoUrl: url, videoProvider: info.provider, videoId: info.id });
193 }
194
195 return el(Fragment, null,
196 el(InspectorControls, null,
197 el(PanelBody, { title: __('Video', 'blockenberg'), initialOpen: true },
198 el(TextControl, { label: __('YouTube or Vimeo URL', 'blockenberg'), value: a.videoUrl, onChange: handleUrlChange, placeholder: 'https://youtube.com/watch?v=...' }),
199 a.videoProvider && a.videoId && el('p', { style: { fontSize: '12px', color: '#888', margin: '0 0 8px', background: '#f0f4ff', padding: '4px 8px', borderRadius: '4px' } },
200 '�
201 ' + a.videoProvider.charAt(0).toUpperCase() + a.videoProvider.slice(1) + ' ID: ' + a.videoId
202 ),
203 el(SelectControl, { label: __('Aspect ratio', 'blockenberg'), value: a.aspectRatio, options: [{ label: '16:9 (Widescreen)', value: '16-9' }, { label: '4:3 (Classic)', value: '4-3' }, { label: '21:9 (Cinematic)', value: '21-9' }, { label: '1:1 (Square)', value: '1-1' }], onChange: function (v) { setAttributes({ aspectRatio: v }); } }),
204 el(ToggleControl, { label: __('Auto-load thumbnail from provider', 'blockenberg'), checked: a.autoThumb, onChange: function (v) { setAttributes({ autoThumb: v }); }, __nextHasNoMarginBottom: true }),
205 el('p', { style: { fontSize: '12px', color: '#888', margin: '4px 0 12px' } }, __('Or upload a custom thumbnail below:', 'blockenberg')),
206 el(MediaUploadCheck, null,
207 el(MediaUpload, { onSelect: function (m) { setAttributes({ thumbnailUrl: m.url, thumbnailId: m.id }); }, allowedTypes: ['image'], value: a.thumbnailId,
208 render: function (mp) {
209 return el(Fragment, null,
210 a.thumbnailUrl && el('img', { src: a.thumbnailUrl, style: { width: '100%', borderRadius: '6px', marginBottom: '6px', display: 'block' } }),
211 el(Button, { variant: 'secondary', size: 'compact', onClick: mp.open }, a.thumbnailUrl ? __('Change thumbnail', 'blockenberg') : __('Upload thumbnail', 'blockenberg')),
212 a.thumbnailUrl && el(Button, { variant: 'tertiary', size: 'compact', isDestructive: true, onClick: function () { setAttributes({ thumbnailUrl: '', thumbnailId: 0 }); }, style: { marginLeft: '6px' } }, __('Remove', 'blockenberg'))
213 );
214 }
215 })
216 )
217 ),
218 el(PanelBody, { title: __('Overlay & Play Button', 'blockenberg'), initialOpen: false },
219 RangeControl && el(RangeControl, { label: __('Overlay opacity (%)', 'blockenberg'), value: a.overlayOpacity, min: 0, max: 85, onChange: function (v) { setAttributes({ overlayOpacity: v }); } }),
220 cc('overlayColor', __('Overlay color', 'blockenberg'), a.overlayColor, 'overlayColor'),
221 el(SelectControl, { label: __('Play button style', 'blockenberg'), value: a.playStyle, options: [{ label: __('Circle', 'blockenberg'), value: 'circle' }, { label: __('Oval with text', 'blockenberg'), value: 'oval' }, { label: __('Minimal outline', 'blockenberg'), value: 'minimal' }], onChange: function (v) { setAttributes({ playStyle: v }); } }),
222 el(RangeControl, { label: __('Play button size (px)', 'blockenberg'), value: a.playSize, min: 40, max: 140, onChange: function (v) { setAttributes({ playSize: v }); } }),
223 cc('playBg', __('Play button background', 'blockenberg'), a.playBg, 'playBg'),
224 cc('playColor', __('Play icon color', 'blockenberg'), a.playColor, 'playColor'),
225 el(ToggleControl, { label: __('Pulsing animation', 'blockenberg'), checked: a.playPulsing, onChange: function (v) { setAttributes({ playPulsing: v }); }, __nextHasNoMarginBottom: true })
226 ),
227 el(PanelBody, { title: __('Overlay Text', 'blockenberg'), initialOpen: false },
228 el(ToggleControl, { label: __('Show title', 'blockenberg'), checked: a.showTitle, onChange: function (v) { setAttributes({ showTitle: v }); }, __nextHasNoMarginBottom: true }),
229 a.showTitle && el(TextControl, { label: __('Title', 'blockenberg'), value: a.title, onChange: function (v) { setAttributes({ title: v }); } }),
230 el(ToggleControl, { label: __('Show subtitle', 'blockenberg'), checked: a.showSubtitle, onChange: function (v) { setAttributes({ showSubtitle: v }); }, __nextHasNoMarginBottom: true }),
231 a.showSubtitle && el(TextControl, { label: __('Subtitle', 'blockenberg'), value: a.subtitle, onChange: function (v) { setAttributes({ subtitle: v }); } }),
232 cc('titleColor', __('Title color', 'blockenberg'), a.titleColor, 'titleColor'),
233 cc('subtitleColor', __('Subtitle color', 'blockenberg'), a.subtitleColor, 'subtitleColor')
234 ),
235 el(PanelBody, { title: __('Caption', 'blockenberg'), initialOpen: false },
236 el(ToggleControl, { label: __('Show caption', 'blockenberg'), checked: a.showCaption, onChange: function (v) { setAttributes({ showCaption: v }); }, __nextHasNoMarginBottom: true }),
237 a.showCaption && el(TextControl, { label: __('Caption text', 'blockenberg'), value: a.caption, onChange: function (v) { setAttributes({ caption: v }); } }),
238 a.showCaption && cc('captionColor', __('Caption color', 'blockenberg'), a.captionColor, 'captionColor')
239 ),
240 el(PanelBody, { title: __('Card Style', 'blockenberg'), initialOpen: false },
241 el(RangeControl, { label: __('Border radius (px)', 'blockenberg'), value: a.borderRadius, min: 0, max: 40, onChange: function (v) { setAttributes({ borderRadius: v }); } }),
242 el(ToggleControl, { label: __('Show shadow', 'blockenberg'), checked: a.showShadow, onChange: function (v) { setAttributes({ showShadow: v }); }, __nextHasNoMarginBottom: true }),
243 cc('bgColor', __('Section background', 'blockenberg'), a.bgColor, 'bgColor')
244 ),
245 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
246 el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
247 el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
248 ),
249 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
250 getTypoControl(__('Title', 'blockenberg'), 'titleTypo', a, setAttributes),
251 getTypoControl(__('Subtitle', 'blockenberg'), 'subtitleTypo', a, setAttributes),
252 getTypoControl(__('Caption', 'blockenberg'), 'captionTypo', a, setAttributes)
253 )
254 ),
255
256 el('div', blockProps,
257 el(VideoPreview, { a: a }),
258 a.showCaption && a.caption && el('p', { className: 'bkbg-vf-caption', style: { marginTop: '10px', color: a.captionColor, textAlign: 'center' } }, a.caption)
259 )
260 );
261 },
262
263 save: function (props) {
264 var a = props.attributes;
265 var thumbSrc = a.thumbnailUrl || (a.autoThumb ? getAutoThumb(a.videoProvider, a.videoId) : '');
266 var ratio = ASPECT_RATIOS[a.aspectRatio] || 56.25;
267
268 return el('div', wp.blockEditor.useBlockProps.save((function () {
269 var _tv = getTypoCssVars(a);
270 _tv.backgroundColor = a.bgColor || undefined;
271 _tv.paddingTop = a.paddingTop + 'px';
272 _tv.paddingBottom = a.paddingBottom + 'px';
273 return { className: 'bkbg-vf-wrapper', style: _tv };
274 })()),
275 el('div', {
276 className: 'bkbg-vf-facade',
277 'data-provider': a.videoProvider,
278 'data-vid': a.videoId,
279 'data-pulsing': a.playPulsing ? '1' : '0',
280 style: {
281 position: 'relative', width: '100%',
282 paddingBottom: ratio + '%',
283 borderRadius: a.borderRadius + 'px',
284 overflow: 'hidden',
285 boxShadow: a.showShadow ? '0 12px 48px rgba(0,0,0,0.18)' : 'none',
286 background: '#111',
287 cursor: 'pointer',
288 }
289 },
290 thumbSrc && el('img', {
291 className: 'bkbg-vf-thumb', src: thumbSrc, alt: a.title || '',
292 loading: 'lazy',
293 style: { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', display: 'block' }
294 }),
295 el('div', { className: 'bkbg-vf-overlay', style: { position: 'absolute', inset: 0, background: hexToRgba(a.overlayColor, a.overlayOpacity) } }),
296 (a.showTitle || a.showSubtitle) && el('div', { className: 'bkbg-vf-text', style: { position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-end', padding: '32px 24px', textAlign: 'center', pointerEvents: 'none' } },
297 a.showTitle && a.title && el('p', { className: 'bkbg-vf-title', style: { margin: 0, color: a.titleColor } }, a.title),
298 a.showSubtitle && a.subtitle && el('p', { className: 'bkbg-vf-subtitle', style: { margin: '6px 0 0', color: a.subtitleColor } }, a.subtitle)
299 ),
300 el('div', { className: 'bkbg-vf-play', style: { position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', pointerEvents: 'none' } },
301 a.playStyle === 'oval'
302 ? el('div', { style: { padding: '14px 24px', display: 'flex', alignItems: 'center', gap: '10px', background: a.playBg, borderRadius: '99px' } },
303 el('svg', { xmlns: 'http://www.w3.org/2000/svg', width: a.playSize * 0.45, height: a.playSize * 0.45, viewBox: '0 0 24 24', fill: a.playColor }, el('path', { d: 'M8 5v14l11-7z' })),
304 el('span', { style: { color: a.playColor, fontWeight: 700, fontSize: '16px' } }, 'Watch')
305 )
306 : el('div', { style: { width: a.playSize + 'px', height: a.playSize + 'px', borderRadius: a.playStyle === 'minimal' ? '50%' : '50%', background: a.playStyle === 'minimal' ? 'transparent' : a.playBg, border: a.playStyle === 'minimal' ? '3px solid ' + a.playColor : 'none', display: 'flex', alignItems: 'center', justifyContent: 'center' } },
307 el('svg', { xmlns: 'http://www.w3.org/2000/svg', width: a.playSize * 0.45, height: a.playSize * 0.45, viewBox: '0 0 24 24', fill: a.playColor }, el('path', { d: 'M8 5v14l11-7z' }))
308 )
309 )
310 ),
311 a.showCaption && a.caption && el('p', { className: 'bkbg-vf-caption', style: { marginTop: '10px', color: a.captionColor, textAlign: 'center' } }, a.caption)
312 );
313 }
314 });
315 }() );
316