From dbcb73ad49a36463d0a4618b2c985ca637a48341 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sat, 25 Oct 2025 14:36:23 -0300 Subject: content, css: transformContent: fenced code blocks --- src/content/dependencies/transformContent.js | 67 ++++++++++++++++++++++------ src/static/css/site.css | 16 +++++++ 2 files changed, 69 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js index db9f5d99..e6d847fa 100644 --- a/src/content/dependencies/transformContent.js +++ b/src/content/dependencies/transformContent.js @@ -29,6 +29,28 @@ const commonMarkedOptions = { const multilineMarked = new Marked({ ...commonMarkedOptions, + + renderer: { + code({text}) { + let lines = text + .replace(/^\n+/, '') + .replace(/\n+$/, '') + .split('\n'); + + lines = lines + .map(line => line + .replace(/^ +/, spaces => ' '.repeat(spaces.length)) + .replaceAll(/ {2,}/g, spaces => ' '.repeat(spaces.length))); + + return ( + `
` +
+        (lines.length > 1 ? '\n' : '') +
+        lines.join('
\n') + + (lines.length > 1 ? '\n' : '') + + `
` + ); + }, + }, }); const inlineMarked = new Marked({ @@ -867,20 +889,37 @@ export default { // This is separated into its own function just since we're gonna reuse // it in a minute if everything goes to heck in lyrics mode. const transformMultiline = () => { - const markedInput = - extractNonTextNodes() - // Compress multiple line breaks into single line breaks, - // except when they're preceding or following indented - // text (by at least two spaces) or blockquotes. - .replace(/(?.*)\n{2,}(?!^ |^>)/gm, '\n') /* eslint-disable-line no-regex-spaces */ - // Expand line breaks which don't follow a list, quote, - // or
/ " ", and which don't precede or follow - // indented text (by at least two spaces). - .replace(/(?.*|^ .*\n*| $|
$)\n+(?! |\n)/gm, '\n\n') /* eslint-disable-line no-regex-spaces */ - // Expand line breaks which are at the end of a list. - .replace(/(?<=^ *(?:-|\d+\.).*)\n+(?!^ *(?:-|\d+\.))/gm, '\n\n') - // Expand line breaks which are at the end of a quote. - .replace(/(?<=^>.*)\n+(?!^>)/gm, '\n\n'); + let fencedCode = []; + + const fencedCodePlaceholder = + ``; + + let markedInput = extractNonTextNodes(); + + markedInput = markedInput + .replaceAll(/```(?:[\s\S](?!```))*\n```/g, (match) => { + fencedCode.push(match); + return fencedCodePlaceholder; + }); + + markedInput = markedInput + // Compress multiple line breaks into single line breaks, + // except when they're preceding or following indented + // text (by at least two spaces) or blockquotes. + .replace(/(?.*)\n{2,}(?!^ |^>)/gm, '\n') /* eslint-disable-line no-regex-spaces */ + // Expand line breaks which don't follow a list, quote, + // or
/ " ", and which don't precede or follow + // indented text (by at least two spaces). + .replace(/(?.*|^ .*\n*| $|
$)\n+(?! |\n)/gm, '\n\n') /* eslint-disable-line no-regex-spaces */ + // Expand line breaks which are at the end of a list. + .replace(/(?<=^ *(?:-|\d+\.).*)\n+(?!^ *(?:-|\d+\.))/gm, '\n\n') + // Expand line breaks which are at the end of a quote. + .replace(/(?<=^>.*)\n+(?!^>)/gm, '\n\n'); + + fencedCode = fencedCode.reverse(); + + markedInput = markedInput + .replaceAll(fencedCodePlaceholder, () => fencedCode.pop()); const markedOutput = multilineMarked.parse(markedInput); diff --git a/src/static/css/site.css b/src/static/css/site.css index 61803c9d..4998b799 100644 --- a/src/static/css/site.css +++ b/src/static/css/site.css @@ -1554,6 +1554,22 @@ li:not(:first-child:last-child) .tooltip:where(:not(.cover-artwork .tooltip)), color: #fffb; } +pre.content-code { + white-space: normal; + background: black; + color: white; + padding: 5px; + max-width: calc(100vw - 180px); + overflow-x: scroll; + border: 1px dashed var(--primary-color); +} + +pre.content-code code { + font-size: 0.8em; + line-height: 1; + white-space: nowrap; +} + s.spoiler { display: inline-block; color: transparent; -- cgit 1.3.0-6-gf8a5