| 1 |
(function () { |
| 2 |
'use strict'; |
| 3 |
|
| 4 |
function mk(tag, cls, styles) { |
| 5 |
var d = document.createElement(tag); |
| 6 |
if (cls) d.className = cls; |
| 7 |
if (styles) Object.keys(styles).forEach(function (k) { d.style[k] = styles[k]; }); |
| 8 |
return d; |
| 9 |
} |
| 10 |
function mkText(tag, cls, text, styles) { |
| 11 |
var d = mk(tag, cls, styles); |
| 12 |
d.textContent = text; |
| 13 |
return d; |
| 14 |
} |
| 15 |
function hexToRgba(hex, alpha) { |
| 16 |
if (!hex || hex.length < 7) return 'rgba(180,180,180,' + alpha + ')'; |
| 17 |
var r = parseInt(hex.slice(1, 3), 16); |
| 18 |
var g = parseInt(hex.slice(3, 5), 16); |
| 19 |
var b = parseInt(hex.slice(5, 7), 16); |
| 20 |
return 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')'; |
| 21 |
} |
| 22 |
|
| 23 |
function typoCssVarsForEl(typo, prefix, el) { |
| 24 |
if (!typo || typeof typo !== 'object') return; |
| 25 |
var m = { family:'font-family', weight:'font-weight', transform:'text-transform', style:'font-style', decoration:'text-decoration', |
| 26 |
sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m', |
| 27 |
lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m', |
| 28 |
letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m', |
| 29 |
wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m' }; |
| 30 |
Object.keys(m).forEach(function (k) { |
| 31 |
if (typo[k] !== undefined && typo[k] !== '') { |
| 32 |
var v = typo[k], u = typo[k + 'Unit'] || ''; |
| 33 |
if (/Desktop|Tablet|Mobile/.test(k) && typeof v === 'number') v = v + (u || 'px'); |
| 34 |
el.style.setProperty(prefix + m[k], '' + v); |
| 35 |
} |
| 36 |
}); |
| 37 |
} |
| 38 |
|
| 39 |
function buildSide(o, side) { |
| 40 |
var isLeft = side === 'left'; |
| 41 |
var label = isLeft ? o.leftLabel : o.rightLabel; |
| 42 |
var icon = isLeft ? o.leftIcon : o.rightIcon; |
| 43 |
var points = isLeft ? o.leftPoints : o.rightPoints; |
| 44 |
var color = isLeft ? o.leftColor : o.rightColor; |
| 45 |
var bg = isLeft ? o.leftBg : o.rightBg; |
| 46 |
var borderCol = hexToRgba(color, 0.35); |
| 47 |
|
| 48 |
var card = mk('div', 'bkbg-db-side', { |
| 49 |
background: o.style === 'minimal' ? 'transparent' : bg, |
| 50 |
border: o.style === 'minimal' ? 'none' : '1px solid ' + borderCol, |
| 51 |
boxShadow: o.style === 'card' ? '0 2px 12px rgba(0,0,0,.07)' : 'none' |
| 52 |
}); |
| 53 |
|
| 54 |
// Header |
| 55 |
var header = mk('div', 'bkbg-db-side-header', { |
| 56 |
background: color, |
| 57 |
padding: '14px ' + o.gap + 'px' |
| 58 |
}); |
| 59 |
|
| 60 |
if (o.showIcons && icon) { |
| 61 |
var iconEl = mkText('span', 'bkbg-db-side-icon', icon); |
| 62 |
header.appendChild(iconEl); |
| 63 |
} |
| 64 |
|
| 65 |
var labelEl = mkText('span', 'bkbg-db-side-label', label, { |
| 66 |
color: o.headerTextColor |
| 67 |
}); |
| 68 |
header.appendChild(labelEl); |
| 69 |
card.appendChild(header); |
| 70 |
|
| 71 |
// Points |
| 72 |
var pointsList = mk('ul', 'bkbg-db-points', { padding: '12px ' + o.gap + 'px' }); |
| 73 |
|
| 74 |
(points || []).forEach(function (point, idx) { |
| 75 |
var li = mk('li', 'bkbg-db-point'); |
| 76 |
|
| 77 |
if (o.showBullets) { |
| 78 |
var bullet = mkText('span', 'bkbg-db-bullet', isLeft ? '✓' : '✗', { color: color }); |
| 79 |
li.appendChild(bullet); |
| 80 |
} |
| 81 |
|
| 82 |
var text = mkText('span', 'bkbg-db-point-text', point, { |
| 83 |
color: o.textColor |
| 84 |
}); |
| 85 |
li.appendChild(text); |
| 86 |
pointsList.appendChild(li); |
| 87 |
}); |
| 88 |
|
| 89 |
card.appendChild(pointsList); |
| 90 |
return card; |
| 91 |
} |
| 92 |
|
| 93 |
function init() { |
| 94 |
document.querySelectorAll('.bkbg-debate-block-app').forEach(function (appEl) { |
| 95 |
if (appEl.dataset.rendered) return; |
| 96 |
appEl.dataset.rendered = '1'; |
| 97 |
|
| 98 |
var opts; try { opts = JSON.parse(appEl.dataset.opts || '{}'); } catch (e) { opts = {}; } |
| 99 |
|
| 100 |
var o = { |
| 101 |
blockTitle: opts.blockTitle || 'The Great Debate', |
| 102 |
showTitle: opts.showTitle !== false, |
| 103 |
blockSubtitle: opts.blockSubtitle || '', |
| 104 |
showSubtitle: opts.showSubtitle !== false, |
| 105 |
leftLabel: opts.leftLabel || 'For', |
| 106 |
rightLabel: opts.rightLabel || 'Against', |
| 107 |
leftIcon: opts.leftIcon || '👍', |
| 108 |
rightIcon: opts.rightIcon || '👎', |
| 109 |
leftPoints: opts.leftPoints || [], |
| 110 |
rightPoints: opts.rightPoints || [], |
| 111 |
verdict: opts.verdict || '', |
| 112 |
showVerdict: opts.showVerdict !== false, |
| 113 |
verdictLabel: opts.verdictLabel || '💡 Verdict', |
| 114 |
layout: opts.layout || 'columns', |
| 115 |
style: opts.style || 'card', |
| 116 |
showIcons: opts.showIcons !== false, |
| 117 |
showBullets: opts.showBullets !== false, |
| 118 |
borderRadius: opts.borderRadius !== undefined ? opts.borderRadius : 12, |
| 119 |
gap: opts.gap !== undefined ? opts.gap : 20, |
| 120 |
fontSize: opts.fontSize !== undefined ? opts.fontSize : 14, |
| 121 |
headerFontSize:opts.headerFontSize !== undefined ? opts.headerFontSize : 18, |
| 122 |
leftColor: opts.leftColor || '#22c55e', |
| 123 |
rightColor: opts.rightColor || '#ef4444', |
| 124 |
bgColor: opts.bgColor || '#f8fafc', |
| 125 |
leftBg: opts.leftBg || '#f0fdf4', |
| 126 |
rightBg: opts.rightBg || '#fef2f2', |
| 127 |
textColor: opts.textColor || '#374151', |
| 128 |
headerTextColor: opts.headerTextColor || '#ffffff', |
| 129 |
titleColor: opts.titleColor || '#0f172a', |
| 130 |
subtitleColor: opts.subtitleColor || '#64748b', |
| 131 |
verdictBg: opts.verdictBg || '#fffbeb', |
| 132 |
verdictColor: opts.verdictColor || '#92400e', |
| 133 |
verdictBorderColor:opts.verdictBorderColor|| '#fcd34d' |
| 134 |
}; |
| 135 |
|
| 136 |
/* ── Block wrapper ───────────────────────────────── */ |
| 137 |
var block = mk('div', 'bkbg-db-block', { |
| 138 |
background: o.bgColor, |
| 139 |
borderRadius: o.borderRadius + 'px', |
| 140 |
overflow: 'hidden' |
| 141 |
}); |
| 142 |
|
| 143 |
/* ── Typography CSS vars ─────────────────────────── */ |
| 144 |
block.style.setProperty('--bkbg-db-ttl-fs', (opts.blockTitleFontSize || 22) + 'px'); |
| 145 |
block.style.setProperty('--bkbg-db-sub-fs', (opts.blockSubtitleFontSize || 14) + 'px'); |
| 146 |
block.style.setProperty('--bkbg-db-hdr-fs', (o.headerFontSize) + 'px'); |
| 147 |
block.style.setProperty('--bkbg-db-pt-fs', (o.fontSize) + 'px'); |
| 148 |
if (opts.typoTitle) typoCssVarsForEl(opts.typoTitle, '--bkbg-db-ttl-', block); |
| 149 |
if (opts.typoSubtitle) typoCssVarsForEl(opts.typoSubtitle, '--bkbg-db-sub-', block); |
| 150 |
if (opts.typoHeader) typoCssVarsForEl(opts.typoHeader, '--bkbg-db-hdr-', block); |
| 151 |
if (opts.typoPoint) typoCssVarsForEl(opts.typoPoint, '--bkbg-db-pt-', block); |
| 152 |
|
| 153 |
/* ── Title / intro ───────────────────────────────── */ |
| 154 |
if (o.showTitle || o.showSubtitle) { |
| 155 |
var intro = mk('div', 'bkbg-db-intro', { |
| 156 |
padding: '28px ' + o.gap + 'px ' + o.gap + 'px', |
| 157 |
borderBottom: '1px solid #f1f5f9' |
| 158 |
}); |
| 159 |
if (o.showTitle && o.blockTitle) { |
| 160 |
intro.appendChild(mkText('h3', 'bkbg-db-title', o.blockTitle, { color: o.titleColor })); |
| 161 |
} |
| 162 |
if (o.showSubtitle && o.blockSubtitle) { |
| 163 |
intro.appendChild(mkText('p', 'bkbg-db-subtitle', o.blockSubtitle, { color: o.subtitleColor })); |
| 164 |
} |
| 165 |
block.appendChild(intro); |
| 166 |
} |
| 167 |
|
| 168 |
/* ── Sides ───────────────────────────────────────── */ |
| 169 |
var sidesClass = 'bkbg-db-sides' + (o.layout === 'stacked' ? ' is-stacked' : ''); |
| 170 |
var sidesWrap = mk('div', sidesClass); |
| 171 |
|
| 172 |
sidesWrap.appendChild(buildSide(o, 'left')); |
| 173 |
|
| 174 |
if (o.layout === 'columns') { |
| 175 |
var vs = mk('div', 'bkbg-db-vs', { background: '#f1f5f9', color: '#64748b' }); |
| 176 |
vs.textContent = 'VS'; |
| 177 |
sidesWrap.appendChild(vs); |
| 178 |
} |
| 179 |
|
| 180 |
sidesWrap.appendChild(buildSide(o, 'right')); |
| 181 |
block.appendChild(sidesWrap); |
| 182 |
|
| 183 |
/* ── Verdict ─────────────────────────────────────── */ |
| 184 |
if (o.showVerdict && o.verdict) { |
| 185 |
var verdict = mk('div', 'bkbg-db-verdict', { |
| 186 |
margin: o.gap + 'px', |
| 187 |
background: o.verdictBg, |
| 188 |
borderColor: o.verdictBorderColor, |
| 189 |
borderRadius: o.borderRadius + 'px', |
| 190 |
padding: '16px ' + o.gap + 'px', |
| 191 |
color: o.verdictColor |
| 192 |
}); |
| 193 |
verdict.appendChild(mkText('div', 'bkbg-db-verdict-label', o.verdictLabel, { color: o.verdictColor })); |
| 194 |
verdict.appendChild(mkText('div', 'bkbg-db-verdict-text', o.verdict, { |
| 195 |
color: o.verdictColor |
| 196 |
})); |
| 197 |
block.appendChild(verdict); |
| 198 |
} |
| 199 |
|
| 200 |
/* ── Insert ──────────────────────────────────────── */ |
| 201 |
appEl.parentNode.insertBefore(block, appEl); |
| 202 |
appEl.style.display = 'none'; |
| 203 |
}); |
| 204 |
} |
| 205 |
|
| 206 |
if (document.readyState !== 'loading') { init(); } |
| 207 |
else { document.addEventListener('DOMContentLoaded', init); } |
| 208 |
})(); |
| 209 |
|