Basic refactoring.

This commit is contained in:
BurnyLlama 2021-08-07 10:46:48 +02:00
parent e5e0599bf6
commit 53bd81a8af
9 changed files with 78 additions and 55 deletions

View File

@ -15,9 +15,10 @@ article > header {
display: grid; display: grid;
place-items: center; place-items: center;
width: min(100%, 45ch); width: fit-content;
padding: 1rem 2rem; margin: 0 auto;
padding: 1rem 4rem;
background-color: var(--grey3); background-color: var(--grey3);
border-radius: .5rem; border-radius: .5rem;
box-shadow: 0 1rem 2rem var(--grey1); box-shadow: 0 1rem 2rem var(--grey1);

View File

@ -1,8 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> {% include "templates/defaultTags.njk" %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ serverName }} - Error 404</title> <title>{{ serverName }} - Error 404</title>
</head> </head>
<body> <body>

View File

@ -15,29 +15,33 @@ const Config = JSON.parse(ConfigFile)
// Create a server object
const Server = express() const Server = express()
// Some config // Configure the assets directory
Server.use('/assets', express.static(Config.assetsDir)) Server.use('/assets', express.static(Config.assetsDir))
// Configure the nunjucks environment (HTML templating)
const njkEnv = njk.configure( const njkEnv = njk.configure(
Config.contentDir, Config.contentDir,
{ {
autoescape: true, autoescape: true, // Automatically escape HTML aka a '<' will become '&lt;'
watch: true, watch: true, // Automatically reload all templates if they change on disk.
trimBlocks: true, trimBlocks: true, // Remove trailing newlines from tags
lstripBlocks: true, lstripBlocks: true, // Automatically remove leading whitespace from tags
express: Server express: Server // Use the express server. (Currently obsolete, I think.)
} }
) )
// Configure marked (markdown parser)
marked.use({ marked.use({
gfm: true, gfm: true, // Use GitHub formatting?
renderer: markedRenderer renderer: markedRenderer // Use my own custom rendering for som tags
}) })
// Let nunjucks use markdown.
njkMarkdown.register(njkEnv, marked) njkMarkdown.register(njkEnv, marked)

16
libs/codeHighlighter.js Normal file
View File

@ -0,0 +1,16 @@
import hljs from 'highlight.js'
export function highlight(code, lang) {
// Check if hljs recognises the language, else assume 'plaintext'.
const language = hljs.getLanguage(lang) ? lang : 'plaintext'
// Highlight it with the corresponding language.
return hljs.highlight(
// Switch out bullet points (•) to spaces (for proper indentation).
code.replace(/•/g, " "), { language })
// Replace newlines with <br> tags.
.value.replace(/\n/g, "<br>")
// Replace spaces with '&nbsp;' to forcefully render them.
.replace(/ /g, "&nbsp;"
)
}

View File

@ -7,7 +7,7 @@ export function parseExternalContext(externalContext) {
// If the line is falsey; leave. // If the line is falsey; leave.
if (!line) return if (!line) return
// Assign properties to parsedContext and give them values. // Assign properties to parsedContext and give them their corresponding values.
line = line.split(/:/) line = line.split(/:/)
parsedContext[line[0]] = line[1].replace(/^\s/, "") parsedContext[line[0]] = line[1].replace(/^\s/, "")
}) })

26
libs/generateContext.js Normal file
View File

@ -0,0 +1,26 @@
import { JSDOM } from 'jsdom'
import { parseExternalContext } from './externalContext.js'
function generateToc(dom) {
// Get all ToC anchors from the DOM
const tocAnchors = dom.window.document.querySelectorAll(".toc-anchor")
// Generate links to lead to those anvhors.
let tocLinks = []
tocAnchors.forEach(anchor => tocLinks.push(`<a href="#${anchor.name}" class="${anchor.classList[1].replace("-anchor", "")}">${anchor.getAttribute('data-orig-text')}</a>`))
return tocLinks
}
export function generateContext(prerenderedNjk, externalContext = undefined) {
// Create a 'virtual DOM' for analysis.
const dom = new JSDOM(prerenderedNjk)
// Generate respective parts of the context.
return {
serverName: Config.serverName,
tocLinks: generateToc(dom),
externalMeta: externalContext ? parseExternalContext(externalContext) : undefined
}
}

View File

