| 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 tx(tag, cls, text, styles) { |
| 11 |
var d = mk(tag, cls, styles); |
| 12 |
d.textContent = text; |
| 13 |
return d; |
| 14 |
} |
| 15 |
function ap(parent) { |
| 16 |
Array.prototype.slice.call(arguments, 1).forEach(function (c) { if (c) parent.appendChild(c); }); |
| 17 |
return parent; |
| 18 |
} |
| 19 |
function mkA(href, text, color) { |
| 20 |
var a = document.createElement('a'); |
| 21 |
a.href = href || '#'; |
| 22 |
a.textContent = text; |
| 23 |
if (color) a.style.color = color; |
| 24 |
return a; |
| 25 |
} |
| 26 |
|
| 27 |
function difficultyBadge(diff) { |
| 28 |
var map = { |
| 29 |
beginner: { label: '🟢 Beginner', bg: '#dcfce7', color: '#14532d' }, |
| 30 |
intermediate: { label: '🟡 Intermediate', bg: '#fef9c3', color: '#713f12' }, |
| 31 |
advanced: { label: '🟠 Advanced', bg: '#ffedd5', color: '#9a3412' }, |
| 32 |
expert: { label: '🔴 Expert', bg: '#fee2e2', color: '#991b1b' } |
| 33 |
}; |
| 34 |
return map[diff] || map.beginner; |
| 35 |
} |
| 36 |
|
| 37 |
var typoKeys = [ |
| 38 |
['family','font-family'],['weight','font-weight'],['style','font-style'], |
| 39 |
['decoration','text-decoration'],['transform','text-transform'], |
| 40 |
['sizeDesktop','font-size-d'],['sizeTablet','font-size-t'],['sizeMobile','font-size-m'], |
| 41 |
['lineHeightDesktop','line-height-d'],['lineHeightTablet','line-height-t'],['lineHeightMobile','line-height-m'], |
| 42 |
['letterSpacingDesktop','letter-spacing-d'],['letterSpacingTablet','letter-spacing-t'],['letterSpacingMobile','letter-spacing-m'], |
| 43 |
['wordSpacingDesktop','word-spacing-d'],['wordSpacingTablet','word-spacing-t'],['wordSpacingMobile','word-spacing-m'] |
| 44 |
]; |
| 45 |
function typoCssVarsForEl(el, typo, prefix) { |
| 46 |
if (!typo || typeof typo !== 'object') return; |
| 47 |
var u = typo.sizeUnit || 'px'; |
| 48 |
typoKeys.forEach(function (pair) { |
| 49 |
var v = typo[pair[0]]; |
| 50 |
if (v === undefined || v === '' || v === null) return; |
| 51 |
var css = (typeof v === 'number' && pair[0].indexOf('size') !== -1) ? v + u |
| 52 |
: (typeof v === 'number') ? String(v) : v; |
| 53 |
el.style.setProperty(prefix + pair[1], css); |
| 54 |
}); |
| 55 |
} |
| 56 |
|
| 57 |
function init() { |
| 58 |
document.querySelectorAll('.bkbg-kb-article-app').forEach(function (appEl) { |
| 59 |
if (appEl.dataset.rendered) return; |
| 60 |
appEl.dataset.rendered = '1'; |
| 61 |
|
| 62 |
var opts; |
| 63 |
try { opts = JSON.parse(appEl.dataset.opts || '{}'); } catch (e) { opts = {}; } |
| 64 |
|
| 65 |
var o = Object.assign({ |
| 66 |
articleTitle: 'Knowledge Base Article', |
| 67 |
category: '', |
| 68 |
subcategory: '', |
| 69 |
showCategory: true, |
| 70 |
difficulty: 'beginner', |
| 71 |
showDifficulty: true, |
| 72 |
lastUpdated: '', |
| 73 |
showLastUpdated: true, |
| 74 |
readTime: '', |
| 75 |
showReadTime: true, |
| 76 |
appliesTo: '', |
| 77 |
showAppliesTo: true, |
| 78 |
intro: '', |
| 79 |
showIntro: true, |
| 80 |
showToc: true, |
| 81 |
tocLabel: 'In this article', |
| 82 |
sections: [], |
| 83 |
tags: [], |
| 84 |
showTags: true, |
| 85 |
relatedArticles: [], |
| 86 |
showRelated: true, |
| 87 |
relatedLabel: 'Related Articles', |
| 88 |
helpfulYes: 0, |
| 89 |
helpfulNo: 0, |
| 90 |
showHelpful: true, |
| 91 |
helpfulLabel: 'Was this article helpful?', |
| 92 |
fontSize: 15, |
| 93 |
titleFontSize: 26, |
| 94 |
lineHeight: 175, |
| 95 |
borderRadius: 10, |
| 96 |
maxWidth: 820, |
| 97 |
bgColor: '#ffffff', |
| 98 |
borderColor: '#e2e8f0', |
| 99 |
headerBg: '#f8fafc', |
| 100 |
headerColor: '#0f172a', |
| 101 |
categoryColor: '#64748b', |
| 102 |
titleColor: '#0f172a', |
| 103 |
textColor: '#374151', |
| 104 |
tocBg: '#f1f5f9', |
| 105 |
tocColor: '#1e293b', |
| 106 |
tocLinkColor: '#2563eb', |
| 107 |
headingColor: '#0f172a', |
| 108 |
sectionBorderColor: '#e5e7eb', |
| 109 |
infoBg: '#eff6ff', |
| 110 |
infoColor: '#1e40af', |
| 111 |
infoBorderColor: '#93c5fd', |
| 112 |
warningBg: '#fffbeb', |
| 113 |
warningColor: '#92400e', |
| 114 |
warningBorderColor: '#fcd34d', |
| 115 |
stepNumberBg: '#2563eb', |
| 116 |
stepNumberColor: '#ffffff', |
| 117 |
accentColor: '#2563eb', |
| 118 |
tagBg: '#f1f5f9', |
| 119 |
tagColor: '#475569', |
| 120 |
helpfulYesBg: '#dcfce7', |
| 121 |
helpfulYesColor: '#14532d', |
| 122 |
helpfulNoBg: '#fee2e2', |
| 123 |
helpfulNoColor: '#991b1b' |
| 124 |
}, opts); |
| 125 |
|
| 126 |
var br = (o.borderRadius || 10) + 'px'; |
| 127 |
var db = difficultyBadge(o.difficulty); |
| 128 |
|
| 129 |
var block = mk('div', 'bkbg-kba-block', { |
| 130 |
border: '1px solid ' + o.borderColor, |
| 131 |
borderRadius: br, |
| 132 |
overflow: 'hidden', |
| 133 |
maxWidth: (o.maxWidth || 820) + 'px' |
| 134 |
}); |
| 135 |
typoCssVarsForEl(block, o.titleTypo, '--bkbg-kba-tt-'); |
| 136 |
typoCssVarsForEl(block, o.bodyTypo, '--bkbg-kba-bd-'); |
| 137 |
block.style.setProperty('--bkbg-kba-sec-border', o.sectionBorderColor || '#e5e7eb'); |
| 138 |
|
| 139 |
// ── Header ───────────────────────────────────────────── |
| 140 |
var header = mk('div', 'bkbg-kba-header', { |
| 141 |
background: o.headerBg, |
| 142 |
borderBottom: '1px solid ' + o.borderColor, |
| 143 |
borderRadius: (o.borderRadius || 10) + 'px ' + (o.borderRadius || 10) + 'px 0 0' |
| 144 |
}); |
| 145 |
|
| 146 |
if (o.showCategory && o.category) { |
| 147 |
var bc = tx('div', 'bkbg-kba-breadcrumb', o.category + (o.subcategory ? ' › ' + o.subcategory : ''), { color: o.categoryColor }); |
| 148 |
ap(header, bc); |
| 149 |
} |
| 150 |
|
| 151 |
var titleEl = tx('h2', 'bkbg-kba-title', o.articleTitle, { color: o.titleColor }); |
| 152 |
ap(header, titleEl); |
| 153 |
|
| 154 |
var meta = mk('div', 'bkbg-kba-meta', { color: o.categoryColor }); |
| 155 |
if (o.showDifficulty) { |
| 156 |
ap(meta, tx('span', 'bkbg-kba-difficulty', db.label, { background: db.bg, color: db.color })); |
| 157 |
} |
| 158 |
if (o.showReadTime && o.readTime) ap(meta, tx('span', null, '⏱ ' + o.readTime)); |
| 159 |
if (o.showLastUpdated && o.lastUpdated) ap(meta, tx('span', null, '🗓 Updated ' + o.lastUpdated)); |
| 160 |
if (o.showAppliesTo && o.appliesTo) ap(meta, tx('span', null, '� |
| 161 |
' + o.appliesTo)); |
| 162 |
ap(header, meta); |
| 163 |
ap(block, header); |
| 164 |
|
| 165 |
// ── Body ─────────────────────────────────────────────── |
| 166 |
var body = mk('div', 'bkbg-kba-body', { background: o.bgColor, color: o.textColor }); |
| 167 |
|
| 168 |
if (o.showIntro && o.intro) { |
| 169 |
ap(body, tx('p', 'bkbg-kba-intro', o.intro)); |
| 170 |
} |
| 171 |
|
| 172 |
// TOC |
| 173 |
if (o.showToc && o.sections && o.sections.length) { |
| 174 |
var toc = mk('div', 'bkbg-kba-toc', { background: o.tocBg }); |
| 175 |
ap(toc, tx('span', 'bkbg-kba-toc-label', o.tocLabel || 'In this article', { color: o.tocColor })); |
| 176 |
var tocList = mk('ol', 'bkbg-kba-toc-list'); |
| 177 |
o.sections.forEach(function (s, i) { |
| 178 |
var li = document.createElement('li'); |
| 179 |
var a = mkA('#bkbg-kba-sec-' + i, s.heading, o.tocLinkColor); |
| 180 |
li.appendChild(a); |
| 181 |
tocList.appendChild(li); |
| 182 |
}); |
| 183 |
ap(toc, tocList); |
| 184 |
ap(body, toc); |
| 185 |
} |
| 186 |
|
| 187 |
// Sections |
| 188 |
var stepNum = 0; |
| 189 |
(o.sections || []).forEach(function (s, i) { |
| 190 |
var isStep = s.type === 'step'; |
| 191 |
var isInfo = s.type === 'info'; |
| 192 |
var isWarn = s.type === 'warning'; |
| 193 |
if (isStep) stepNum++; |
| 194 |
|
| 195 |
var cls = 'bkbg-kba-section' + (isInfo ? ' is-info' : isWarn ? ' is-warning' : ''); |
| 196 |
var sec = mk('div', cls); |
| 197 |
sec.id = 'bkbg-kba-sec-' + i; |
| 198 |
|
| 199 |
if (isInfo) { sec.style.background = o.infoBg; sec.style.color = o.infoColor; sec.style.borderLeftColor = o.infoBorderColor; } |
| 200 |
if (isWarn) { sec.style.background = o.warningBg; sec.style.color = o.warningColor; sec.style.borderLeftColor = o.warningBorderColor; } |
| 201 |
|
| 202 |
var hRow = mk('div', null, { display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '10px' }); |
| 203 |
if (isStep) { |
| 204 |
var numEl = tx('span', 'bkbg-kba-step-num', String(stepNum), { background: o.stepNumberBg, color: o.stepNumberColor }); |
| 205 |
ap(hRow, numEl); |
| 206 |
} |
| 207 |
var icon = isInfo ? '💡 ' : isWarn ? '⚠️ ' : ''; |
| 208 |
var hEl = tx('h3', 'bkbg-kba-section-heading', icon + s.heading, { |
| 209 |
color: isInfo ? o.infoColor : isWarn ? o.warningColor : o.headingColor, |
| 210 |
margin: '0', |
| 211 |
fontSize: '17px', |
| 212 |
fontWeight: '700' |
| 213 |
}); |
| 214 |
ap(hRow, hEl); |
| 215 |
ap(sec, hRow); |
| 216 |
|
| 217 |
ap(sec, tx('p', 'bkbg-kba-section-content', s.content || '', { color: isInfo ? o.infoColor : isWarn ? o.warningColor : o.textColor })); |
| 218 |
ap(body, sec); |
| 219 |
}); |
| 220 |
|
| 221 |
ap(block, body); |
| 222 |
|
| 223 |
// ── Tags ────────────────────────────────────────────── |
| 224 |
if (o.showTags && o.tags && o.tags.length) { |
| 225 |
var tagsDiv = mk('div', 'bkbg-kba-tags'); |
| 226 |
o.tags.forEach(function (t) { |
| 227 |
if (!t) return; |
| 228 |
ap(tagsDiv, tx('span', 'bkbg-kba-tag', t, { background: o.tagBg, color: o.tagColor })); |
| 229 |
}); |
| 230 |
ap(block, tagsDiv); |
| 231 |
} |
| 232 |
|
| 233 |
// ── Related ─────────────────────────────────────────── |
| 234 |
if (o.showRelated && o.relatedArticles && o.relatedArticles.length) { |
| 235 |
var rel = mk('div', 'bkbg-kba-related', { background: o.bgColor }); |
| 236 |
ap(rel, tx('span', 'bkbg-kba-related-label', o.relatedLabel || 'Related Articles', { color: o.headingColor })); |
| 237 |
var relUl = mk('ul', 'bkbg-kba-related-list'); |
| 238 |
o.relatedArticles.forEach(function (r) { |
| 239 |
if (!r.title) return; |
| 240 |
var li = document.createElement('li'); |
| 241 |
var a = mkA(r.url || '#', r.title, o.accentColor); |
| 242 |
li.appendChild(a); |
| 243 |
relUl.appendChild(li); |
| 244 |
}); |
| 245 |
ap(rel, relUl); |
| 246 |
ap(block, rel); |
| 247 |
} |
| 248 |
|
| 249 |
// ── Helpful ─────────────────────────────────────────── |
| 250 |
if (o.showHelpful) { |
| 251 |
var helpful = mk('div', 'bkbg-kba-helpful', { background: o.bgColor }); |
| 252 |
ap(helpful, tx('span', 'bkbg-kba-helpful-label', o.helpfulLabel || 'Was this article helpful?')); |
| 253 |
|
| 254 |
var yesBtn = tx('button', 'bkbg-kba-helpful-btn', '👍 Yes (' + (o.helpfulYes || 0) + ')', { background: o.helpfulYesBg, color: o.helpfulYesColor }); |
| 255 |
var noBtn = tx('button', 'bkbg-kba-helpful-btn', '👎 No (' + (o.helpfulNo || 0) + ')', { background: o.helpfulNoBg, color: o.helpfulNoColor }); |
| 256 |
|
| 257 |
yesBtn.type = 'button'; |
| 258 |
noBtn.type = 'button'; |
| 259 |
|
| 260 |
var voted = false; |
| 261 |
yesBtn.addEventListener('click', function () { |
| 262 |
if (voted) return; |
| 263 |
voted = true; |
| 264 |
yesBtn.classList.add('is-voted'); |
| 265 |
yesBtn.textContent = '👍 Yes (' + ((o.helpfulYes || 0) + 1) + ')'; |
| 266 |
noBtn.disabled = true; |
| 267 |
}); |
| 268 |
noBtn.addEventListener('click', function () { |
| 269 |
if (voted) return; |
| 270 |
voted = true; |
| 271 |
noBtn.classList.add('is-voted'); |
| 272 |
noBtn.textContent = '👎 No (' + ((o.helpfulNo || 0) + 1) + ')'; |
| 273 |
yesBtn.disabled = true; |
| 274 |
}); |
| 275 |
|
| 276 |
ap(helpful, yesBtn, noBtn); |
| 277 |
ap(block, helpful); |
| 278 |
} |
| 279 |
|
| 280 |
appEl.parentNode.insertBefore(block, appEl); |
| 281 |
appEl.style.display = 'none'; |
| 282 |
}); |
| 283 |
} |
| 284 |
|
| 285 |
if (document.readyState !== 'loading') { init(); } |
| 286 |
else { document.addEventListener('DOMContentLoaded', init); } |
| 287 |
})(); |
| 288 |
|