| 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 |
|
| 20 |
function resourceIcon(type) { |
| 21 |
var map = { article: '📄', book: '📚', link: '🔗', video: '🎥', tool: '🛠️' }; |
| 22 |
return map[type] || '🔗'; |
| 23 |
} |
| 24 |
|
| 25 |
function sectionHead(label, accentColor, sectionHeadColor, parentEl) { |
| 26 |
var h = tx('div', 'bkbg-pe-section-head', label, { |
| 27 |
color: sectionHeadColor, |
| 28 |
borderBottomColor: accentColor |
| 29 |
}); |
| 30 |
ap(parentEl, h); |
| 31 |
} |
| 32 |
|
| 33 |
var _typoKeys = { |
| 34 |
family:'font-family', weight:'font-weight', style:'font-style', |
| 35 |
decoration:'text-decoration', transform:'text-transform', |
| 36 |
sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m', |
| 37 |
lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m', |
| 38 |
letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m', |
| 39 |
wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m' |
| 40 |
}; |
| 41 |
function typoCssVarsForEl(el, obj, prefix) { |
| 42 |
if (!obj || typeof obj !== 'object') return; |
| 43 |
Object.keys(_typoKeys).forEach(function (k) { |
| 44 |
var v = obj[k]; |
| 45 |
if (v === undefined || v === '' || v === null) return; |
| 46 |
if (k === 'sizeDesktop' || k === 'sizeTablet' || k === 'sizeMobile') v = v + (obj.sizeUnit || 'px'); |
| 47 |
else if (k === 'lineHeightDesktop' || k === 'lineHeightTablet' || k === 'lineHeightMobile') v = v + (obj.lineHeightUnit || ''); |
| 48 |
else if (k === 'letterSpacingDesktop' || k === 'letterSpacingTablet' || k === 'letterSpacingMobile') v = v + (obj.letterSpacingUnit || 'px'); |
| 49 |
else if (k === 'wordSpacingDesktop' || k === 'wordSpacingTablet' || k === 'wordSpacingMobile') v = v + (obj.wordSpacingUnit || 'px'); |
| 50 |
el.style.setProperty(prefix + _typoKeys[k], String(v)); |
| 51 |
}); |
| 52 |
} |
| 53 |
|
| 54 |
function init() { |
| 55 |
document.querySelectorAll('.bkbg-podcast-episode-app').forEach(function (appEl) { |
| 56 |
if (appEl.dataset.rendered) return; |
| 57 |
appEl.dataset.rendered = '1'; |
| 58 |
|
| 59 |
var opts; |
| 60 |
try { opts = JSON.parse(appEl.dataset.opts || '{}'); } catch (e) { opts = {}; } |
| 61 |
|
| 62 |
var o = Object.assign({ |
| 63 |
episodeTitle: 'Podcast Episode', episodeNumber: '1', season: '1', |
| 64 |
showNumber: true, podcastName: '', showPodcastName: true, |
| 65 |
publishDate: '', duration: '', showMeta: true, |
| 66 |
description: '', showDescription: true, |
| 67 |
guests: [], showGuests: true, guestsLabel: 'Guests', |
| 68 |
timestamps: [], showTimestamps: true, timestampsLabel: 'Chapters', |
| 69 |
listenLinks: [], showListenLinks: true, listenLinksLabel: 'Listen on', |
| 70 |
resources: [], showResources: true, resourcesLabel: 'Resources & Links', |
| 71 |
transcript: '', showTranscript: true, transcriptLabel: 'Highlighted Quote', |
| 72 |
tags: [], showTags: true, |
| 73 |
fontSize: 14, titleFontSize: 22, lineHeight: 168, borderRadius: 12, |
| 74 |
titleTypo: {}, bodyTypo: {}, |
| 75 |
bgColor: '#0f172a', headerColor: '#ffffff', |
| 76 |
bodyBg: '#ffffff', bodyBorderColor: '#e5e7eb', |
| 77 |
textColor: '#374151', mutedColor: '#6b7280', |
| 78 |
accentColor: '#3b82f6', sectionHeadColor: '#0f172a', |
| 79 |
chapterTimeBg: '#f1f5f9', chapterTimeColor: '#1e293b', |
| 80 |
guestBg: '#f8fafc', guestBorderColor: '#e5e7eb', |
| 81 |
guestNameColor: '#0f172a', guestRoleColor: '#3b82f6', |
| 82 |
resourceIconColor: '#3b82f6', |
| 83 |
tagBg: '#eff6ff', tagColor: '#1d4ed8', |
| 84 |
listenBtnBg: '#3b82f6', listenBtnColor: '#ffffff', |
| 85 |
transcriptBg: '#f8fafc', transcriptBorderColor: '#3b82f6' |
| 86 |
}, opts); |
| 87 |
|
| 88 |
// Block |
| 89 |
var block = mk('div', 'bkbg-pe-block', { |
| 90 |
border: '1px solid ' + o.bodyBorderColor, |
| 91 |
borderRadius: o.borderRadius + 'px', |
| 92 |
overflow: 'hidden' |
| 93 |
}); |
| 94 |
typoCssVarsForEl(block, o.titleTypo, '--bkbg-pe-tt-'); |
| 95 |
typoCssVarsForEl(block, o.bodyTypo, '--bkbg-pe-bd-'); |
| 96 |
|
| 97 |
// ── Header (dark) ───────────────────────────────────── |
| 98 |
var header = mk('div', 'bkbg-pe-header', { background: o.bgColor }); |
| 99 |
if (o.showPodcastName && o.podcastName) { |
| 100 |
ap(header, tx('div', 'bkbg-pe-show-name', o.podcastName, { color: o.headerColor })); |
| 101 |
} |
| 102 |
ap(header, tx('h2', 'bkbg-pe-title', o.episodeTitle, { color: o.headerColor })); |
| 103 |
|
| 104 |
var infoRow = mk('div', 'bkbg-pe-info-row'); |
| 105 |
if (o.showNumber && (o.season || o.episodeNumber)) { |
| 106 |
ap(infoRow, tx('span', 'bkbg-pe-info-item', 'S' + o.season + ' · E' + o.episodeNumber, { color: o.headerColor })); |
| 107 |
} |
| 108 |
if (o.showMeta && o.publishDate) { |
| 109 |
ap(infoRow, tx('span', 'bkbg-pe-info-item', '� |
| 110 |
' + o.publishDate, { color: o.headerColor })); |
| 111 |
} |
| 112 |
if (o.showMeta && o.duration) { |
| 113 |
ap(infoRow, tx('span', 'bkbg-pe-info-item', '⏱ ' + o.duration, { color: o.headerColor })); |
| 114 |
} |
| 115 |
if (o.showListenLinks && o.listenLinks && o.listenLinks.length > 0) { |
| 116 |
var listenRow = mk('div', 'bkbg-pe-listen-links'); |
| 117 |
o.listenLinks.forEach(function (lnk) { |
| 118 |
if (!lnk.platform) return; |
| 119 |
var btn = mk('a', 'bkbg-pe-listen-btn', { background: o.listenBtnBg, color: o.listenBtnColor }); |
| 120 |
btn.href = lnk.url || '#'; |
| 121 |
btn.textContent = lnk.platform; |
| 122 |
ap(listenRow, btn); |
| 123 |
}); |
| 124 |
ap(infoRow, listenRow); |
| 125 |
} |
| 126 |
ap(header, infoRow); |
| 127 |
ap(block, header); |
| 128 |
|
| 129 |
// ── Body ───────────────────────────────────────────── |
| 130 |
var body = mk('div', 'bkbg-pe-body', { background: o.bodyBg }); |
| 131 |
|
| 132 |
// Description |
| 133 |
if (o.showDescription && o.description) { |
| 134 |
var descSec = mk('div', 'bkbg-pe-section'); |
| 135 |
ap(descSec, tx('p', '', o.description, { color: o.textColor, margin: '0' })); |
| 136 |
ap(body, descSec); |
| 137 |
} |
| 138 |
|
| 139 |
// Guests |
| 140 |
if (o.showGuests && o.guests && o.guests.length > 0) { |
| 141 |
var gSec = mk('div', 'bkbg-pe-section'); |
| 142 |
sectionHead(o.guestsLabel || 'Guests', o.accentColor, o.sectionHeadColor, gSec); |
| 143 |
var grid = mk('div', 'bkbg-pe-guests-grid'); |
| 144 |
o.guests.forEach(function (g) { |
| 145 |
var card = mk('div', 'bkbg-pe-guest-card', { background: o.guestBg, borderColor: o.guestBorderColor }); |
| 146 |
ap(card, tx('div', 'bkbg-pe-guest-name', g.name, { color: o.guestNameColor })); |
| 147 |
if (g.role) ap(card, tx('div', 'bkbg-pe-guest-role', g.role, { color: o.guestRoleColor })); |
| 148 |
if (g.bio) ap(card, tx('p', 'bkbg-pe-guest-bio', g.bio, { color: o.mutedColor })); |
| 149 |
ap(grid, card); |
| 150 |
}); |
| 151 |
ap(gSec, grid); |
| 152 |
ap(body, gSec); |
| 153 |
} |
| 154 |
|
| 155 |
// Chapters |
| 156 |
if (o.showTimestamps && o.timestamps && o.timestamps.length > 0) { |
| 157 |
var tsSec = mk('div', 'bkbg-pe-section'); |
| 158 |
sectionHead(o.timestampsLabel || 'Chapters', o.accentColor, o.sectionHeadColor, tsSec); |
| 159 |
var chList = mk('ul', 'bkbg-pe-chapters'); |
| 160 |
o.timestamps.forEach(function (ts, i) { |
| 161 |
var li = mk('li', 'bkbg-pe-chapter', { borderBottomColor: o.bodyBorderColor }); |
| 162 |
var time = tx('span', 'bkbg-pe-chapter-time', ts.time, { background: o.chapterTimeBg, color: o.chapterTimeColor }); |
| 163 |
var title = tx('span', '', ts.title, { color: o.textColor }); |
| 164 |
ap(li, time, title); |
| 165 |
ap(chList, li); |
| 166 |
}); |
| 167 |
ap(tsSec, chList); |
| 168 |
ap(body, tsSec); |
| 169 |
} |
| 170 |
|
| 171 |
// Resources |
| 172 |
if (o.showResources && o.resources && o.resources.length > 0) { |
| 173 |
var rSec = mk('div', 'bkbg-pe-section'); |
| 174 |
sectionHead(o.resourcesLabel || 'Resources & Links', o.accentColor, o.sectionHeadColor, rSec); |
| 175 |
var rList = mk('ul', 'bkbg-pe-resources'); |
| 176 |
o.resources.forEach(function (r) { |
| 177 |
var li = mk('li', 'bkbg-pe-resource', { borderBottomColor: o.bodyBorderColor }); |
| 178 |
var icon = tx('span', 'bkbg-pe-resource-icon', resourceIcon(r.type), { color: o.resourceIconColor }); |
| 179 |
var link = mk('a', 'bkbg-pe-resource-link', { color: o.accentColor }); |
| 180 |
link.href = r.url || '#'; link.textContent = r.title; |
| 181 |
ap(li, icon, link); |
| 182 |
ap(rList, li); |
| 183 |
}); |
| 184 |
ap(rSec, rList); |
| 185 |
ap(body, rSec); |
| 186 |
} |
| 187 |
|
| 188 |
// Quote / Transcript |
| 189 |
if (o.showTranscript && o.transcript) { |
| 190 |
var qSec = mk('div', 'bkbg-pe-section'); |
| 191 |
sectionHead(o.transcriptLabel || 'Highlighted Quote', o.accentColor, o.sectionHeadColor, qSec); |
| 192 |
ap(qSec, tx('blockquote', 'bkbg-pe-quote', o.transcript, { |
| 193 |
background: o.transcriptBg, |
| 194 |
borderLeftColor: o.transcriptBorderColor, |
| 195 |
color: o.textColor |
| 196 |
})); |
| 197 |
ap(body, qSec); |
| 198 |
} |
| 199 |
|
| 200 |
// Tags |
| 201 |
if (o.showTags && o.tags && o.tags.length > 0) { |
| 202 |
var tagWrap = mk('div', 'bkbg-pe-tags'); |
| 203 |
o.tags.forEach(function (tag) { |
| 204 |
if (!tag) return; |
| 205 |
ap(tagWrap, tx('span', 'bkbg-pe-tag', tag, { background: o.tagBg, color: o.tagColor })); |
| 206 |
}); |
| 207 |
ap(body, tagWrap); |
| 208 |
} |
| 209 |
|
| 210 |
ap(block, body); |
| 211 |
appEl.parentNode.insertBefore(block, appEl); |
| 212 |
appEl.style.display = 'none'; |
| 213 |
}); |
| 214 |
} |
| 215 |
|
| 216 |
if (document.readyState !== 'loading') { init(); } |
| 217 |
else { document.addEventListener('DOMContentLoaded', init); } |
| 218 |
})(); |
| 219 |
|