Move code rendering to the backend & frontend improvements (#176)

Added Chroma & Goldmark

Added Mermaidjs

More languages supported

Add default values for gist links input

Added copy code from markdown blocks
This commit is contained in:
Thomas Miceli
2023-12-19 02:47:14 +01:00
parent eff88711ea
commit 845e28dd59
24 changed files with 511 additions and 143 deletions

73
public/catppuccin-latte.css vendored Normal file
View File

@ -0,0 +1,73 @@
/* Error */ .chroma .err { color: #d20f39 }
/* LineLink */ .chroma .lnlinks { outline: none; text-decoration: none; color: inherit }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
/* LineHighlight */ .chroma .hl { color: #bcc0cc }
/* LineNumbersTable */ .chroma .lnt { white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #8c8fa1 }
/* LineNumbers */ .chroma .ln { white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #8c8fa1 }
/* Line */ .chroma .line { display: flex; }
/* Keyword */ .chroma .k { color: #8839ef }
/* KeywordConstant */ .chroma .kc { color: #fe640b }
/* KeywordDeclaration */ .chroma .kd { color: #d20f39 }
/* KeywordNamespace */ .chroma .kn { color: #179299 }
/* KeywordPseudo */ .chroma .kp { color: #8839ef }
/* KeywordReserved */ .chroma .kr { color: #8839ef }
/* KeywordType */ .chroma .kt { color: #d20f39 }
/* NameAttribute */ .chroma .na { color: #1e66f5 }
/* NameBuiltin */ .chroma .nb { color: #04a5e5 }
/* NameBuiltinPseudo */ .chroma .bp { color: #04a5e5 }
/* NameClass */ .chroma .nc { color: #df8e1d }
/* NameConstant */ .chroma .no { color: #df8e1d }
/* NameDecorator */ .chroma .nd { color: #1e66f5; font-weight: bold }
/* NameEntity */ .chroma .ni { color: #179299 }
/* NameException */ .chroma .ne { color: #fe640b }
/* NameFunction */ .chroma .nf { color: #1e66f5 }
/* NameFunctionMagic */ .chroma .fm { color: #1e66f5 }
/* NameLabel */ .chroma .nl { color: #04a5e5 }
/* NameNamespace */ .chroma .nn { color: #fe640b }
/* NameProperty */ .chroma .py { color: #fe640b }
/* NameTag */ .chroma .nt { color: #8839ef }
/* NameVariable */ .chroma .nv { color: #dc8a78 }
/* NameVariableClass */ .chroma .vc { color: #dc8a78 }
/* NameVariableGlobal */ .chroma .vg { color: #dc8a78 }
/* NameVariableInstance */ .chroma .vi { color: #dc8a78 }
/* NameVariableMagic */ .chroma .vm { color: #dc8a78 }
/* LiteralString */ .chroma .s { color: #40a02b }
/* LiteralStringAffix */ .chroma .sa { color: #d20f39 }
/* LiteralStringBacktick */ .chroma .sb { color: #40a02b }
/* LiteralStringChar */ .chroma .sc { color: #40a02b }
/* LiteralStringDelimiter */ .chroma .dl { color: #1e66f5 }
/* LiteralStringDoc */ .chroma .sd { color: #9ca0b0 }
/* LiteralStringDouble */ .chroma .s2 { color: #40a02b }
/* LiteralStringEscape */ .chroma .se { color: #1e66f5 }
/* LiteralStringHeredoc */ .chroma .sh { color: #9ca0b0 }
/* LiteralStringInterpol */ .chroma .si { color: #40a02b }
/* LiteralStringOther */ .chroma .sx { color: #40a02b }
/* LiteralStringRegex */ .chroma .sr { color: #179299 }
/* LiteralStringSingle */ .chroma .s1 { color: #40a02b }
/* LiteralStringSymbol */ .chroma .ss { color: #40a02b }
/* LiteralNumber */ .chroma .m { color: #fe640b }
/* LiteralNumberBin */ .chroma .mb { color: #fe640b }
/* LiteralNumberFloat */ .chroma .mf { color: #fe640b }
/* LiteralNumberHex */ .chroma .mh { color: #fe640b }
/* LiteralNumberInteger */ .chroma .mi { color: #fe640b }
/* LiteralNumberIntegerLong */ .chroma .il { color: #fe640b }
/* LiteralNumberOct */ .chroma .mo { color: #fe640b }
/* Operator */ .chroma .o { color: #04a5e5; font-weight: bold }
/* OperatorWord */ .chroma .ow { color: #04a5e5; font-weight: bold }
/* Comment */ .chroma .c { color: #9ca0b0; font-style: italic }
/* CommentHashbang */ .chroma .ch { color: #9ca0b0; font-style: italic }
/* CommentMultiline */ .chroma .cm { color: #9ca0b0; font-style: italic }
/* CommentSingle */ .chroma .c1 { color: #9ca0b0; font-style: italic }
/* CommentSpecial */ .chroma .cs { color: #9ca0b0; font-style: italic }
/* CommentPreproc */ .chroma .cp { color: #9ca0b0; font-style: italic }
/* CommentPreprocFile */ .chroma .cpf { color: #9ca0b0; font-weight: bold; font-style: italic }
/* GenericDeleted */ .chroma .gd { color: #d20f39; background-color: #ccd0da }
/* GenericEmph */ .chroma .ge { font-style: italic }
/* GenericError */ .chroma .gr { color: #d20f39 }
/* GenericHeading */ .chroma .gh { color: #fe640b; font-weight: bold }
/* GenericInserted */ .chroma .gi { color: #40a02b; background-color: #ccd0da }
/* GenericStrong */ .chroma .gs { font-weight: bold }
/* GenericSubheading */ .chroma .gu { color: #fe640b; font-weight: bold }
/* GenericTraceback */ .chroma .gt { color: #d20f39 }
/* GenericUnderline */ .chroma .gl { text-decoration: underline }

73
public/catppuccin-macchiato.css vendored Normal file
View File

@ -0,0 +1,73 @@
/* Error */ .chroma .err { color: #f38ba8 }
/* LineLink */ .chroma .lnlinks { outline: none; text-decoration: none; color: inherit }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
/* LineHighlight */ .chroma .hl { color: #45475a }
/* LineNumbersTable */ .chroma .lnt { white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f849c }
/* LineNumbers */ .chroma .ln { white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f849c }
/* Line */ .chroma .line { display: flex; }
/* Keyword */ .chroma .k { color: #cba6f7 }
/* KeywordConstant */ .chroma .kc { color: #fab387 }
/* KeywordDeclaration */ .chroma .kd { color: #f38ba8 }
/* KeywordNamespace */ .chroma .kn { color: #94e2d5 }
/* KeywordPseudo */ .chroma .kp { color: #cba6f7 }
/* KeywordReserved */ .chroma .kr { color: #cba6f7 }
/* KeywordType */ .chroma .kt { color: #f38ba8 }
/* NameAttribute */ .chroma .na { color: #89b4fa }
/* NameBuiltin */ .chroma .nb { color: #89dceb }
/* NameBuiltinPseudo */ .chroma .bp { color: #89dceb }
/* NameClass */ .chroma .nc { color: #f9e2af }
/* NameConstant */ .chroma .no { color: #f9e2af }
/* NameDecorator */ .chroma .nd { color: #89b4fa; font-weight: bold }
/* NameEntity */ .chroma .ni { color: #94e2d5 }
/* NameException */ .chroma .ne { color: #fab387 }
/* NameFunction */ .chroma .nf { color: #89b4fa }
/* NameFunctionMagic */ .chroma .fm { color: #89b4fa }
/* NameLabel */ .chroma .nl { color: #89dceb }
/* NameNamespace */ .chroma .nn { color: #fab387 }
/* NameProperty */ .chroma .py { color: #fab387 }
/* NameTag */ .chroma .nt { color: #cba6f7 }
/* NameVariable */ .chroma .nv { color: #f5e0dc }
/* NameVariableClass */ .chroma .vc { color: #f5e0dc }
/* NameVariableGlobal */ .chroma .vg { color: #f5e0dc }
/* NameVariableInstance */ .chroma .vi { color: #f5e0dc }
/* NameVariableMagic */ .chroma .vm { color: #f5e0dc }
/* LiteralString */ .chroma .s { color: #a6e3a1 }
/* LiteralStringAffix */ .chroma .sa { color: #f38ba8 }
/* LiteralStringBacktick */ .chroma .sb { color: #a6e3a1 }
/* LiteralStringChar */ .chroma .sc { color: #a6e3a1 }
/* LiteralStringDelimiter */ .chroma .dl { color: #89b4fa }
/* LiteralStringDoc */ .chroma .sd { color: #6c7086 }
/* LiteralStringDouble */ .chroma .s2 { color: #a6e3a1 }
/* LiteralStringEscape */ .chroma .se { color: #89b4fa }
/* LiteralStringHeredoc */ .chroma .sh { color: #6c7086 }
/* LiteralStringInterpol */ .chroma .si { color: #a6e3a1 }
/* LiteralStringOther */ .chroma .sx { color: #a6e3a1 }
/* LiteralStringRegex */ .chroma .sr { color: #94e2d5 }
/* LiteralStringSingle */ .chroma .s1 { color: #a6e3a1 }
/* LiteralStringSymbol */ .chroma .ss { color: #a6e3a1 }
/* LiteralNumber */ .chroma .m { color: #fab387 }
/* LiteralNumberBin */ .chroma .mb { color: #fab387 }
/* LiteralNumberFloat */ .chroma .mf { color: #fab387 }
/* LiteralNumberHex */ .chroma .mh { color: #fab387 }
/* LiteralNumberInteger */ .chroma .mi { color: #fab387 }
/* LiteralNumberIntegerLong */ .chroma .il { color: #fab387 }
/* LiteralNumberOct */ .chroma .mo { color: #fab387 }
/* Operator */ .chroma .o { color: #89dceb; font-weight: bold }
/* OperatorWord */ .chroma .ow { color: #89dceb; font-weight: bold }
/* Comment */ .chroma .c { color: #6c7086; font-style: italic }
/* CommentHashbang */ .chroma .ch { color: #6c7086; font-style: italic }
/* CommentMultiline */ .chroma .cm { color: #6c7086; font-style: italic }
/* CommentSingle */ .chroma .c1 { color: #6c7086; font-style: italic }
/* CommentSpecial */ .chroma .cs { color: #6c7086; font-style: italic }
/* CommentPreproc */ .chroma .cp { color: #6c7086; font-style: italic }
/* CommentPreprocFile */ .chroma .cpf { color: #6c7086; font-weight: bold; font-style: italic }
/* GenericDeleted */ .chroma .gd { color: #f38ba8; background-color: #313244 }
/* GenericEmph */ .chroma .ge { font-style: italic }
/* GenericError */ .chroma .gr { color: #f38ba8 }
/* GenericHeading */ .chroma .gh { color: #fab387; font-weight: bold }
/* GenericInserted */ .chroma .gi { color: #a6e3a1; background-color: #313244 }
/* GenericStrong */ .chroma .gs { font-weight: bold }
/* GenericSubheading */ .chroma .gu { color: #fab387; font-weight: bold }
/* GenericTraceback */ .chroma .gt { color: #f38ba8 }
/* GenericUnderline */ .chroma .gl { text-decoration: underline }

38
public/gist.ts Normal file
View File

@ -0,0 +1,38 @@
document.querySelectorAll<HTMLElement>('.table-code').forEach((el) => {
el.addEventListener('click', event => {
if (event.target && (event.target as HTMLElement).matches('.line-num')) {
Array.from(document.querySelectorAll('.table-code .selected')).forEach((el) => el.classList.remove('selected'));
const nextSibling = (event.target as HTMLElement).nextSibling;
if (nextSibling instanceof HTMLElement) {
nextSibling.classList.add('selected');
}
const filename = el.dataset.filenameSlug;
const line = (event.target as HTMLElement).textContent;
const url = location.protocol + '//' + location.host + location.pathname;
const hash = '#file-' + filename + '-' + line;
window.history.pushState(null, null, url + hash);
location.hash = hash;
}
});
});
let copybtnhtml = `<button type="button" style="top: 1em !important; right: 1em !important;" class="md-code-copy-btn absolute focus-within:z-auto rounded-md dark:border-gray-600 px-2 py-2 opacity-80 font-medium text-slate-700 bg-gray-100 dark:bg-gray-700 dark:text-slate-300 hover:bg-gray-200 dark:hover:bg-gray-600 hover:border-gray-500 hover:text-slate-700 dark:hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192.373-.03.748-.057 1.123-.08M15.75 18H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5A3.375 3.375 0 006.375 7.5H5.25m11.9-3.664A2.251 2.251 0 0015 2.25h-1.5a2.251 2.251 0 00-2.15 1.586m5.8 0c.065.21.1.433.1.664v.75h-6V4.5c0-.231.035-.454.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 00-9-9z" /></svg></button>`;
document.querySelectorAll<HTMLElement>('.markdown-body pre').forEach((el) => {
el.innerHTML = copybtnhtml + `<span class="code-div">` + el.innerHTML + `</span>`;
});
document.querySelectorAll('.md-code-copy-btn').forEach(button => {
button.addEventListener('click', function() {
let code = this.nextElementSibling.textContent;
navigator.clipboard.writeText(code).catch((err) => {
console.error('Could not copy text: ', err);
});
});
});

View File

@ -1,49 +0,0 @@
import hljs from 'highlight.js';
import md from 'markdown-it';
document.querySelectorAll('.markdown').forEach((e: HTMLElement) => {
e.innerHTML = md({
html: true,
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return '<pre class="hljs"><code>' +
hljs.highlight(str, {language: lang, ignoreIllegals: true}).value +
'</code></pre>';
} catch (__) {
}
}
return '<pre class="hljs"><code>' + md().utils.escapeHtml(str) + '</code></pre>';
}
}).render(e.textContent);
});
document.querySelectorAll<HTMLElement>('.table-code').forEach((el) => {
const ext = el.dataset.filename?.split('.').pop() || '';
if (hljs.getLanguage(ext) && ext !== 'txt') {
el.querySelectorAll<HTMLElement>('td.line-code').forEach((ell) => {
ell.classList.add('language-' + ext);
hljs.highlightElement(ell);
});
}
el.addEventListener('click', event => {
if (event.target && (event.target as HTMLElement).matches('.line-num')) {
Array.from(document.querySelectorAll('.table-code .selected')).forEach((el) => el.classList.remove('selected'));
const nextSibling = (event.target as HTMLElement).nextSibling;
if (nextSibling instanceof HTMLElement) {
nextSibling.classList.add('selected');
}
const filename = el.dataset.filenameSlug;
const line = (event.target as HTMLElement).textContent;
const url = location.protocol + '//' + location.host + location.pathname;
const hash = '#file-' + filename + '-' + line;
window.history.pushState(null, null, url + hash);
location.hash = hash;
}
});
});

20
public/style.css vendored
View File

@ -156,3 +156,23 @@ dl.dl-config dd {
.markdown-body {
@apply dark:bg-gray-900 !important;
}
.markdown-body pre {
@apply flex relative items-start p-0 !important;
}
.markdown-body .code-div {
@apply p-4 max-w-full overflow-x-auto !important;
}
.markdown-body code {
@apply overflow-auto whitespace-pre !important;
}
.chroma.preview.markdown code {
@apply p-4 !important;
}
.mermaid {
background: #f6f8fa !important;
}

4
public/style.scss vendored
View File

@ -1,9 +1,9 @@
:root {
@import "github-markdown-css/github-markdown-light";
@import 'highlight.js/scss/base16/one-light.scss';
@import './catppuccin-latte';
}
.dark {
@import "github-markdown-css/github-markdown-dark";
@import 'highlight.js/scss/base16/onedark.scss';
@import './catppuccin-macchiato';
}