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

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

489 lines 28.6 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 RichText = wp.blockEditor.RichText;
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 /* ── Typography lazy getters ───────────────────────────────────────────── */
22 var _Typo, _tv;
23 Object.defineProperty(window, '__bkbgApTypoReady', { get: function () {
24 if (!_Typo) _Typo = window.bkbgTypographyControl;
25 if (!_tv) _tv = window.bkbgTypoCssVars;
26 return !!(_Typo && _tv);
27 }});
28
29 function getTypoCssVars() { window.__bkbgApTypoReady; return _tv; }
30 function getTypoComponent() { window.__bkbgApTypoReady; return _Typo; }
31
32 // ── CSS vars ──────────────────────────────────────────────────────────────
33 function buildWrapStyle(a) {
34 var tv = getTypoCssVars();
35 var shadow = a.boxShadow === 'sm' ? '0 1px 6px rgba(0,0,0,0.08)' :
36 a.boxShadow === 'md' ? '0 4px 20px rgba(0,0,0,0.12)' :
37 a.boxShadow === 'lg' ? '0 12px 48px rgba(0,0,0,0.16)' : 'none';
38 var s = {
39 '--bkbg-ap-accent' : a.accentColor,
40 '--bkbg-ap-progress-bg' : a.progressBg,
41 '--bkbg-ap-bg' : a.bgColor,
42 '--bkbg-ap-text-color' : a.textColor,
43 '--bkbg-ap-subtitle-color': a.subtitleColor,
44 '--bkbg-ap-icon-color' : a.iconColor,
45 '--bkbg-ap-icon-bg' : a.iconBg,
46 '--bkbg-ap-cover-radius' : a.coverRadius + 'px',
47 '--bkbg-ap-cover-size' : a.coverSize + 'px',
48 '--bkbg-ap-radius' : a.playerRadius + 'px',
49 '--bkbg-ap-pad' : a.playerPaddingV + 'px ' + a.playerPaddingH + 'px',
50 '--bkbg-ap-shadow' : shadow,
51 '--bkbg-ap-title-size' : a.titleSize + 'px',
52 '--bkbg-ap-title-weight' : a.titleWeight,
53 '--bkbg-ap-artist-size' : a.artistSize + 'px',
54 '--bkbg-ap-btn-size' : a.playButtonSize + 'px',
55 '--bkbg-ap-progress-h' : a.progressHeight + 'px',
56 '--bkbg-ap-max-width' : a.maxWidth + 'px'
57 };
58 if (tv) {
59 Object.assign(s, tv(a.titleTypo || {}, '--bkbg-ap-title-'));
60 Object.assign(s, tv(a.artistTypo || {}, '--bkbg-ap-artist-'));
61 }
62 return s;
63 }
64
65 // ── Color swatch ──────────────────────────────────────────────────────────
66 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
67 var isOpen = openKey === key;
68 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
69 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
70 el('div', { style: { position: 'relative', flexShrink: 0 } },
71 el('button', {
72 type: 'button', title: value || 'none',
73 onClick: function () { setOpenKey(isOpen ? null : key); },
74 style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#fff' }
75 }),
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 / Pause icons ────────────────────────────────────────────────────
86 var PlayIcon = el('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'currentColor', width: '22', height: '22' },
87 el('path', { d: 'M8 5v14l11-7z' })
88 );
89
90 var MusicIcon = el('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'currentColor', width: '40', height: '40' },
91 el('path', { d: 'M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z', opacity: '0.6' })
92 );
93
94 // ── Register ──────────────────────────────────────────────────────────────
95 registerBlockType('blockenberg/audio-player', {
96 title: __('Audio Player', 'blockenberg'),
97 icon: 'controls-play',
98 category: 'bkbg-media',
99 description: __('Custom-styled audio player with cover art and track info.', 'blockenberg'),
100
101 edit: function (props) {
102 var a = props.attributes;
103 var setAttributes = props.setAttributes;
104
105 var openColorKeyState = useState(null);
106 var openColorKey = openColorKeyState[0];
107 var setOpenColorKey = openColorKeyState[1];
108
109 function cc(key, label, attrKey) {
110 return renderColorControl(key, label, a[attrKey], function (val) {
111 var upd = {}; upd[attrKey] = val; setAttributes(upd);
112 }, openColorKey, setOpenColorKey);
113 }
114
115 var blockProps = useBlockProps({
116 className: 'bkbg-ap-wrapper bkbg-ap-style-' + a.playerStyle,
117 style: buildWrapStyle(a)
118 });
119
120 // ── Inspector ─────────────────────────────────────────────────────
121 var inspector = el(InspectorControls, {},
122 // Audio File
123 el(PanelBody, { title: __('Audio File', 'blockenberg'), initialOpen: true },
124 el(TextControl, {
125 label: __('Audio URL (mp3/ogg/wav)', 'blockenberg'),
126 value: a.audioUrl, type: 'url', placeholder: 'https://example.com/audio.mp3',
127 onChange: function (v) { setAttributes({ audioUrl: v }); }
128 }),
129 el(MediaUploadCheck, {},
130 el(MediaUpload, {
131 onSelect: function (media) {
132 setAttributes({ audioUrl: media.url, audioType: media.mime || 'audio/mpeg' });
133 },
134 type: 'audio',
135 value: a.audioUrl,
136 render: function (ref) {
137 return el(Button, { variant: 'secondary', onClick: ref.open, style: { width: '100%', justifyContent: 'center', marginTop: '8px' } },
138 a.audioUrl ? __('Replace Audio', 'blockenberg') : __('Select Audio from Library', 'blockenberg')
139 );
140 }
141 })
142 ),
143 el(SelectControl, {
144 label: __('Preload', 'blockenberg'), value: a.preload,
145 options: [
146 { label: __('Metadata (recommended)', 'blockenberg'), value: 'metadata' },
147 { label: __('Auto (load fully)', 'blockenberg'), value: 'auto' },
148 { label: __('None (on demand)', 'blockenberg'), value: 'none' }
149 ],
150 onChange: function (v) { setAttributes({ preload: v }); }
151 }),
152 el(ToggleControl, {
153 label: __('Autoplay', 'blockenberg'), checked: a.autoplay,
154 onChange: function (v) { setAttributes({ autoplay: v }); }
155 }),
156 el(ToggleControl, {
157 label: __('Loop', 'blockenberg'), checked: a.loop,
158 onChange: function (v) { setAttributes({ loop: v }); }
159 })
160 ),
161
162 // Track Info
163 el(PanelBody, { title: __('Track Info', 'blockenberg'), initialOpen: false },
164 el(TextControl, {
165 label: __('Track Title', 'blockenberg'), value: a.audioTitle,
166 onChange: function (v) { setAttributes({ audioTitle: v }); }
167 }),
168 el(TextControl, {
169 label: __('Artist Name', 'blockenberg'), value: a.audioArtist,
170 onChange: function (v) { setAttributes({ audioArtist: v }); }
171 }),
172 el(TextControl, {
173 label: __('Album', 'blockenberg'), value: a.audioAlbum,
174 onChange: function (v) { setAttributes({ audioAlbum: v }); }
175 }),
176 el(ToggleControl, {
177 label: __('Show Title', 'blockenberg'), checked: a.showTitle,
178 onChange: function (v) { setAttributes({ showTitle: v }); }
179 }),
180 el(ToggleControl, {
181 label: __('Show Artist', 'blockenberg'), checked: a.showArtist,
182 onChange: function (v) { setAttributes({ showArtist: v }); }
183 }),
184 el(ToggleControl, {
185 label: __('Show Album', 'blockenberg'), checked: a.showAlbum,
186 onChange: function (v) { setAttributes({ showAlbum: v }); }
187 })
188 ),
189
190 // Cover Art
191 el(PanelBody, { title: __('Cover Art', 'blockenberg'), initialOpen: false },
192 el(ToggleControl, {
193 label: __('Show Cover Art', 'blockenberg'), checked: a.showCover,
194 onChange: function (v) { setAttributes({ showCover: v }); }
195 }),
196 a.showCover && el(Fragment, {},
197 el(TextControl, {
198 label: __('Cover Image URL', 'blockenberg'),
199 value: a.coverUrl, type: 'url', placeholder: 'https://example.com/cover.jpg',
200 onChange: function (v) { setAttributes({ coverUrl: v }); }
201 }),
202 el(MediaUploadCheck, {},
203 el(MediaUpload, {
204 onSelect: function (media) { setAttributes({ coverUrl: media.url, coverId: media.id }); },
205 type: 'image',
206 value: a.coverId,
207 render: function (ref) {
208 return el(Button, { variant: 'secondary', onClick: ref.open, style: { width: '100%', justifyContent: 'center', marginTop: '8px' } },
209 a.coverUrl ? __('Replace Cover', 'blockenberg') : __('Select Cover Image', 'blockenberg')
210 );
211 }
212 })
213 ),
214 el(RangeControl, {
215 label: __('Cover Size (px)', 'blockenberg'), value: a.coverSize, min: 40, max: 200,
216 onChange: function (v) { setAttributes({ coverSize: v }); }
217 }),
218 el(RangeControl, {
219 label: __('Cover Border Radius (px)', 'blockenberg'), value: a.coverRadius, min: 0, max: 50,
220 onChange: function (v) { setAttributes({ coverRadius: v }); }
221 })
222 )
223 ),
224
225 // Controls
226 el(PanelBody, { title: __('Controls', 'blockenberg'), initialOpen: false },
227 el(ToggleControl, {
228 label: __('Show Timestamp', 'blockenberg'), checked: a.showTimestamp,
229 onChange: function (v) { setAttributes({ showTimestamp: v }); }
230 }),
231 el(ToggleControl, {
232 label: __('Show Volume Control', 'blockenberg'), checked: a.showVolume,
233 onChange: function (v) { setAttributes({ showVolume: v }); }
234 }),
235 el(ToggleControl, {
236 label: __('Show Playback Speed', 'blockenberg'), checked: a.showSpeed,
237 onChange: function (v) { setAttributes({ showSpeed: v }); }
238 }),
239 el(ToggleControl, {
240 label: __('Show Download Button', 'blockenberg'), checked: a.showDownload,
241 onChange: function (v) { setAttributes({ showDownload: v }); }
242 }),
243 el(RangeControl, {
244 label: __('Play Button Size (px)', 'blockenberg'), value: a.playButtonSize, min: 32, max: 80,
245 onChange: function (v) { setAttributes({ playButtonSize: v }); }
246 }),
247 el(RangeControl, {
248 label: __('Progress Bar Height (px)', 'blockenberg'), value: a.progressHeight, min: 2, max: 12,
249 onChange: function (v) { setAttributes({ progressHeight: v }); }
250 })
251 ),
252
253 // Style
254 el(PanelBody, { title: __('Player Style', 'blockenberg'), initialOpen: false },
255 el(SelectControl, {
256 label: __('Style', 'blockenberg'), value: a.playerStyle,
257 options: [
258 { label: __('Card', 'blockenberg'), value: 'card' },
259 { label: __('Minimal (bar)', 'blockenberg'), value: 'minimal' },
260 { label: __('Compact', 'blockenberg'), value: 'compact' }
261 ],
262 onChange: function (v) { setAttributes({ playerStyle: v }); }
263 }),
264 el(SelectControl, {
265 label: __('Box Shadow', 'blockenberg'), value: a.boxShadow,
266 options: [
267 { label: __('None', 'blockenberg'), value: 'none' },
268 { label: __('Small', 'blockenberg'), value: 'sm' },
269 { label: __('Medium', 'blockenberg'), value: 'md' },
270 { label: __('Large', 'blockenberg'), value: 'lg' }
271 ],
272 onChange: function (v) { setAttributes({ boxShadow: v }); }
273 }),
274 el(RangeControl, {
275 label: __('Player Border Radius (px)', 'blockenberg'), value: a.playerRadius, min: 0, max: 40,
276 onChange: function (v) { setAttributes({ playerRadius: v }); }
277 }),
278 el(RangeControl, {
279 label: __('Vertical Padding (px)', 'blockenberg'), value: a.playerPaddingV, min: 8, max: 60,
280 onChange: function (v) { setAttributes({ playerPaddingV: v }); }
281 }),
282 el(RangeControl, {
283 label: __('Horizontal Padding (px)', 'blockenberg'), value: a.playerPaddingH, min: 8, max: 60,
284 onChange: function (v) { setAttributes({ playerPaddingH: v }); }
285 }),
286 el(RangeControl, {
287 label: __('Max Width (px)', 'blockenberg'), value: a.maxWidth, min: 200, max: 1200,
288 onChange: function (v) { setAttributes({ maxWidth: v }); }
289 })
290 ),
291
292 // Colors
293 el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false },
294 cc('accentColor', __('Accent / Progress Color', 'blockenberg'), 'accentColor'),
295 cc('progressBg', __('Progress Track Background', 'blockenberg'), 'progressBg'),
296 cc('bgColor', __('Player Background', 'blockenberg'), 'bgColor'),
297 cc('textColor', __('Title Color', 'blockenberg'), 'textColor'),
298 cc('subtitleColor', __('Artist / Subtitle Color', 'blockenberg'), 'subtitleColor'),
299 cc('iconColor', __('Play Button Icon Color', 'blockenberg'), 'iconColor'),
300 cc('iconBg', __('Play Button Background', 'blockenberg'), 'iconBg')
301 ),
302
303 // Typography
304 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
305 getTypoComponent() && el(getTypoComponent(), {
306 label: __('Title Typography', 'blockenberg'),
307 value: a.titleTypo || {},
308 onChange: function (v) { setAttributes({ titleTypo: v }); }
309 }),
310 getTypoComponent() && el(getTypoComponent(), {
311 label: __('Artist Typography', 'blockenberg'),
312 value: a.artistTypo || {},
313 onChange: function (v) { setAttributes({ artistTypo: v }); }
314 })
315 )
316 );
317
318 // ── Block preview ─────────────────────────────────────────────────
319 function renderCover() {
320 if (!a.showCover) return null;
321 return el('div', { className: 'bkbg-ap-cover' },
322 a.coverUrl
323 ? el('img', { src: a.coverUrl, alt: a.audioTitle, className: 'bkbg-ap-cover-img' })
324 : el('div', { className: 'bkbg-ap-cover-placeholder' }, MusicIcon)
325 );
326 }
327
328 function renderTrackInfo() {
329 return el('div', { className: 'bkbg-ap-track-info' },
330 a.showTitle && el('div', { className: 'bkbg-ap-title' }, a.audioTitle || __('Track Title', 'blockenberg')),
331 a.showArtist && el('div', { className: 'bkbg-ap-artist' }, a.audioArtist || __('Artist Name', 'blockenberg')),
332 a.showAlbum && a.audioAlbum && el('div', { className: 'bkbg-ap-album' }, a.audioAlbum)
333 );
334 }
335
336 function renderProgressBar() {
337 return el('div', { className: 'bkbg-ap-progress-wrap' },
338 el('div', { className: 'bkbg-ap-progress-track' },
339 el('div', { className: 'bkbg-ap-progress-fill', style: { width: '35%' } }),
340 el('div', { className: 'bkbg-ap-progress-thumb' })
341 ),
342 a.showTimestamp && el('div', { className: 'bkbg-ap-timestamps' },
343 el('span', { className: 'bkbg-ap-current' }, '0:00'),
344 el('span', { className: 'bkbg-ap-duration' }, '0:00')
345 )
346 );
347 }
348
349 function renderPlayBtn() {
350 return el('button', { type: 'button', className: 'bkbg-ap-play-btn', disabled: true }, PlayIcon);
351 }
352
353 var uploadPrompt = !a.audioUrl && el('div', { style: { background: '#f0f7ff', border: '2px dashed #90c4f7', borderRadius: '8px', padding: '20px', textAlign: 'center', color: '#2563eb', marginBottom: '16px', fontSize: '14px' } },
354 el('strong', {}, __('Audio Player', 'blockenberg')),
355 el('br', {}),
356 __('Set the audio URL in the block settings panel →', 'blockenberg')
357 );
358
359 return el(Fragment, {},
360 inspector,
361 el('div', blockProps,
362 uploadPrompt,
363 el('div', { className: 'bkbg-ap-player' },
364 a.playerStyle !== 'minimal'
365 ? el(Fragment, {},
366 el('div', { className: 'bkbg-ap-top' },
367 renderCover(),
368 el('div', { className: 'bkbg-ap-info-col' },
369 renderTrackInfo(),
370 renderProgressBar()
371 )
372 ),
373 el('div', { className: 'bkbg-ap-controls' },
374 renderPlayBtn(),
375 a.showVolume && el('div', { className: 'bkbg-ap-volume' },
376 el('span', { className: 'bkbg-ap-vol-icon' }, '🔉'),
377 el('input', { type: 'range', className: 'bkbg-ap-vol-slider', min: 0, max: 1, step: 0.01, defaultValue: 1, disabled: true })
378 )
379 )
380 )
381 : el(Fragment, {},
382 renderPlayBtn(),
383 el('div', { className: 'bkbg-ap-minimal-info' },
384 a.showTitle && el('span', { className: 'bkbg-ap-title' }, a.audioTitle),
385 renderProgressBar()
386 )
387 )
388 )
389 )
390 );
391 },
392
393 // ── Save ─────────────────────────────────────────────────────────────
394 save: function (props) {
395 var a = props.attributes;
396
397 return el('div', wp.blockEditor.useBlockProps.save({
398 className: 'bkbg-ap-wrapper bkbg-ap-style-' + a.playerStyle,
399 style: buildWrapStyle(a)
400 }),
401 el('div', {
402 className: 'bkbg-ap-player',
403 'data-audio-url': a.audioUrl,
404 'data-audio-type': a.audioType,
405 'data-autoplay': a.autoplay ? '1' : '0',
406 'data-loop': a.loop ? '1' : '0',
407 'data-preload': a.preload,
408 'data-show-volume': a.showVolume ? '1' : '0',
409 'data-show-speed': a.showSpeed ? '1' : '0',
410 'data-show-download': a.showDownload ? '1' : '0',
411 'data-audio-url-download': a.showDownload ? a.audioUrl : ''
412 },
413 a.playerStyle !== 'minimal'
414 ? el(Fragment, {},
415 el('div', { className: 'bkbg-ap-top' },
416 a.showCover && el('div', { className: 'bkbg-ap-cover' },
417 a.coverUrl
418 ? el('img', { src: a.coverUrl, alt: a.audioTitle, className: 'bkbg-ap-cover-img', loading: 'lazy' })
419 : el('div', { className: 'bkbg-ap-cover-placeholder' })
420 ),
421 el('div', { className: 'bkbg-ap-info-col' },
422 el('div', { className: 'bkbg-ap-track-info' },
423 a.showTitle && el('div', { className: 'bkbg-ap-title' }, a.audioTitle),
424 a.showArtist && el('div', { className: 'bkbg-ap-artist' }, a.audioArtist),
425 a.showAlbum && a.audioAlbum && el('div', { className: 'bkbg-ap-album' }, a.audioAlbum)
426 ),
427 el('div', { className: 'bkbg-ap-progress-wrap' },
428 el('div', { className: 'bkbg-ap-progress-track' },
429 el('div', { className: 'bkbg-ap-progress-fill' }),
430 el('div', { className: 'bkbg-ap-progress-thumb' })
431 ),
432 a.showTimestamp && el('div', { className: 'bkbg-ap-timestamps' },
433 el('span', { className: 'bkbg-ap-current' }, '0:00'),
434 el('span', { className: 'bkbg-ap-duration' }, '0:00')
435 )
436 )
437 )
438 ),
439 el('div', { className: 'bkbg-ap-controls' },
440 el('button', { type: 'button', className: 'bkbg-ap-play-btn', 'aria-label': 'Play' },
441 el('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'currentColor', width: '22', height: '22' },
442 el('path', { d: 'M8 5v14l11-7z' })
443 )
444 ),
445 a.showSpeed && el('button', { type: 'button', className: 'bkbg-ap-speed-btn', 'aria-label': 'Playback speed' }, ''),
446 a.showVolume && el('div', { className: 'bkbg-ap-volume' },
447 el('button', { type: 'button', className: 'bkbg-ap-vol-btn', 'aria-label': 'Volume' },
448 el('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'currentColor', width: '18', height: '18' },
449 el('path', { d: 'M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02z' })
450 )
451 ),
452 el('input', { type: 'range', className: 'bkbg-ap-vol-slider', min: '0', max: '1', step: '0.01', defaultValue: '1', 'aria-label': 'Volume' })
453 ),
454 a.showDownload && a.audioUrl && el('a', {
455 href: a.audioUrl, download: '', className: 'bkbg-ap-download-btn',
456 title: __('Download', 'blockenberg'), 'aria-label': __('Download audio', 'blockenberg')
457 },
458 el('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'currentColor', width: '18', height: '18' },
459 el('path', { d: 'M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z' })
460 )
461 )
462 )
463 )
464 : el(Fragment, {},
465 el('button', { type: 'button', className: 'bkbg-ap-play-btn', 'aria-label': 'Play' },
466 el('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'currentColor', width: '22', height: '22' },
467 el('path', { d: 'M8 5v14l11-7z' })
468 )
469 ),
470 el('div', { className: 'bkbg-ap-minimal-info' },
471 a.showTitle && el('span', { className: 'bkbg-ap-title' }, a.audioTitle),
472 el('div', { className: 'bkbg-ap-progress-wrap' },
473 el('div', { className: 'bkbg-ap-progress-track' },
474 el('div', { className: 'bkbg-ap-progress-fill' }),
475 el('div', { className: 'bkbg-ap-progress-thumb' })
476 ),
477 a.showTimestamp && el('div', { className: 'bkbg-ap-timestamps' },
478 el('span', { className: 'bkbg-ap-current' }, '0:00'),
479 el('span', { className: 'bkbg-ap-duration' }, '0:00')
480 )
481 )
482 )
483 )
484 )
485 );
486 }
487 });
488 }() );
489