@ -1,15 +1,7 @@
import hljs from 'highlight.js' import { highlight } from "./codeHighlighter.js"
function highlight(code, lang) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext'
return hljs.highlight(
code.replace(/•/g, " "), { language })
.value.replace(/\n/g, "<br>")
.replace(/ /g, "&nbsp;"
)
}
export const markedRenderer = { export const markedRenderer = {
// Rendering of headings (add an anchor above all headings).
heading(text, level) { heading(text, level) {
return ` return `
<a name="${text.replace(/\s/g, "-")}" data-orig-text="${text}" class="toc-anchor toc-anchor-h${level}"></a> <a name="${text.replace(/\s/g, "-")}" data-orig-text="${text}" class="toc-anchor toc-anchor-h${level}"></a>
@ -19,6 +11,7 @@ export const markedRenderer = {
` `
}, },
// Render code properly, and syntax highlight it.
code(code, lang, escaped) { code(code, lang, escaped) {
return ` return `
<pre> <pre>

View File

@ -1,19 +1,21 @@
import fs from 'fs' import fs from 'fs'
import { mdRenderer, njkRenderer } from './siteRenderer.js' import { mdRenderer, njkRenderer } from './siteRenderer.js'
// Handle all request and try to find a corresponding file/template.
export function requestHandler(req, res, Config) { export function requestHandler(req, res, Config) {
// Check for njk files first
if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}.njk`)) if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}.njk`))
return res.send(njkRenderer(`./${Config.contentDir}/pages/${req.path}.njk`)) return res.send(njkRenderer(`./${Config.contentDir}/pages/${req.path}.njk`))
if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}/index.njk`)) if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}/index.njk`))
return res.send(njkRenderer(`./${Config.contentDir}/pages/${req.path}/index.njk`)) return res.send(njkRenderer(`./${Config.contentDir}/pages/${req.path}/index.njk`))
// Secondly search for markdown
if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}.md`)) if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}.md`))
return res.send(mdRenderer(`./${Config.contentDir}/pages/${req.path}.md`)) return res.send(mdRenderer(`./${Config.contentDir}/pages/${req.path}.md`))
if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}/index.md`)) if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}/index.md`))
return res.send(mdRenderer(`./${Config.contentDir}/pages/${req.path}/index.md`)) return res.send(mdRenderer(`./${Config.contentDir}/pages/${req.path}/index.md`))
// If no matching file is found, return a 404 error.
return res.status(404).send(njkRenderer(`./${Config.contentDir}/errors/404.njk`)) return res.status(404).send(njkRenderer(`./${Config.contentDir}/errors/404.njk`))
} }

View File

@ -1,38 +1,19 @@
import fs from 'fs' import fs from 'fs'
import njk from 'nunjucks' import njk from 'nunjucks'
import { JSDOM } from 'jsdom' import { generateContext } from './generateContext.js'
import { parseExternalContext } from './externalContext.js'
// Load in config // Load in config
const ConfigFile = fs.readFileSync('./config.json') const ConfigFile = fs.readFileSync('./config.json')
const Config = JSON.parse(ConfigFile) const Config = JSON.parse(ConfigFile)
function generateToc(dom) {
const tocAnchors = dom.window.document.querySelectorAll(".toc-anchor")
let tocLinks = []
// This basically creates a proper link for the ToC. :)))
tocAnchors.forEach(anchor => tocLinks.push(`<a href="#${anchor.name}" class="${anchor.classList[1].replace("-anchor", "")}">${anchor.getAttribute('data-orig-text')}</a>`))
return tocLinks
}
function generateContext(renderedNjk, externalContext = undefined) {
const dom = new JSDOM(renderedNjk)
return {
serverName: Config.serverName,
tocLinks: generateToc(dom),
externalMeta: externalContext ? parseExternalContext(externalContext) : undefined
}
}
export function njkRenderer(path) { export function njkRenderer(path) {
// Read in the template
const njkFile = fs.readFileSync(path).toString() const njkFile = fs.readFileSync(path).toString()
const renderedNjk = njk.renderString(njkFile) // Pre-render it for analysis while rendering context
const prerenderedNjk = njk.renderString(njkFile)
const context = generateContext(renderedNjk)
// Generate proper context and make a final render of the template.
const context = generateContext(prerenderedNjk)
return njk.renderString(njkFile, context) return njk.renderString(njkFile, context)
} }
@ -45,10 +26,11 @@ export function mdRenderer(path) {
const externalMarkdown = externalMarkdownFile.replace(/^%%-\n[\S\s]*-%%\n/, "").replace(/```\w*[\s\S]*?```/g, match => match.replace(/ /g, "•")) const externalMarkdown = externalMarkdownFile.replace(/^%%-\n[\S\s]*-%%\n/, "").replace(/```\w*[\s\S]*?```/g, match => match.replace(/ /g, "•"))
const externalContext = externalMarkdownFile.match(/^%%-\n[\S\s]*-%%\n/)[0] const externalContext = externalMarkdownFile.match(/^%%-\n[\S\s]*-%%\n/)[0]
const renderedNjk = njk.renderString(njkFile, { externalMarkdown }) // Pre-render the template for analysis during context generation.
const prerenderedNjk = njk.renderString(njkFile, { externalMarkdown })
let context = generateContext(renderedNjk, externalContext) // Generate the context and add the externalMarkdown to the context, then render the template.
let context = generateContext(prerenderedNjk, externalContext)
context.externalMarkdown = externalMarkdown context.externalMarkdown = externalMarkdown
return njk.renderString(njkFile, context) return njk.renderString(njkFile, context)
} }