| 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 statusInfo(status, o) { |
| 21 |
if (status === 'in-progress') return { label: 'In Progress', bg: o.taskInProgressBg, color: o.taskInProgressColor }; |
| 22 |
if (status === 'done') return { label: '✓ Done', bg: o.taskDoneBg, color: o.taskDoneColor }; |
| 23 |
return { label: 'Open', bg: o.taskOpenBg, color: o.taskOpenColor }; |
| 24 |
} |
| 25 |
|
| 26 |
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' }; |
| 27 |
function typoCssVarsForEl(el, typo, prefix) { |
| 28 |
if (!typo || typeof typo !== 'object') return; |
| 29 |
Object.keys(_typoKeys).forEach(function (k) { |
| 30 |
if (typo[k] !== undefined && typo[k] !== '') el.style.setProperty(prefix + _typoKeys[k], typo[k]); |
| 31 |
}); |
| 32 |
} |
| 33 |
|
| 34 |
function init() { |
| 35 |
document.querySelectorAll('.bkbg-meeting-recap-app').forEach(function (appEl) { |
| 36 |
if (appEl.dataset.rendered) return; |
| 37 |
appEl.dataset.rendered = '1'; |
| 38 |
|
| 39 |
var opts; |
| 40 |
try { opts = JSON.parse(appEl.dataset.opts || '{}'); } catch (e) { opts = {}; } |
| 41 |
|
| 42 |
var o = Object.assign({ |
| 43 |
meetingTitle: 'Meeting Recap', |
| 44 |
meetingDate: '', |
| 45 |
meetingTime: '', |
| 46 |
location: '', |
| 47 |
facilitator: '', |
| 48 |
showMeta: true, |
| 49 |
attendees: [], |
| 50 |
showAttendees: true, |
| 51 |
attendeesLabel: 'Attendees', |
| 52 |
agendaItems: [], |
| 53 |
showAgenda: true, |
| 54 |
agendaLabel: 'Agenda', |
| 55 |
decisions: [], |
| 56 |
showDecisions: true, |
| 57 |
decisionsLabel: 'Decisions Made', |
| 58 |
actionItems: [], |
| 59 |
showActionItems: true, |
| 60 |
actionItemsLabel: 'Action Items', |
| 61 |
nextMeetingDate: '', |
| 62 |
showNextMeeting: true, |
| 63 |
nextMeetingLabel: 'Next Meeting', |
| 64 |
notes: '', |
| 65 |
showNotes: true, |
| 66 |
notesLabel: 'Additional Notes', |
| 67 |
fontSize: 14, |
| 68 |
titleFontSize: 22, |
| 69 |
lineHeight: 165, |
| 70 |
borderRadius: 10, |
| 71 |
bgColor: '#ffffff', |
| 72 |
borderColor: '#e2e8f0', |
| 73 |
headerBg: '#0f172a', |
| 74 |
headerColor: '#ffffff', |
| 75 |
sectionLabelColor: '#0f172a', |
| 76 |
textColor: '#374151', |
| 77 |
sectionBorderColor: '#e5e7eb', |
| 78 |
attendeePresentBg: '#dcfce7', |
| 79 |
attendeePresentColor: '#14532d', |
| 80 |
attendeeAbsentBg: '#f1f5f9', |
| 81 |
attendeeAbsentColor: '#64748b', |
| 82 |
decisionIconColor: '#16a34a', |
| 83 |
taskOpenBg: '#eff6ff', |
| 84 |
taskOpenColor: '#1d4ed8', |
| 85 |
taskInProgressBg: '#fef9c3', |
| 86 |
taskInProgressColor: '#854d0e', |
| 87 |
taskDoneBg: '#dcfce7', |
| 88 |
taskDoneColor: '#14532d', |
| 89 |
nextMeetingBg: '#f0f9ff', |
| 90 |
nextMeetingColor: '#0369a1', |
| 91 |
accentColor: '#3b82f6' |
| 92 |
}, opts); |
| 93 |
|
| 94 |
var br = (o.borderRadius || 10) + 'px'; |
| 95 |
var fs = (o.fontSize || 14) + 'px'; |
| 96 |
var lh = ((o.lineHeight || 165) / 100).toFixed(2); |
| 97 |
|
| 98 |
var block = mk('div', 'bkbg-mr-block', { |
| 99 |
border: '1px solid ' + o.borderColor, |
| 100 |
borderRadius: br, |
| 101 |
overflow: 'hidden' |
| 102 |
}); |
| 103 |
|
| 104 |
typoCssVarsForEl(block, o.titleTypo, '--bkbg-mr-tt-'); |
| 105 |
typoCssVarsForEl(block, o.bodyTypo, '--bkbg-mr-bd-'); |
| 106 |
typoCssVarsForEl(block, o.sectionLabelTypo, '--bkbg-mr-sl-'); |
| 107 |
|
| 108 |
// ── Header ───────────────────────────────────────────── |
| 109 |
var header = mk('div', 'bkbg-mr-header', { |
| 110 |
background: o.headerBg, |
| 111 |
color: o.headerColor, |
| 112 |
borderRadius: (o.borderRadius || 10) + 'px ' + (o.borderRadius || 10) + 'px 0 0' |
| 113 |
}); |
| 114 |
ap(header, tx('div', 'bkbg-mr-kicker', '📋 MEETING RECAP')); |
| 115 |
ap(header, tx('h2', 'bkbg-mr-title', o.meetingTitle, { color: o.headerColor })); |
| 116 |
|
| 117 |
if (o.showMeta) { |
| 118 |
var meta = mk('div', 'bkbg-mr-meta'); |
| 119 |
if (o.meetingDate) ap(meta, tx('span', null, '� |
| 120 |
' + o.meetingDate)); |
| 121 |
if (o.meetingTime) ap(meta, tx('span', null, '⏰ ' + o.meetingTime)); |
| 122 |
if (o.location) ap(meta, tx('span', null, '📍 ' + o.location)); |
| 123 |
if (o.facilitator) ap(meta, tx('span', null, '👤 ' + o.facilitator)); |
| 124 |
ap(header, meta); |
| 125 |
} |
| 126 |
ap(block, header); |
| 127 |
|
| 128 |
// ── Body ─────────────────────────────────────────────── |
| 129 |
var body = mk('div', 'bkbg-mr-body', { background: o.bgColor, color: o.textColor }); |
| 130 |
|
| 131 |
function sectionHead(label) { |
| 132 |
return tx('span', 'bkbg-mr-section-head', label, { color: o.accentColor, borderBottomColor: o.accentColor }); |
| 133 |
} |
| 134 |
|
| 135 |
// Attendees |
| 136 |
if (o.showAttendees && o.attendees && o.attendees.length) { |
| 137 |
var attSec = mk('div', 'bkbg-mr-section'); |
| 138 |
ap(attSec, sectionHead(o.attendeesLabel || 'Attendees')); |
| 139 |
var attWrap = mk('div', 'bkbg-mr-attendees'); |
| 140 |
o.attendees.forEach(function (att) { |
| 141 |
var pill = mk('div', 'bkbg-mr-attendee', { |
| 142 |
background: att.present ? o.attendeePresentBg : o.attendeeAbsentBg, |
| 143 |
color: att.present ? o.attendeePresentColor: o.attendeeAbsentColor |
| 144 |
}); |
| 145 |
|
| 146 |
var nameSp = document.createElement('strong'); |
| 147 |
nameSp.textContent = att.name || ''; |
| 148 |
ap(pill, nameSp); |
| 149 |
|
| 150 |
if (att.role) { |
| 151 |
ap(pill, tx('span', 'bkbg-mr-attendee-role', ' · ' + att.role)); |
| 152 |
} |
| 153 |
if (!att.present) { |
| 154 |
ap(pill, tx('span', 'bkbg-mr-attendee-absent', '(absent)')); |
| 155 |
} |
| 156 |
ap(attWrap, pill); |
| 157 |
}); |
| 158 |
ap(attSec, attWrap); |
| 159 |
ap(body, attSec); |
| 160 |
} |
| 161 |
|
| 162 |
// Agenda |
| 163 |
if (o.showAgenda && o.agendaItems && o.agendaItems.length) { |
| 164 |
var agSec = mk('div', 'bkbg-mr-section'); |
| 165 |
ap(agSec, sectionHead(o.agendaLabel || 'Agenda')); |
| 166 |
var agOl = mk('ol', 'bkbg-mr-agenda-list'); |
| 167 |
o.agendaItems.forEach(function (ag) { |
| 168 |
var li = document.createElement('li'); |
| 169 |
li.appendChild(document.createTextNode(ag.item || '')); |
| 170 |
if (ag.duration) { |
| 171 |
ap(li, tx('span', 'bkbg-mr-agenda-duration', '— ' + ag.duration)); |
| 172 |
} |
| 173 |
ap(agOl, li); |
| 174 |
}); |
| 175 |
ap(agSec, agOl); |
| 176 |
ap(body, agSec); |
| 177 |
} |
| 178 |
|
| 179 |
// Decisions |
| 180 |
if (o.showDecisions && o.decisions && o.decisions.length) { |
| 181 |
var decSec = mk('div', 'bkbg-mr-section'); |
| 182 |
ap(decSec, sectionHead(o.decisionsLabel || 'Decisions Made')); |
| 183 |
var decUl = mk('ul', 'bkbg-mr-decisions-list'); |
| 184 |
o.decisions.forEach(function (d) { |
| 185 |
var li = mk('li', 'bkbg-mr-decision-item'); |
| 186 |
ap(li, |
| 187 |
tx('span', 'bkbg-mr-decision-icon', '✓', { color: o.decisionIconColor }), |
| 188 |
tx('span', null, d) |
| 189 |
); |
| 190 |
ap(decUl, li); |
| 191 |
}); |
| 192 |
ap(decSec, decUl); |
| 193 |
ap(body, decSec); |
| 194 |
} |
| 195 |
|
| 196 |
// Action Items |
| 197 |
if (o.showActionItems && o.actionItems && o.actionItems.length) { |
| 198 |
var aiSec = mk('div', 'bkbg-mr-section'); |
| 199 |
ap(aiSec, sectionHead(o.actionItemsLabel || 'Action Items')); |
| 200 |
o.actionItems.forEach(function (ai) { |
| 201 |
var si = statusInfo(ai.status || 'open', o); |
| 202 |
var row = mk('div', 'bkbg-mr-action-item', { borderLeftColor: o.accentColor }); |
| 203 |
ap(row, tx('span', 'bkbg-mr-action-status', si.label, { background: si.bg, color: si.color })); |
| 204 |
ap(row, tx('span', 'bkbg-mr-action-task', ai.task || '')); |
| 205 |
if (ai.owner || ai.due) { |
| 206 |
var meta = mk('div', 'bkbg-mr-action-meta'); |
| 207 |
if (ai.owner) ap(meta, tx('span', null, '👤 ' + ai.owner)); |
| 208 |
if (ai.due) ap(meta, tx('span', null, '� |
| 209 |
' + ai.due)); |
| 210 |
ap(row, meta); |
| 211 |
} |
| 212 |
ap(aiSec, row); |
| 213 |
}); |
| 214 |
ap(body, aiSec); |
| 215 |
} |
| 216 |
|
| 217 |
// Next Meeting |
| 218 |
if (o.showNextMeeting && o.nextMeetingDate) { |
| 219 |
var nm = mk('div', 'bkbg-mr-next-meeting', { background: o.nextMeetingBg, color: o.nextMeetingColor }); |
| 220 |
ap(nm, |
| 221 |
tx('span', 'bkbg-mr-next-label', (o.nextMeetingLabel || 'Next Meeting') + ':'), |
| 222 |
tx('span', null, '� |
| 223 |
' + o.nextMeetingDate) |
| 224 |
); |
| 225 |
ap(body, nm); |
| 226 |
} |
| 227 |
|
| 228 |
// Notes |
| 229 |
if (o.showNotes && o.notes) { |
| 230 |
var noteSec = mk('div', 'bkbg-mr-section'); |
| 231 |
ap(noteSec, sectionHead(o.notesLabel || 'Additional Notes')); |
| 232 |
ap(noteSec, tx('p', 'bkbg-mr-notes-text', o.notes)); |
| 233 |
ap(body, noteSec); |
| 234 |
} |
| 235 |
|
| 236 |
ap(block, body); |
| 237 |
appEl.parentNode.insertBefore(block, appEl); |
| 238 |
appEl.style.display = 'none'; |
| 239 |
}); |
| 240 |
} |
| 241 |
|
| 242 |
if (document.readyState !== 'loading') { init(); } |
| 243 |
else { document.addEventListener('DOMContentLoaded', init); } |
| 244 |
})(); |
| 245 |
|