(function () { 'use strict'; var _typoKeys = { family:'font-family', weight:'font-weight', style:'font-style', decoration:'text-decoration', transform:'text-transform', sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m', lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m', letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m', wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m' }; function typoCssVarsForEl(el, obj, prefix) { if (!obj || typeof obj !== 'object') return; Object.keys(_typoKeys).forEach(function (k) { var v = obj[k]; if (v === undefined || v === '' || v === null) return; if (k === 'sizeDesktop' || k === 'sizeTablet' || k === 'sizeMobile') v = v + (obj.sizeUnit || 'px'); else if (k === 'lineHeightDesktop' || k === 'lineHeightTablet' || k === 'lineHeightMobile') v = v + (obj.lineHeightUnit || ''); else if (k === 'letterSpacingDesktop' || k === 'letterSpacingTablet' || k === 'letterSpacingMobile') v = v + (obj.letterSpacingUnit || 'px'); else if (k === 'wordSpacingDesktop' || k === 'wordSpacingTablet' || k === 'wordSpacingMobile') v = v + (obj.wordSpacingUnit || 'px'); el.style.setProperty(prefix + _typoKeys[k], String(v)); }); } function buildBlock(root) { var o; try { o = JSON.parse(root.getAttribute('data-opts')); } catch (e) { return; } // CSS vars root.style.setProperty('--sw-accent', o.accentColor || '#6366f1'); root.style.setProperty('--sw-clock-bg', o.clockBg || '#1e1b4b'); root.style.setProperty('--sw-clock-color', o.clockColor || '#e0e7ff'); root.style.setProperty('--sw-title-color', o.titleColor || '#111827'); root.style.setProperty('--sw-subtitle-color',o.subtitleColor || '#6b7280'); root.style.setProperty('--sw-label-color', o.labelColor || '#374151'); root.style.setProperty('--sw-card-bg', o.cardBg || '#ffffff'); root.style.setProperty('--sw-max-width', (o.contentMaxWidth||560) + 'px'); root.style.setProperty('--sw-title-size', (o.titleFontSize ||26) + 'px'); root.style.setProperty('--sw-clock-size', (o.clockFontSize ||64) + 'px'); // Typography vars typoCssVarsForEl(root, o.titleTypo, '--bksw-tt-'); typoCssVarsForEl(root, o.subtitleTypo, '--bksw-st-'); // State var elapsed = 0; // ms total elapsed var lapStart = 0; // ms at last lap press var running = false; var rafId = null; var startedAt = 0; // performance.now() snapshot var laps = []; var maxLaps = o.maxLaps || 20; var showMs = o.showMilliseconds !== false; // Build DOM var wrap = document.createElement('div'); wrap.className = 'bkbg-sw-wrap'; wrap.style.background = o.sectionBg || '#f5f3ff'; root.appendChild(wrap); if (o.showTitle && o.title) { var titleEl = document.createElement('h3'); titleEl.className = 'bkbg-sw-title'; titleEl.textContent = o.title; wrap.appendChild(titleEl); } if (o.showSubtitle && o.subtitle) { var subEl = document.createElement('p'); subEl.className = 'bkbg-sw-subtitle'; subEl.textContent = o.subtitle; wrap.appendChild(subEl); } // Clock var clockEl = document.createElement('div'); clockEl.className = 'bkbg-sw-clock'; wrap.appendChild(clockEl); // Buttons var btnRow = document.createElement('div'); btnRow.className = 'bkbg-sw-btns'; wrap.appendChild(btnRow); function makeBtn(label, bg, handler) { var btn = document.createElement('button'); btn.className = 'bkbg-sw-btn'; btn.textContent = label; btn.style.background = bg; btn.addEventListener('click', handler); btnRow.appendChild(btn); return btn; } var startBtn = makeBtn('▶ Start', o.startColor || '#22c55e', onStart); var lapBtn = o.showLaps ? makeBtn('⏱ Lap', o.lapColor || '#f59e0b', onLap) : null; var resetBtn = makeBtn('↺ Reset', o.resetColor || '#6b7280', onReset); // Laps section var lapSection = null, lapHead = null, lapBody = null; if (o.showLaps) { lapSection = document.createElement('div'); lapSection.className = 'bkbg-sw-laps'; lapHead = document.createElement('div'); lapHead.className = 'bkbg-sw-laps-head'; lapHead.innerHTML = '#SplitTotal'; lapSection.appendChild(lapHead); lapBody = document.createElement('div'); lapSection.appendChild(lapBody); wrap.appendChild(lapSection); } // ── Format ms as MM:SS.mm or MM:SS ── function fmtTime(ms, withMs) { var totalS = Math.floor(ms / 1000); var minutes = Math.floor(totalS / 60); var seconds = totalS % 60; var centis = Math.floor((ms % 1000) / 10); var mm = String(minutes).padStart(2, '0'); var ss = String(seconds).padStart(2, '0'); if (withMs !== false) { var cs = String(centis).padStart(2, '0'); return mm + ':' + ss + '.' + cs; } return mm + ':' + ss; } // ── Render clock ── function renderClock() { clockEl.textContent = fmtTime(elapsed, showMs); } // ── RAF loop ── function tick() { elapsed = (o._elapsed || 0) + (performance.now() - startedAt); renderClock(); rafId = requestAnimationFrame(tick); } // ── Start / Pause toggle ── function onStart() { if (!running) { running = true; o._elapsed = elapsed; startedAt = performance.now(); rafId = requestAnimationFrame(tick); startBtn.textContent = '⏸ Pause'; startBtn.style.background = o.stopColor || '#ef4444'; if (lapBtn) lapBtn.disabled = false; } else { running = false; cancelAnimationFrame(rafId); o._elapsed = elapsed; startBtn.textContent = '▶ Resume'; startBtn.style.background = o.startColor || '#22c55e'; } } // ── Lap ── function onLap() { if (!running) return; if (laps.length >= maxLaps) return; var split = elapsed - lapStart; lapStart = elapsed; laps.unshift({ num: laps.length + 1, split: split, total: elapsed }); renderLaps(); } // ── Reset ── function onReset() { running = false; cancelAnimationFrame(rafId); elapsed = 0; lapStart = 0; o._elapsed = 0; laps = []; startBtn.textContent = '▶ Start'; startBtn.style.background = o.startColor || '#22c55e'; if (lapBtn) lapBtn.disabled = true; renderClock(); if (lapBody) renderLaps(); } // ── Render laps list ── function renderLaps() { if (!lapBody) return; lapBody.innerHTML = ''; if (laps.length === 0) { var empty = document.createElement('div'); empty.className = 'bkbg-sw-laps-empty'; empty.textContent = 'No laps recorded yet'; lapBody.appendChild(empty); return; } laps.forEach(function (lap) { var row = document.createElement('div'); row.className = 'bkbg-sw-lap-row'; row.innerHTML = '' + lap.num + '' + '' + fmtTime(lap.split, showMs) + '' + '' + fmtTime(lap.total, showMs) + ''; lapBody.appendChild(row); }); } // Init if (lapBtn) lapBtn.disabled = true; renderClock(); if (lapBody) renderLaps(); } document.querySelectorAll('.bkbg-sw-app').forEach(buildBlock); })();