| 1 |
(function () { |
| 2 |
function typoCssVarsForEl(typo, prefix, el) { |
| 3 |
if (!typo || typeof typo !== 'object') return; |
| 4 |
var m = { |
| 5 |
family: 'font-family', weight: 'font-weight', |
| 6 |
transform: 'text-transform', style: 'font-style', decoration: 'text-decoration' |
| 7 |
}; |
| 8 |
Object.keys(m).forEach(function (k) { |
| 9 |
if (typo[k]) el.style.setProperty(prefix + m[k], typo[k]); |
| 10 |
}); |
| 11 |
var r = { |
| 12 |
size: 'font-size', lineHeight: 'line-height', |
| 13 |
letterSpacing: 'letter-spacing', wordSpacing: 'word-spacing' |
| 14 |
}; |
| 15 |
Object.keys(r).forEach(function (k) { |
| 16 |
['Desktop', 'Tablet', 'Mobile'].forEach(function (d, i) { |
| 17 |
var v = typo[k + d]; |
| 18 |
if (v === undefined || v === '') return; |
| 19 |
var suffix = ['-d', '-t', '-m'][i]; |
| 20 |
var unit = typo[k + 'Unit'] || ('size' === k ? 'px' : (k === 'lineHeight' ? '' : 'px')); |
| 21 |
el.style.setProperty(prefix + r[k] + suffix, v + unit); |
| 22 |
}); |
| 23 |
}); |
| 24 |
} |
| 25 |
|
| 26 |
var STATUS_ICONS = { |
| 27 |
'color-check': { included: '✓', 'not-included': '✗', partial: '◐', 'coming-soon': '⏱' }, |
| 28 |
'emoji': { included: '� |
| 29 |
', 'not-included': '❌', partial: '🔶', 'coming-soon': '🔜' }, |
| 30 |
'minimal': { included: '•', 'not-included': '–', partial: '~', 'coming-soon': '…' } |
| 31 |
}; |
| 32 |
|
| 33 |
function init() { |
| 34 |
document.querySelectorAll('.bkbg-fl-app').forEach(function (appEl) { |
| 35 |
if (appEl.dataset.rendered) return; |
| 36 |
appEl.dataset.rendered = '1'; |
| 37 |
|
| 38 |
var opts; |
| 39 |
try { opts = JSON.parse(appEl.dataset.opts || '{}'); } catch (e) { opts = {}; } |
| 40 |
|
| 41 |
var o = Object.assign({ |
| 42 |
heading: 'Everything in Pro', showHeading: true, |
| 43 |
items: [], listStyle: 'bordered', iconSet: 'color-check', |
| 44 |
showDesc: true, showBadge: true, showNotIncluded: true, strikeNotIncluded: false, |
| 45 |
iconSize: 20, fontSize: 15, gap: 0, borderRadius: 12, |
| 46 |
paddingTop: 0, paddingBottom: 0, |
| 47 |
bgColor: '', itemBg: '#ffffff', stripeBg: '#f9fafb', borderColor: '#e5e7eb', |
| 48 |
labelColor: '#111827', descColor: '#6b7280', headingColor: '#111827', |
| 49 |
includedColor: '#10b981', notIncludedColor: '#d1d5db', |
| 50 |
partialColor: '#f59e0b', comingSoonColor: '#8b5cf6', |
| 51 |
badgeBg: '#ede9fe', badgeColor: '#7c3aed' |
| 52 |
}, opts); |
| 53 |
|
| 54 |
function statusColor(s) { |
| 55 |
if (s === 'included') return o.includedColor; |
| 56 |
if (s === 'not-included') return o.notIncludedColor; |
| 57 |
if (s === 'partial') return o.partialColor; |
| 58 |
if (s === 'coming-soon') return o.comingSoonColor; |
| 59 |
return o.labelColor; |
| 60 |
} |
| 61 |
|
| 62 |
function statusIcon(s) { |
| 63 |
var icons = STATUS_ICONS[o.iconSet] || STATUS_ICONS['color-check']; |
| 64 |
return icons[s] || '•'; |
| 65 |
} |
| 66 |
|
| 67 |
/* Wrapper */ |
| 68 |
var section = document.createElement('div'); |
| 69 |
section.className = 'bkbg-fl-wrap'; |
| 70 |
section.style.cssText = [ |
| 71 |
o.bgColor ? 'background:' + o.bgColor : '', |
| 72 |
'padding-top:' + o.paddingTop + 'px', |
| 73 |
'padding-bottom:' + o.paddingBottom + 'px' |
| 74 |
].filter(Boolean).join(';'); |
| 75 |
|
| 76 |
/* CSS vars */ |
| 77 |
section.style.setProperty('--fl-border', o.borderColor); |
| 78 |
section.style.setProperty('--fl-radius', o.borderRadius + 'px'); |
| 79 |
typoCssVarsForEl(o.typoHeading, '--bkbg-fl-hd-', section); |
| 80 |
typoCssVarsForEl(o.typoLabel, '--bkbg-fl-lb-', section); |
| 81 |
typoCssVarsForEl(o.typoDesc, '--bkbg-fl-ds-', section); |
| 82 |
|
| 83 |
/* Heading */ |
| 84 |
if (o.showHeading && o.heading) { |
| 85 |
var h = document.createElement('h3'); |
| 86 |
h.className = 'bkbg-fl-heading'; |
| 87 |
h.innerHTML = o.heading; |
| 88 |
h.style.color = o.headingColor; |
| 89 |
section.appendChild(h); |
| 90 |
} |
| 91 |
|
| 92 |
/* List */ |
| 93 |
var list = document.createElement('div'); |
| 94 |
list.className = 'bkbg-fl-list style-' + o.listStyle; |
| 95 |
if (o.borderRadius && (o.listStyle === 'card')) { |
| 96 |
list.style.borderRadius = o.borderRadius + 'px'; |
| 97 |
} |
| 98 |
|
| 99 |
var prevGroup = ''; |
| 100 |
var displayedIdx = 0; |
| 101 |
|
| 102 |
(o.items || []).forEach(function (it, idx) { |
| 103 |
if (!o.showNotIncluded && it.status === 'not-included') return; |
| 104 |
|
| 105 |
/* Group header */ |
| 106 |
if (it.group && it.group !== prevGroup) { |
| 107 |
var g = document.createElement('div'); |
| 108 |
g.className = 'bkbg-fl-group'; |
| 109 |
g.textContent = it.group; |
| 110 |
g.style.background = o.stripeBg; |
| 111 |
g.style.color = o.descColor; |
| 112 |
g.style.borderColor = o.borderColor; |
| 113 |
list.appendChild(g); |
| 114 |
prevGroup = it.group; |
| 115 |
} |
| 116 |
|
| 117 |
var isStriped = o.listStyle === 'striped'; |
| 118 |
var rowBg = isStriped && displayedIdx % 2 === 1 ? o.stripeBg : o.itemBg; |
| 119 |
var isNotIncl = it.status === 'not-included'; |
| 120 |
|
| 121 |
var row = document.createElement('div'); |
| 122 |
row.className = 'bkbg-fl-row'; |
| 123 |
row.style.background = rowBg; |
| 124 |
if (o.listStyle === 'compact' && o.gap > 0) { |
| 125 |
row.style.marginBottom = o.gap + 'px'; |
| 126 |
} |
| 127 |
|
| 128 |
/* Icon */ |
| 129 |
var icon = document.createElement('span'); |
| 130 |
icon.className = 'bkbg-fl-icon'; |
| 131 |
icon.textContent = statusIcon(it.status); |
| 132 |
icon.style.cssText = 'color:' + statusColor(it.status) + ';font-size:' + o.iconSize + 'px;width:' + o.iconSize + 'px'; |
| 133 |
row.appendChild(icon); |
| 134 |
|
| 135 |
/* Body */ |
| 136 |
var body = document.createElement('div'); |
| 137 |
body.className = 'bkbg-fl-body'; |
| 138 |
|
| 139 |
var label = document.createElement('div'); |
| 140 |
label.className = 'bkbg-fl-label'; |
| 141 |
label.textContent = it.label; |
| 142 |
label.style.cssText = 'color:' + (isNotIncl ? o.notIncludedColor : o.labelColor) + (isNotIncl && o.strikeNotIncluded ? ';text-decoration:line-through' : ''); |
| 143 |
body.appendChild(label); |
| 144 |
|
| 145 |
if (o.showDesc && it.description) { |
| 146 |
var desc = document.createElement('div'); |
| 147 |
desc.className = 'bkbg-fl-desc'; |
| 148 |
desc.textContent = it.description; |
| 149 |
desc.style.cssText = 'color:' + o.descColor; |
| 150 |
body.appendChild(desc); |
| 151 |
} |
| 152 |
|
| 153 |
row.appendChild(body); |
| 154 |
|
| 155 |
/* Badge */ |
| 156 |
if (o.showBadge && it.badge) { |
| 157 |
var badge = document.createElement('span'); |
| 158 |
badge.className = 'bkbg-fl-badge'; |
| 159 |
badge.textContent = it.badge; |
| 160 |
badge.style.cssText = 'background:' + o.badgeBg + ';color:' + o.badgeColor; |
| 161 |
row.appendChild(badge); |
| 162 |
} |
| 163 |
|
| 164 |
list.appendChild(row); |
| 165 |
displayedIdx++; |
| 166 |
}); |
| 167 |
|
| 168 |
section.appendChild(list); |
| 169 |
appEl.parentNode.insertBefore(section, appEl); |
| 170 |
}); |
| 171 |
} |
| 172 |
|
| 173 |
if (document.readyState !== 'loading') { init(); } |
| 174 |
else { document.addEventListener('DOMContentLoaded', init); } |
| 175 |
})(); |
| 176 |
|