| 1 |
(function () { |
| 2 |
'use strict'; |
| 3 |
function mk(tag, cls, styles) { var d = document.createElement(tag); if (cls) d.className = cls; if (styles) Object.keys(styles).forEach(function (k) { d.style[k] = styles[k]; }); return d; } |
| 4 |
function tx(tag, cls, text, styles) { var d = mk(tag, cls, styles); d.textContent = text; return d; } |
| 5 |
function ap(p) { Array.prototype.slice.call(arguments, 1).forEach(function (c) { if (c) p.appendChild(c); }); return p; } |
| 6 |
|
| 7 |
var typoKeys = [ |
| 8 |
['family','font-family'],['weight','font-weight'],['style','font-style'], |
| 9 |
['decoration','text-decoration'],['transform','text-transform'], |
| 10 |
['sizeDesktop','font-size-d'],['sizeTablet','font-size-t'],['sizeMobile','font-size-m'], |
| 11 |
['lineHeightDesktop','line-height-d'],['lineHeightTablet','line-height-t'],['lineHeightMobile','line-height-m'], |
| 12 |
['letterSpacingDesktop','letter-spacing-d'],['letterSpacingTablet','letter-spacing-t'],['letterSpacingMobile','letter-spacing-m'], |
| 13 |
['wordSpacingDesktop','word-spacing-d'],['wordSpacingTablet','word-spacing-t'],['wordSpacingMobile','word-spacing-m'] |
| 14 |
]; |
| 15 |
function typoCssVarsForEl(el, typo, prefix) { |
| 16 |
if (!typo || typeof typo !== 'object') return; |
| 17 |
var u = typo.sizeUnit || 'px'; |
| 18 |
typoKeys.forEach(function (pair) { |
| 19 |
var v = typo[pair[0]]; |
| 20 |
if (v === undefined || v === '' || v === null) return; |
| 21 |
var css = (typeof v === 'number' && pair[0].indexOf('size') !== -1) ? v + u |
| 22 |
: (typeof v === 'number') ? String(v) : v; |
| 23 |
el.style.setProperty(prefix + pair[1], css); |
| 24 |
}); |
| 25 |
} |
| 26 |
|
| 27 |
function renderKeys(keysStr, a) { |
| 28 |
if (!keysStr) return null; |
| 29 |
var wrap = mk('div', 'bkbg-ks-keys'); |
| 30 |
wrap.style.cssText = 'display:flex;align-items:center;gap:3px;flex-wrap:nowrap'; |
| 31 |
keysStr.split(' ').forEach(function (k) { |
| 32 |
if (k === '/' || k === '+') { |
| 33 |
var sep = tx('span', null, k); |
| 34 |
sep.style.cssText = 'color:' + a.keyColor + ';opacity:0.4;font-size:' + a.keyFontSize + 'px'; |
| 35 |
ap(wrap, sep); |
| 36 |
} else { |
| 37 |
var key = tx('kbd', 'bkbg-ks-key', k); |
| 38 |
key.style.cssText = 'display:inline-block;padding:2px 7px;background:' + a.keyBg + ';border:1px solid ' + a.keyBorderColor + ';border-bottom:3px solid ' + a.keyBorderColor + ';border-radius:' + a.keyRadius + 'px;font-size:' + a.keyFontSize + 'px;color:' + a.keyColor + ';font-family:inherit;line-height:1.4;white-space:nowrap'; |
| 39 |
ap(wrap, key); |
| 40 |
} |
| 41 |
}); |
| 42 |
return wrap; |
| 43 |
} |
| 44 |
|
| 45 |
function buildBlock(appEl) { |
| 46 |
if (appEl.dataset.rendered) return; |
| 47 |
appEl.dataset.rendered = '1'; |
| 48 |
|
| 49 |
var a = Object.assign({ |
| 50 |
sheetTitle: 'Keyboard Shortcuts', showTitle: true, platform: 'both', sections: [], |
| 51 |
fontSize: 14, titleFontSize: 22, headingFontSize: 12, keyFontSize: 12, |
| 52 |
lineHeight: 160, borderRadius: 12, keyRadius: 6, |
| 53 |
bgColor: '#ffffff', borderColor: '#e5e7eb', titleColor: '#111827', |
| 54 |
headingBg: '#f8fafc', headingColor: '#374151', headingBorderColor: '#e5e7eb', |
| 55 |
descColor: '#374151', keyBg: '#f1f5f9', keyBorderColor: '#cbd5e1', keyColor: '#1e293b', |
| 56 |
macAccentColor: '#6366f1', winAccentColor: '#0ea5e9', separatorColor: '#f1f5f9' |
| 57 |
}, JSON.parse(appEl.dataset.opts || '{}')); |
| 58 |
|
| 59 |
var lh = (a.lineHeight / 100).toFixed(2); |
| 60 |
var showMac = (a.platform === 'mac' || a.platform === 'both'); |
| 61 |
var showWin = (a.platform === 'windows' || a.platform === 'both'); |
| 62 |
|
| 63 |
var wrap = mk('div', 'bkbg-ks-wrap'); |
| 64 |
wrap.style.cssText = 'background:' + a.bgColor + ';border-radius:' + a.borderRadius + 'px;border:1px solid ' + a.borderColor + ';overflow:hidden;font-size:' + a.fontSize + 'px;line-height:' + lh; |
| 65 |
typoCssVarsForEl(wrap, a.titleTypo, '--bkbg-ks-tt-'); |
| 66 |
|
| 67 |
if (a.showTitle && a.sheetTitle) { |
| 68 |
var header = mk('div', 'bkbg-ks-header'); |
| 69 |
header.style.cssText = 'padding:18px 20px;border-bottom:1px solid ' + a.borderColor; |
| 70 |
var titleEl = tx('h3', 'bkbg-ks-title', a.sheetTitle); |
| 71 |
titleEl.style.cssText = 'margin:0;color:' + a.titleColor; |
| 72 |
ap(header, titleEl); |
| 73 |
ap(wrap, header); |
| 74 |
} |
| 75 |
|
| 76 |
a.sections.forEach(function (sec, si) { |
| 77 |
var section = mk('div', 'bkbg-ks-section'); |
| 78 |
|
| 79 |
var secHead = mk('div', 'bkbg-ks-section-head'); |
| 80 |
secHead.style.cssText = 'background:' + a.headingBg + ';padding:7px 20px;border-top:1px solid ' + a.headingBorderColor + ';border-bottom:1px solid ' + a.headingBorderColor; |
| 81 |
if (si === 0 && !a.showTitle) secHead.style.borderTop = 'none'; |
| 82 |
var headLabel = tx('span', null, sec.heading); |
| 83 |
headLabel.style.cssText = 'font-size:' + a.headingFontSize + 'px;font-weight:700;color:' + a.headingColor + ';text-transform:uppercase;letter-spacing:0.07em'; |
| 84 |
ap(secHead, headLabel); |
| 85 |
ap(section, secHead); |
| 86 |
|
| 87 |
sec.shortcuts.forEach(function (sc, sci) { |
| 88 |
var row = mk('div', 'bkbg-ks-row'); |
| 89 |
row.style.cssText = 'display:flex;align-items:center;justify-content:space-between;padding:9px 20px;gap:16px' + (sci > 0 ? ';border-top:1px solid ' + a.separatorColor : ''); |
| 90 |
|
| 91 |
var desc = tx('span', 'bkbg-ks-desc', sc.description); |
| 92 |
desc.style.cssText = 'color:' + a.descColor + ';flex:1'; |
| 93 |
ap(row, desc); |
| 94 |
|
| 95 |
var keysWrap = mk('div', 'bkbg-ks-keys-wrap'); |
| 96 |
keysWrap.style.cssText = 'display:flex;gap:' + (a.platform === 'both' ? '16px' : '0') + ';align-items:center;flex-shrink:0'; |
| 97 |
|
| 98 |
if (showMac && sc.macKeys) { |
| 99 |
var macCol = mk('div'); |
| 100 |
macCol.style.cssText = 'display:flex;flex-direction:column;align-items:flex-end;gap:2px'; |
| 101 |
if (a.platform === 'both') { |
| 102 |
var macLabel = tx('div', null, 'Mac'); |
| 103 |
macLabel.style.cssText = 'font-size:10px;color:' + a.macAccentColor + ';font-weight:600;text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px'; |
| 104 |
ap(macCol, macLabel); |
| 105 |
} |
| 106 |
var mkKeys = renderKeys(sc.macKeys, a); |
| 107 |
if (mkKeys) ap(macCol, mkKeys); |
| 108 |
ap(keysWrap, macCol); |
| 109 |
} |
| 110 |
if (showWin && sc.winKeys) { |
| 111 |
var winCol = mk('div'); |
| 112 |
winCol.style.cssText = 'display:flex;flex-direction:column;align-items:flex-end;gap:2px'; |
| 113 |
if (a.platform === 'both') { |
| 114 |
var winLabel = tx('div', null, 'Win'); |
| 115 |
winLabel.style.cssText = 'font-size:10px;color:' + a.winAccentColor + ';font-weight:600;text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px'; |
| 116 |
ap(winCol, winLabel); |
| 117 |
} |
| 118 |
var wKeys = renderKeys(sc.winKeys, a); |
| 119 |
if (wKeys) ap(winCol, wKeys); |
| 120 |
ap(keysWrap, winCol); |
| 121 |
} |
| 122 |
ap(row, keysWrap); |
| 123 |
ap(section, row); |
| 124 |
}); |
| 125 |
|
| 126 |
ap(wrap, section); |
| 127 |
}); |
| 128 |
|
| 129 |
appEl.innerHTML = ''; |
| 130 |
appEl.appendChild(wrap); |
| 131 |
} |
| 132 |
|
| 133 |
function init() { document.querySelectorAll('.bkbg-keyboard-shortcut-app').forEach(buildBlock); } |
| 134 |
if (document.readyState !== 'loading') { init(); } else { document.addEventListener('DOMContentLoaded', init); } |
| 135 |
})(); |
| 136 |
|