-
Notifications
You must be signed in to change notification settings - Fork 0
/
renderers.js
100 lines (82 loc) · 4 KB
/
renderers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
* @module renderers
*/
import * as shiki from './dist/index.browser.mjs';
import MarkdownIt from 'https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/+esm';
import markdownItFrontMatter from 'https://cdn.jsdelivr.net/npm/markdown-it-front-matter@0.2.3/+esm'
import { json as readJSON, text as readText } from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
import { createMetaTag } from './utils.js';
export let frontMatter;
export let currentTheme;
export let highlighter;
/**
* Renter a markdown file directly into the body of a page,
* optionally including open graph tags.
*
* @note Most "unfurlers" won't see the OG tags if dynamically rendered.
* I'm using the JSON frontmatter to keep track of stuff and to
* potentially provide parameterized (via HTTP query strings) experiments.
* It's super easy to change `renderFrontMatter` to `false` for "production"
* after I copy the rendered OG tags into `index.html` from DevTools "inspect".
* @param {string} markdownFile
* @param {string} theme
* @param {string[]} langs
* @param {boolean} renderFrontmatter
*/
export async function renderMarkdownInBody(
markdownFile,
theme,
langs = [ 'javascript', 'r', 'json', 'xml', 'html', 'console' ],
renderFrontmatter = true) {
currentTheme = await readJSON(`./themes/${theme}.json`);
const readHTML = new DOMParser();
const content = document.getElementById("content")
const highlighter = await shiki.getHighlighter({
theme: 'ayu-dark',
langs: [ 'js', 'r', 'json', 'xml', 'html', 'console' ]
});
const md = new MarkdownIt({
html: true,
highlight: (code, lang) => {
return highlighter.codeToHtml(code, { lang })
}
}).use(markdownItFrontMatter, async fm => {
// extract frontmatter and setup meta tags and title
frontMatter = JSON.parse(fm);
if (renderFrontmatter) {
const matterKeys = Object.keys(frontMatter);
const head = document.getElementsByTagName("head")[ 0 ];
if (matterKeys.includes("title")) {
document.title = frontMatter.title;
head.appendChild(createMetaTag("og:title", frontMatter.title))
head.appendChild(createMetaTag("twitter:title", frontMatter.title))
}
if (matterKeys.includes("og")) {
frontMatter.og.description && head.appendChild(createMetaTag("og:description", frontMatter.og.description))
frontMatter.og.description && head.appendChild(createMetaTag("twitter:description", frontMatter.og.description))
frontMatter.og.url && head.appendChild(createMetaTag("og:site", frontMatter.og.url))
frontMatter.og.site_name && head.appendChild(createMetaTag("og:site_name", frontMatter.og.site_name))
frontMatter.og.image.url && head.appendChild(createMetaTag("og:image:url", frontMatter.og.image.url))
frontMatter.og.image.width && head.appendChild(createMetaTag("og:image:width", frontMatter.og.image.width))
frontMatter.og.image.height && head.appendChild(createMetaTag("og:image:height", frontMatter.og.image.height))
frontMatter.og.image.alt && head.appendChild(createMetaTag("og:image:alt", frontMatter.og.image.alt))
}
if (matterKeys.includes("twitter")) {
frontMatter.twitter.site && head.appendChild(createMetaTag("twitter:site_name", frontMatter.twitter.site))
frontMatter.twitter.domain && head.appendChild(createMetaTag("twitter:domain", frontMatter.twitter.domain))
frontMatter.og.image.url && head.appendChild(createMetaTag("twitter:image", frontMatter.og.image.url))
frontMatter.og.image.url && head.appendChild(createMetaTag("twitter:card", "summary_large_image"))
}
head.appendChild(createMetaTag("article:published_time", new Date().toISOString()))
}
})
// parse the rest of the document and add it to the body
const mdContent = await readText(`md/${markdownFile}.md`);
const rendered = md.render(mdContent);
const contentParsed = readHTML.parseFromString(rendered, "text/html");
const bodyContent = contentParsed.getElementsByTagName("body")[ 0 ];
content.replaceChildren();
while (bodyContent.childNodes.length > 0) {
content.appendChild(bodyContent.childNodes[ 0 ]);
}
}