80 lines
3.0 KiB
JavaScript
80 lines
3.0 KiB
JavaScript
//
|
|
// render.js — assembles the HTML document Nova's preview tab will load.
|
|
//
|
|
// Nothing is rendered here. Markdown-to-HTML and Mermaid both need to run in a
|
|
// browser, and the preview tab is a real WebView, so this file only builds a
|
|
// shell: the Markdown source as data, plus the scripts that turn it into a page.
|
|
// That keeps the diagram code where a DOM exists, and keeps regeneration cheap
|
|
// — a save rewrites a few kilobytes, not a three-megabyte bundle.
|
|
//
|
|
|
|
/** Escapes a string for embedding in a <script type="application/json"> block. */
|
|
function embedJSON(value) {
|
|
return JSON.stringify(value)
|
|
.replace(/</g, "\\u003c")
|
|
.replace(/>/g, "\\u003e")
|
|
.replace(/&/g, "\\u0026")
|
|
.replace(/\u2028/g, "\\u2028")
|
|
.replace(/\u2029/g, "\\u2029");
|
|
}
|
|
|
|
function escapeHTML(text) {
|
|
return String(text)
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """);
|
|
}
|
|
|
|
/**
|
|
* Builds the preview document.
|
|
*
|
|
* @param {object} options
|
|
* @param {string} options.markdown Source text of the file being previewed.
|
|
* @param {string} options.title Tab and document title.
|
|
* @param {string} options.sourcePath Absolute path of the source file.
|
|
* @param {string} options.sourceRelDir Directory of the source file, relative to
|
|
* the generated HTML, so links and images
|
|
* in the Markdown still resolve.
|
|
* @param {string} options.assetsRelDir Assets directory, relative to the HTML.
|
|
* @param {string} options.mode "markdown" or "mermaid".
|
|
* @param {string} options.theme "auto", "light" or "dark".
|
|
* @param {number} options.contentWidth Max width of the text column, in pixels.
|
|
*/
|
|
function buildDocument(options) {
|
|
const data = {
|
|
markdown: options.markdown,
|
|
title: options.title,
|
|
sourcePath: options.sourcePath,
|
|
sourceRelDir: options.sourceRelDir,
|
|
mode: options.mode,
|
|
theme: options.theme,
|
|
generatedAt: Date.now(),
|
|
};
|
|
|
|
const assets = options.assetsRelDir;
|
|
|
|
return `<!DOCTYPE html>
|
|
<html lang="en" data-theme="${escapeHTML(options.theme)}">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="generator" content="Mermaid Preview for Nova">
|
|
<title>${escapeHTML(options.title)}</title>
|
|
<link rel="stylesheet" href="${escapeHTML(assets)}/preview.css">
|
|
<style>:root { --content-width: ${Number(options.contentWidth) || 860}px; }</style>
|
|
</head>
|
|
<body>
|
|
<main id="content" class="markdown-body" aria-busy="true"></main>
|
|
<div id="error" hidden></div>
|
|
<script type="application/json" id="preview-data">${embedJSON(data)}</script>
|
|
<script src="${escapeHTML(assets)}/vendor/markdown-it.min.js"></script>
|
|
<script src="${escapeHTML(assets)}/vendor/mermaid.min.js"></script>
|
|
<script src="${escapeHTML(assets)}/preview.js"></script>
|
|
</body>
|
|
</html>
|
|
`;
|
|
}
|
|
|
|
module.exports = { buildDocument };
|