diff --git a/assets/css/article.css b/assets/css/article.css index 3a4c5a6..bf99285 100644 --- a/assets/css/article.css +++ b/assets/css/article.css @@ -15,9 +15,10 @@ article > header { display: grid; place-items: center; - width: min(100%, 45ch); + width: fit-content; - padding: 1rem 2rem; + margin: 0 auto; + padding: 1rem 4rem; background-color: var(--grey3); border-radius: .5rem; box-shadow: 0 1rem 2rem var(--grey1); diff --git a/content/errors/404.njk b/content/errors/404.njk index 72498fe..93e56b5 100644 --- a/content/errors/404.njk +++ b/content/errors/404.njk @@ -1,8 +1,7 @@ - - + {% include "templates/defaultTags.njk" %} {{ serverName }} - Error 404 diff --git a/index.js b/index.js index 93aafe6..f928620 100644 --- a/index.js +++ b/index.js @@ -15,29 +15,33 @@ const Config = JSON.parse(ConfigFile) +// Create a server object const Server = express() -// Some config +// Configure the assets directory Server.use('/assets', express.static(Config.assetsDir)) +// Configure the nunjucks environment (HTML templating) const njkEnv = njk.configure( Config.contentDir, { - autoescape: true, - watch: true, - trimBlocks: true, - lstripBlocks: true, - express: Server + autoescape: true, // Automatically escape HTML aka a '<' will become '<' + watch: true, // Automatically reload all templates if they change on disk. + trimBlocks: true, // Remove trailing newlines from tags + lstripBlocks: true, // Automatically remove leading whitespace from tags + express: Server // Use the express server. (Currently obsolete, I think.) } ) +// Configure marked (markdown parser) marked.use({ - gfm: true, - renderer: markedRenderer + gfm: true, // Use GitHub formatting? + renderer: markedRenderer // Use my own custom rendering for som tags }) +// Let nunjucks use markdown. njkMarkdown.register(njkEnv, marked) diff --git a/libs/codeHighlighter.js b/libs/codeHighlighter.js new file mode 100644 index 0000000..7b1a51a --- /dev/null +++ b/libs/codeHighlighter.js @@ -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
tags. + .value.replace(/\n/g, "
") + // Replace spaces with ' ' to forcefully render them. + .replace(/ /g, " " + ) +} \ No newline at end of file diff --git a/libs/externalContext.js b/libs/externalContext.js index 8e5d2dc..dc82a1a 100644 --- a/libs/externalContext.js +++ b/libs/externalContext.js @@ -1,13 +1,13 @@ export function parseExternalContext(externalContext) { // Remove start and end tag externalContext = externalContext.replace(/%%-\n|-%%\n/g, "") - + let parsedContext = {} externalContext.split("\n").forEach(line => { // If the line is falsey; leave. if (!line) return - // Assign properties to parsedContext and give them values. + // Assign properties to parsedContext and give them their corresponding values. line = line.split(/:/) parsedContext[line[0]] = line[1].replace(/^\s/, "") }) diff --git a/libs/generateContext.js b/libs/generateContext.js new file mode 100644 index 0000000..5f35ef8 --- /dev/null +++ b/libs/generateContext.js @@ -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(`${anchor.getAttribute('data-orig-text')}`)) + + 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 + } +} + diff --git a/libs/markedRenderer.js b/libs/markedRenderer.js index 3c17982..a19789b 100644 --- a/libs/markedRenderer.js +++ b/libs/markedRenderer.js @@ -1,15 +1,7 @@ -import hljs from 'highlight.js' - -function highlight(code, lang) { - const language = hljs.getLanguage(lang) ? lang : 'plaintext' - return hljs.highlight( - code.replace(/•/g, " "), { language }) - .value.replace(/\n/g, "
") - .replace(/ /g, " " - ) -} +import { highlight } from "./codeHighlighter.js" export const markedRenderer = { + // Rendering of headings (add an anchor above all headings). heading(text, level) { return ` @@ -19,6 +11,7 @@ export const markedRenderer = { ` }, + // Render code properly, and syntax highlight it. code(code, lang, escaped) { return `
diff --git a/libs/requestHandler.js b/libs/requestHandler.js
index 8dd7787..4cb0d58 100644
--- a/libs/requestHandler.js
+++ b/libs/requestHandler.js
@@ -1,19 +1,21 @@
 import fs from 'fs'
 import { mdRenderer, njkRenderer } from './siteRenderer.js'
 
+
+// Handle all request and try to find a corresponding file/template.
 export function requestHandler(req, res, Config) {
+    // Check for njk files first
     if (fs.existsSync(`./${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`))
         return res.send(njkRenderer(`./${Config.contentDir}/pages/${req.path}/index.njk`))
 
+    // Secondly search for markdown
     if (fs.existsSync(`./${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`))
         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`))
 }
\ No newline at end of file
diff --git a/libs/siteRenderer.js b/libs/siteRenderer.js
index 259a277..e86e008 100644
--- a/libs/siteRenderer.js
+++ b/libs/siteRenderer.js
@@ -1,38 +1,19 @@
 import fs from 'fs'
 import njk from 'nunjucks'
-import { JSDOM } from 'jsdom'
-import { parseExternalContext } from './externalContext.js'
+import { generateContext } from './generateContext.js'
 
 // Load in config
 const ConfigFile = fs.readFileSync('./config.json')
 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(`${anchor.getAttribute('data-orig-text')}`))
-
-    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) {
+    // Read in the template
     const njkFile = fs.readFileSync(path).toString()
-    const renderedNjk = njk.renderString(njkFile)
-
-    const context = generateContext(renderedNjk)
+    // Pre-render it for analysis while rendering context
+    const prerenderedNjk = njk.renderString(njkFile)
 
+    // Generate proper context and make a final render of the template.
+    const context = generateContext(prerenderedNjk)
     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 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
-
     return njk.renderString(njkFile, context)
 }
\ No newline at end of file