| 1 |
( function () { |
| 2 |
var el = wp.element.createElement; |
| 3 |
var __ = wp.i18n.__; |
| 4 |
var useBlockProps = wp.blockEditor.useBlockProps; |
| 5 |
var InspectorControls = wp.blockEditor.InspectorControls; |
| 6 |
var PanelColorSettings = wp.blockEditor.PanelColorSettings; |
| 7 |
var PanelBody = wp.components.PanelBody; |
| 8 |
var TextControl = wp.components.TextControl; |
| 9 |
var TextareaControl = wp.components.TextareaControl; |
| 10 |
var ToggleControl = wp.components.ToggleControl; |
| 11 |
var SelectControl = wp.components.SelectControl; |
| 12 |
var RangeControl = wp.components.RangeControl; |
| 13 |
var useRef = wp.element.useRef; |
| 14 |
var useEffect = wp.element.useEffect; |
| 15 |
|
| 16 |
function getTypographyControl() { return (window.bkbgTypographyControl || function () { return null; }); } |
| 17 |
function _tv() { var fn = window.bkbgTypoCssVars; return fn ? fn.apply(null, arguments) : {}; } |
| 18 |
|
| 19 |
var LANGS = [ |
| 20 |
{ label: 'JavaScript', value: 'javascript' }, |
| 21 |
{ label: 'TypeScript', value: 'typescript' }, |
| 22 |
{ label: 'PHP', value: 'php' }, |
| 23 |
{ label: 'Python', value: 'python' }, |
| 24 |
{ label: 'CSS', value: 'css' }, |
| 25 |
{ label: 'HTML', value: 'html' }, |
| 26 |
{ label: 'Bash / Shell', value: 'bash' }, |
| 27 |
{ label: 'SQL', value: 'sql' }, |
| 28 |
{ label: 'JSON', value: 'json' }, |
| 29 |
{ label: 'Ruby', value: 'ruby' }, |
| 30 |
{ label: 'Go', value: 'go' }, |
| 31 |
{ label: 'Rust', value: 'rust' }, |
| 32 |
{ label: 'Plain Text', value: 'text' } |
| 33 |
]; |
| 34 |
|
| 35 |
var THEMES = [ |
| 36 |
{ label: 'Dark (Catppuccin)', value: 'dark' }, |
| 37 |
{ label: 'Light', value: 'light' }, |
| 38 |
{ label: 'Dracula', value: 'dracula' }, |
| 39 |
{ label: 'GitHub', value: 'github' }, |
| 40 |
{ label: 'Custom', value: 'custom' } |
| 41 |
]; |
| 42 |
|
| 43 |
var THEME_PRESETS = { |
| 44 |
dark: { bgL: '#1e1e2e', bgR: '#1e2e1e', hdL: '#ff6b6b', hdR: '#6bcb77', hdColor: '#fff', code: '#cdd6f4', lineNum: '#6c7086', addBg: 'rgba(107,203,119,0.15)', remBg: 'rgba(255,107,107,0.15)' }, |
| 45 |
light: { bgL: '#fdf6e3', bgR: '#f0fff0', hdL: '#e06c75', hdR: '#27ae60', hdColor: '#fff', code: '#24292e', lineNum: '#999', addBg: 'rgba(39,174,96,0.12)', remBg: 'rgba(224,108,117,0.12)' }, |
| 46 |
dracula: { bgL: '#282a36', bgR: '#1a3028', hdL: '#ff5555', hdR: '#50fa7b', hdColor: '#f8f8f2', code: '#f8f8f2', lineNum: '#6272a4', addBg: 'rgba(80,250,123,0.12)', remBg: 'rgba(255,85,85,0.12)' }, |
| 47 |
github: { bgL: '#fff', bgR: '#f1fff1', hdL: '#ffd7d5', hdR: '#ccffd8', hdColor: '#1f2328', code: '#1f2328', lineNum: '#aaa', addBg: 'rgba(24,128,41,0.12)', remBg: 'rgba(164,14,38,0.12)' } |
| 48 |
}; |
| 49 |
|
| 50 |
// Minimal tokeniser — returns array of {type, text} |
| 51 |
function tokenize(code, lang) { |
| 52 |
if (lang === 'text') return [{ type: 'plain', text: code }]; |
| 53 |
|
| 54 |
var keywords = { |
| 55 |
javascript: 'break case catch class const continue debugger default delete do else enum export extends false finally for from function if import in instanceof let new null of return static super switch this throw true try typeof undefined var void while with yield async await', |
| 56 |
typescript: 'break case catch class const continue debugger default delete do else enum export extends false finally for from function if import in instanceof interface let namespace new null of return static super switch this throw true try type typeof undefined var void while with yield async await', |
| 57 |
php: 'echo print class function return if else elseif for foreach while do switch case break continue true false null new public private protected static abstract final try catch finally throw namespace use extends implements interface trait', |
| 58 |
python: 'False None True and as assert async await break class continue def del elif else except finally for from global if import in is lambda nonlocal not or pass raise return try while with yield', |
| 59 |
css: 'important', |
| 60 |
bash: 'if then else elif fi for while do done case esac in function return export readonly local true false', |
| 61 |
sql: 'SELECT FROM WHERE JOIN LEFT RIGHT INNER OUTER ON UPDATE INSERT INTO VALUES DELETE CREATE DROP TABLE ALTER ADD COLUMN AS GROUP BY ORDER HAVING LIMIT DISTINCT WITH UNION ALL SET AND OR NOT NULL IS IN EXISTS', |
| 62 |
ruby: 'BEGIN END __ENCODING__ __END__ __FILE__ __LINE__ alias and begin break case class def defined do else elsif end ensure false for if in module next nil not or raise redo rescue retry return self super then true undef unless until when while yield', |
| 63 |
go: 'break case chan const continue default defer else fallthrough for func go goto if import interface map package range return select struct switch type var nil true false', |
| 64 |
rust: 'as async await break const continue crate dyn else enum extern false fn for if impl in let loop match mod move mut pub ref return self Self static struct super trait true type unsafe use where while' |
| 65 |
}; |
| 66 |
var kw = (keywords[lang] || '').split(' ').filter(Boolean); |
| 67 |
|
| 68 |
var rules = [ |
| 69 |
{ type: 'string', re: /("""[\s\S]*?"""|'''[\s\S]*?'''|`[\s\S]*?`|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/ }, |
| 70 |
{ type: 'comment', re: /(\/\/[^\n]*|\/\*[\s\S]*?\*\/|#[^\n]*|--[^\n]*)/ }, |
| 71 |
{ type: 'number', re: /(\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b)/ }, |
| 72 |
{ type: 'operator', re: /([+\-*/%=<>!&|^~?:;,.()\[\]{}])/ }, |
| 73 |
{ type: 'keyword', re: new RegExp('\\b(' + (kw.length ? kw.join('|') : '__NONE__') + ')\\b') }, |
| 74 |
{ type: 'function', re: /\b([a-zA-Z_$][a-zA-Z0-9_$]*)(?=\s*\()/ }, |
| 75 |
{ type: 'tag', re: lang === 'html' ? /(<\/?\w[^>]*>)/ : null }, |
| 76 |
{ type: 'variable', re: lang === 'php' ? /(\$[a-zA-Z_]\w*)/ : null } |
| 77 |
].filter(function (r) { return r.re !== null; }); |
| 78 |
|
| 79 |
var tokens = []; |
| 80 |
var rest = code; |
| 81 |
while (rest.length) { |
| 82 |
var best = null, bestIdx = Infinity, bestLen = 0, bestType = 'plain'; |
| 83 |
for (var i = 0; i < rules.length; i++) { |
| 84 |
var m = rules[i].re.exec(rest); |
| 85 |
if (m && m.index < bestIdx) { |
| 86 |
best = m; bestIdx = m.index; bestLen = m[0].length; bestType = rules[i].type; |
| 87 |
} |
| 88 |
} |
| 89 |
if (!best) { tokens.push({ type: 'plain', text: rest }); break; } |
| 90 |
if (bestIdx > 0) tokens.push({ type: 'plain', text: rest.slice(0, bestIdx) }); |
| 91 |
tokens.push({ type: bestType, text: rest.slice(bestIdx, bestIdx + bestLen) }); |
| 92 |
rest = rest.slice(bestIdx + bestLen); |
| 93 |
} |
| 94 |
return tokens; |
| 95 |
} |
| 96 |
|
| 97 |
var TOKEN_COLORS = { |
| 98 |
plain: null, |
| 99 |
keyword: '#c792ea', |
| 100 |
string: '#c3e88d', |
| 101 |
comment: '#546e7a', |
| 102 |
number: '#f78c6c', |
| 103 |
operator: '#89ddff', |
| 104 |
function: '#82aaff', |
| 105 |
tag: '#f07178', |
| 106 |
variable: '#ffcb6b' |
| 107 |
}; |
| 108 |
|
| 109 |
function renderCode(code, lang, showLineNums, wrapLines, codeColor, lineNumColor, maxH, diffLinesArr, side) { |
| 110 |
var lines = code.split('\n'); |
| 111 |
var rows = lines.map(function (line, i) { |
| 112 |
var lineNum = i + 1; |
| 113 |
var tokens = tokenize(line, lang); |
| 114 |
var spans = tokens.map(function (t) { |
| 115 |
var style = TOKEN_COLORS[t.type] ? { color: TOKEN_COLORS[t.type] } : { color: codeColor }; |
| 116 |
return el('span', { style: style }, t.text); |
| 117 |
}); |
| 118 |
var isDiff = diffLinesArr.indexOf(i) !== -1; |
| 119 |
var marker = ''; |
| 120 |
if (isDiff && side === 'left') marker = el('span', { style: { color: '#ff6b6b', userSelect: 'none', marginRight: '6px' } }, '−'); |
| 121 |
if (isDiff && side === 'right') marker = el('span', { style: { color: '#6bcb77', userSelect: 'none', marginRight: '6px' } }, '+'); |
| 122 |
var diffBg = ''; |
| 123 |
if (isDiff && side === 'left') diffBg = 'rgba(255,107,107,0.13)'; |
| 124 |
if (isDiff && side === 'right') diffBg = 'rgba(107,203,119,0.13)'; |
| 125 |
return el('div', { |
| 126 |
key: i, |
| 127 |
style: { |
| 128 |
display: 'flex', alignItems: 'flex-start', backgroundColor: diffBg || undefined, |
| 129 |
whiteSpace: wrapLines ? 'pre-wrap' : 'pre', wordBreak: wrapLines ? 'break-word' : undefined, |
| 130 |
minHeight: '1.5em' |
| 131 |
} |
| 132 |
}, |
| 133 |
showLineNums && el('span', { |
| 134 |
style: { minWidth: '2.6em', textAlign: 'right', paddingRight: '1em', userSelect: 'none', color: lineNumColor, flexShrink: 0, fontSize: '0.85em', paddingTop: '1px' } |
| 135 |
}, lineNum), |
| 136 |
marker, |
| 137 |
el('span', { style: { flex: 1, color: codeColor } }, ...spans) |
| 138 |
); |
| 139 |
}); |
| 140 |
return el('div', { |
| 141 |
style: { |
| 142 |
overflowY: 'auto', overflowX: maxH ? 'auto' : undefined, |
| 143 |
maxHeight: maxH ? maxH + 'px' : undefined, |
| 144 |
padding: '14px 16px', |
| 145 |
fontSize: 'inherit', lineHeight: '1.6' |
| 146 |
} |
| 147 |
}, ...rows); |
| 148 |
} |
| 149 |
|
| 150 |
// ── Preview component ────────────────────────────────────────────────────── |
| 151 |
function ComparisonPreview(props) { |
| 152 |
var attr = props.attr; |
| 153 |
var splitL = attr.splitRatio; |
| 154 |
var splitR = 100 - splitL; |
| 155 |
|
| 156 |
var diffLinesArr = []; |
| 157 |
if (attr.diffLines && attr.diffLines.trim()) { |
| 158 |
attr.diffLines.split(',').forEach(function (s) { |
| 159 |
var n = parseInt(s.trim(), 10); |
| 160 |
if (!isNaN(n)) diffLinesArr.push(n - 1); |
| 161 |
}); |
| 162 |
} |
| 163 |
|
| 164 |
var paneStyle = function (bg) { return { |
| 165 |
flex: 1, backgroundColor: bg, overflow: 'hidden', fontFamily: '"Fira Code", "Cascadia Code", "JetBrains Mono", monospace' |
| 166 |
}; }; |
| 167 |
|
| 168 |
var headerStyle = function (hbg) { return { |
| 169 |
display: 'flex', alignItems: 'center', justifyContent: 'space-between', |
| 170 |
padding: '8px 14px', backgroundColor: hbg, color: attr.headerColor, fontSize: '12px', fontWeight: 700, letterSpacing: '0.06em' |
| 171 |
}; }; |
| 172 |
|
| 173 |
var typoVars = _tv(attr.typoCode, '--bkbg-cc-cd'); |
| 174 |
return el('div', { |
| 175 |
style: Object.assign({ |
| 176 |
display: 'flex', borderRadius: attr.borderRadius + 'px', overflow: 'hidden', |
| 177 |
position: 'relative' |
| 178 |
}, typoVars) |
| 179 |
}, |
| 180 |
el('div', { style: { ...paneStyle(attr.bgLeft), width: splitL + '%', flexShrink: 0, flexGrow: 0 } }, |
| 181 |
el('div', { style: headerStyle(attr.headerBgLeft) }, |
| 182 |
el('span', {}, attr.leftLabel), |
| 183 |
attr.showLanguageBadge && el('span', { style: { opacity: 0.8, fontWeight: 400 } }, attr.leftLang), |
| 184 |
attr.showCopyButtons && el('span', { |
| 185 |
style: { cursor: 'pointer', background: 'rgba(255,255,255,0.2)', borderRadius: '4px', padding: '2px 8px', fontSize: '10px' } |
| 186 |
}, 'Copy') |
| 187 |
), |
| 188 |
renderCode(attr.leftCode, attr.leftLang, attr.showLineNumbers, attr.wrapLines, attr.codeColor, attr.lineNumColor, attr.maxHeight, attr.showDiffMarkers ? diffLinesArr : [], 'left') |
| 189 |
), |
| 190 |
el('div', { style: { width: '3px', backgroundColor: 'rgba(128,128,128,0.3)', flexShrink: 0, cursor: 'col-resize' } }), |
| 191 |
el('div', { style: { ...paneStyle(attr.bgRight), width: splitR + '%', flexShrink: 0, flexGrow: 0 } }, |
| 192 |
el('div', { style: headerStyle(attr.headerBgRight) }, |
| 193 |
el('span', {}, attr.rightLabel), |
| 194 |
attr.showLanguageBadge && el('span', { style: { opacity: 0.8, fontWeight: 400 } }, attr.rightLang), |
| 195 |
attr.showCopyButtons && el('span', { |
| 196 |
style: { cursor: 'pointer', background: 'rgba(255,255,255,0.2)', borderRadius: '4px', padding: '2px 8px', fontSize: '10px' } |
| 197 |
}, 'Copy') |
| 198 |
), |
| 199 |
renderCode(attr.rightCode, attr.rightLang, attr.showLineNumbers, attr.wrapLines, attr.codeColor, attr.lineNumColor, attr.maxHeight, attr.showDiffMarkers ? diffLinesArr : [], 'right') |
| 200 |
) |
| 201 |
); |
| 202 |
} |
| 203 |
|
| 204 |
// ── Block registration ───────────────────────────────────────────────────── |
| 205 |
wp.blocks.registerBlockType('blockenberg/code-comparison', { |
| 206 |
title: 'Code Comparison', |
| 207 |
icon: 'editor-code', |
| 208 |
category: 'bkbg-dev', |
| 209 |
edit: function (props) { |
| 210 |
var attr = props.attributes; |
| 211 |
var setAttr = props.setAttributes; |
| 212 |
|
| 213 |
function applyTheme(themeKey) { |
| 214 |
if (themeKey === 'custom') return; |
| 215 |
var p = THEME_PRESETS[themeKey]; |
| 216 |
if (!p) return; |
| 217 |
setAttr({ bgLeft: p.bgL, bgRight: p.bgR, headerBgLeft: p.hdL, headerBgRight: p.hdR, headerColor: p.hdColor, codeColor: p.code, lineNumColor: p.lineNum, diffAddBg: p.addBg, diffRemBg: p.remBg }); |
| 218 |
} |
| 219 |
|
| 220 |
var blockProps = useBlockProps({ style: { fontFamily: 'inherit' } }); |
| 221 |
|
| 222 |
return el('div', blockProps, |
| 223 |
el(InspectorControls, {}, |
| 224 |
// Code panels |
| 225 |
el(PanelBody, { title: __('Left Pane (Before)', 'blockenberg'), initialOpen: true }, |
| 226 |
el(TextControl, { |
| 227 |
__nextHasNoMarginBottom: true, |
| 228 |
label: __('Label', 'blockenberg'), |
| 229 |
value: attr.leftLabel, |
| 230 |
onChange: function (v) { setAttr({ leftLabel: v }); } |
| 231 |
}), |
| 232 |
el(SelectControl, { |
| 233 |
__nextHasNoMarginBottom: true, |
| 234 |
label: __('Language', 'blockenberg'), |
| 235 |
value: attr.leftLang, |
| 236 |
options: LANGS, |
| 237 |
onChange: function (v) { setAttr({ leftLang: v }); } |
| 238 |
}), |
| 239 |
el(TextareaControl, { |
| 240 |
__nextHasNoMarginBottom: true, |
| 241 |
label: __('Code', 'blockenberg'), |
| 242 |
value: attr.leftCode, |
| 243 |
rows: 10, |
| 244 |
onChange: function (v) { setAttr({ leftCode: v }); } |
| 245 |
}) |
| 246 |
), |
| 247 |
el(PanelBody, { title: __('Right Pane (After)', 'blockenberg'), initialOpen: false }, |
| 248 |
el(TextControl, { |
| 249 |
__nextHasNoMarginBottom: true, |
| 250 |
label: __('Label', 'blockenberg'), |
| 251 |
value: attr.rightLabel, |
| 252 |
onChange: function (v) { setAttr({ rightLabel: v }); } |
| 253 |
}), |
| 254 |
el(SelectControl, { |
| 255 |
__nextHasNoMarginBottom: true, |
| 256 |
label: __('Language', 'blockenberg'), |
| 257 |
value: attr.rightLang, |
| 258 |
options: LANGS, |
| 259 |
onChange: function (v) { setAttr({ rightLang: v }); } |
| 260 |
}), |
| 261 |
el(TextareaControl, { |
| 262 |
__nextHasNoMarginBottom: true, |
| 263 |
label: __('Code', 'blockenberg'), |
| 264 |
value: attr.rightCode, |
| 265 |
rows: 10, |
| 266 |
onChange: function (v) { setAttr({ rightCode: v }); } |
| 267 |
}) |
| 268 |
), |
| 269 |
el(PanelBody, { title: __('Diff & Display', 'blockenberg'), initialOpen: false }, |
| 270 |
el(TextControl, { |
| 271 |
__nextHasNoMarginBottom: true, |
| 272 |
label: __('Highlighted Line Numbers (comma-separated)', 'blockenberg'), |
| 273 |
help: __('e.g. 2,5,7 — marks those lines as changed in both panes', 'blockenberg'), |
| 274 |
value: attr.diffLines, |
| 275 |
onChange: function (v) { setAttr({ diffLines: v }); } |
| 276 |
}), |
| 277 |
el(ToggleControl, { |
| 278 |
__nextHasNoMarginBottom: true, |
| 279 |
label: __('Show Diff Markers (+/−)', 'blockenberg'), |
| 280 |
checked: attr.showDiffMarkers, |
| 281 |
onChange: function (v) { setAttr({ showDiffMarkers: v }); } |
| 282 |
}), |
| 283 |
el(ToggleControl, { |
| 284 |
__nextHasNoMarginBottom: true, |
| 285 |
label: __('Line Numbers', 'blockenberg'), |
| 286 |
checked: attr.showLineNumbers, |
| 287 |
onChange: function (v) { setAttr({ showLineNumbers: v }); } |
| 288 |
}), |
| 289 |
el(ToggleControl, { |
| 290 |
__nextHasNoMarginBottom: true, |
| 291 |
label: __('Wrap Long Lines', 'blockenberg'), |
| 292 |
checked: attr.wrapLines, |
| 293 |
onChange: function (v) { setAttr({ wrapLines: v }); } |
| 294 |
}), |
| 295 |
el(ToggleControl, { |
| 296 |
__nextHasNoMarginBottom: true, |
| 297 |
label: __('Copy Buttons', 'blockenberg'), |
| 298 |
checked: attr.showCopyButtons, |
| 299 |
onChange: function (v) { setAttr({ showCopyButtons: v }); } |
| 300 |
}), |
| 301 |
el(ToggleControl, { |
| 302 |
__nextHasNoMarginBottom: true, |
| 303 |
label: __('Language Badge', 'blockenberg'), |
| 304 |
checked: attr.showLanguageBadge, |
| 305 |
onChange: function (v) { setAttr({ showLanguageBadge: v }); } |
| 306 |
}), |
| 307 |
el(ToggleControl, { |
| 308 |
__nextHasNoMarginBottom: true, |
| 309 |
label: __('Draggable Divider', 'blockenberg'), |
| 310 |
checked: attr.draggableSplit, |
| 311 |
onChange: function (v) { setAttr({ draggableSplit: v }); } |
| 312 |
}) |
| 313 |
), |
| 314 |
el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: false }, |
| 315 |
el(RangeControl, { |
| 316 |
__nextHasNoMarginBottom: true, |
| 317 |
label: __('Left Pane Width %', 'blockenberg'), |
| 318 |
value: attr.splitRatio, |
| 319 |
min: 20, max: 80, |
| 320 |
onChange: function (v) { setAttr({ splitRatio: v }); } |
| 321 |
}), |
| 322 |
el(RangeControl, { |
| 323 |
__nextHasNoMarginBottom: true, |
| 324 |
label: __('Max Height (0 = unlimited)', 'blockenberg'), |
| 325 |
value: attr.maxHeight, |
| 326 |
min: 0, max: 1000, step: 20, |
| 327 |
onChange: function (v) { setAttr({ maxHeight: v }); } |
| 328 |
}), |
| 329 |
el(RangeControl, { |
| 330 |
__nextHasNoMarginBottom: true, |
| 331 |
label: __('Border Radius (px)', 'blockenberg'), |
| 332 |
value: attr.borderRadius, |
| 333 |
min: 0, max: 32, |
| 334 |
onChange: function (v) { setAttr({ borderRadius: v }); } |
| 335 |
}) |
| 336 |
), |
| 337 |
el(PanelBody, { title: __('Theme', 'blockenberg'), initialOpen: false }, |
| 338 |
el(SelectControl, { |
| 339 |
__nextHasNoMarginBottom: true, |
| 340 |
label: __('Preset Theme', 'blockenberg'), |
| 341 |
value: attr.theme, |
| 342 |
options: THEMES, |
| 343 |
onChange: function (v) { setAttr({ theme: v }); applyTheme(v); } |
| 344 |
}) |
| 345 |
), |
| 346 |
|
| 347 |
el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false }, |
| 348 |
el(getTypographyControl(), { label: __('Code Text', 'blockenberg'), value: attr.typoCode, onChange: function (v) { setAttr({ typoCode: v }); } }), |
| 349 |
el(RangeControl, { |
| 350 |
__nextHasNoMarginBottom: true, |
| 351 |
label: __('Font Size (px)', 'blockenberg'), |
| 352 |
value: attr.fontSize, |
| 353 |
min: 10, max: 22, |
| 354 |
onChange: function (v) { setAttr({ fontSize: v }); } |
| 355 |
}) |
| 356 |
), |
| 357 |
el(PanelColorSettings, { |
| 358 |
title: __('Colors', 'blockenberg'), |
| 359 |
initialOpen: false, |
| 360 |
colorSettings: [ |
| 361 |
{ label: __('Left Pane Background', 'blockenberg'), value: attr.bgLeft, onChange: function (v) { setAttr({ bgLeft: v || '' }); } }, |
| 362 |
{ label: __('Right Pane Background', 'blockenberg'), value: attr.bgRight, onChange: function (v) { setAttr({ bgRight: v || '' }); } }, |
| 363 |
{ label: __('Left Header', 'blockenberg'), value: attr.headerBgLeft, onChange: function (v) { setAttr({ headerBgLeft: v || '' }); } }, |
| 364 |
{ label: __('Right Header', 'blockenberg'), value: attr.headerBgRight, onChange: function (v) { setAttr({ headerBgRight: v || '' }); } }, |
| 365 |
{ label: __('Header Text', 'blockenberg'), value: attr.headerColor, onChange: function (v) { setAttr({ headerColor: v || '' }); } }, |
| 366 |
{ label: __('Code Text', 'blockenberg'), value: attr.codeColor, onChange: function (v) { setAttr({ codeColor: v || '' }); } }, |
| 367 |
{ label: __('Line Number Color', 'blockenberg'), value: attr.lineNumColor, onChange: function (v) { setAttr({ lineNumColor: v || '' }); } } |
| 368 |
] |
| 369 |
}) |
| 370 |
), |
| 371 |
el(ComparisonPreview, { attr: attr }) |
| 372 |
); |
| 373 |
}, |
| 374 |
save: function (props) { |
| 375 |
var attr = props.attributes; |
| 376 |
return el('div', useBlockProps.save(), |
| 377 |
el('div', { |
| 378 |
className: 'bkbg-cc-app', |
| 379 |
'data-opts': JSON.stringify(attr) |
| 380 |
}) |
| 381 |
); |
| 382 |
} |
| 383 |
}); |
| 384 |
}() ); |
| 385 |
|