diff --git a/.eleventy.js b/.eleventy.js index 1e981d1..beb0859 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -14,6 +14,7 @@ module.exports = function(eleventyConfig) { html: true }) .use(require("markdown-it-footnote")) + .use(require("markdown-it-attrs")) .use(require('markdown-it-mathjax3'), { tex: { inlineMath: [ diff --git a/package-lock.json b/package-lock.json index 2a4b6cb..8c7adcd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "gray-matter": "^4.0.3", "lunr": "^2.3.9", "markdown-it": "^12.3.2", + "markdown-it-attrs": "^4.1.6", "markdown-it-footnote": "^3.0.3", "markdown-it-mathjax3": "^4.3.1", "markdown-it-plantuml": "^1.4.1", @@ -3420,6 +3421,17 @@ "markdown-it": "bin/markdown-it.js" } }, + "node_modules/markdown-it-attrs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-4.1.6.tgz", + "integrity": "sha512-O7PDKZlN8RFMyDX13JnctQompwrrILuz2y43pW2GagcwpIIElkAdfeek+erHfxUOlXWPsjFeWmZ8ch1xtRLWpA==", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "markdown-it": ">= 9.0.0" + } + }, "node_modules/markdown-it-footnote": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-3.0.3.tgz", @@ -8957,6 +8969,12 @@ } } }, + "markdown-it-attrs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-4.1.6.tgz", + "integrity": "sha512-O7PDKZlN8RFMyDX13JnctQompwrrILuz2y43pW2GagcwpIIElkAdfeek+erHfxUOlXWPsjFeWmZ8ch1xtRLWpA==", + "requires": {} + }, "markdown-it-footnote": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-3.0.3.tgz", diff --git a/package.json b/package.json index af9b980..f6f39cc 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "gray-matter": "^4.0.3", "lunr": "^2.3.9", "markdown-it": "^12.3.2", + "markdown-it-attrs": "^4.1.6", "markdown-it-footnote": "^3.0.3", "markdown-it-mathjax3": "^4.3.1", "markdown-it-plantuml": "^1.4.1", diff --git a/src/helpers/linkUtils.js b/src/helpers/linkUtils.js new file mode 100644 index 0000000..3b386d9 --- /dev/null +++ b/src/helpers/linkUtils.js @@ -0,0 +1,108 @@ +const wikilink = /\[\[(.*?\|.*?)\]\]/g +const internalLinkRegex = /href="\/(.*?)"/g; + + +function caselessCompare(a, b) { + return a.toLowerCase() === b.toLowerCase(); +} + +function extractLinks(content) { + return[...(content.match(wikilink) || []).map(link => ( + link.slice(2, -2) + .split("|")[0] + .replace(/.(md|markdown)\s?$/i, "") + .replace("\\", "") + .trim() + )), ...(content.match(internalLinkRegex) || []).map( + (link) => + link + .slice(6, -1) + .split("|")[0] + .replace(/.(md|markdown)\s?$/i, "") + .replace("\\", "") + .trim() + )]; +} + +function getBacklinks(data) { + const notes = data.collections.note; + if (!notes) { + return []; + } + const currentFileSlug = data.page.filePathStem.replace('/notes/', ''); + const currentURL = data.page.url; + + let backlinks = []; + let uniqueLinks = new Set(); + let counter = 1; + + for (const otherNote of notes) { + const noteContent = otherNote.template.frontMatter.content; + const backLinks = extractLinks(noteContent); + + if (!uniqueLinks.has(otherNote.url) && backLinks.some(link => caselessCompare(link, currentFileSlug) || + currentURL == link.split("#")[0])) { + let preview = noteContent.slice(0, 240); + backlinks.push({ + url: otherNote.url, + title: otherNote.data.page.fileSlug, + preview, + id: counter++ + }) + uniqueLinks.add(otherNote.url); + } + } + return backlinks; +} + +function getOutboundLinks(data, isHome=false){ + const notes = data.collections.note; + + + + if (!notes || notes.length == 0) { + return []; + } + + let currentNote; + if (isHome) { + currentNote = data.collections.gardenEntry && data.collections.gardenEntry[0]; + } else { + const currentFileSlug = data.page.filePathStem.replace('/notes/', ''); + currentNote = notes.find(x => x.data.page.filePathStem && caselessCompare(x.data.page.filePathStem.replace('/notes/', ''), currentFileSlug)); + } + + if (!currentNote) { + return []; + } + + let counter = 1; + let uniqueLinks = new Set(); + + const outboundLinks = extractLinks(currentNote.template.frontMatter.content); + let outbound = outboundLinks.map(fileslug => { + var outboundNote = notes.find(x => caselessCompare(x.data.page.filePathStem.replace("/notes/", ""), fileslug) || x.data.page.url == fileslug.split("#")[0]); + if (!outboundNote) { + return null; + } + if (!uniqueLinks.has(outboundNote.url)) { + + uniqueLinks.add(outboundNote.url); + return { + url: outboundNote.url, + title: outboundNote.data.page.fileSlug, + id: counter++, + }; + } else { + return null; + } + }).filter(x => x); + return outbound; +} + +exports.wikilink = wikilink; +exports.internalLinkRegex = internalLinkRegex; +exports.getBacklinks = getBacklinks; +exports.getOutboundLinks = getOutboundLinks; +exports.caselessCompare = caselessCompare; +exports.extractLinks = extractLinks; \ No newline at end of file diff --git a/src/site/index.11tydata.js b/src/site/index.11tydata.js index 21c20e0..5a39475 100644 --- a/src/site/index.11tydata.js +++ b/src/site/index.11tydata.js @@ -2,98 +2,18 @@ require("dotenv").config(); const settings = require("../helpers/constants"); -const wikilink = /\[\[(.*?\|.*?)\]\]/g - const markdownIt = require("markdown-it"); +const { getBacklinks, getOutboundLinks } = require("../helpers/linkUtils"); const md = markdownIt({ html: true, }).use(require("../helpers/utils").namedHeadingsFilter); -function caselessCompare(a, b) { - return a.toLowerCase() === b.toLowerCase(); -} - const allSettings = settings.ALL_NOTE_SETTINGS; module.exports = { eleventyComputed: { - backlinks: (data) => { - const notes = data.collections.note; - if (!notes) { - return []; - } - const currentFileSlug = data.page.filePathStem.replace('/notes/', ''); - - let backlinks = []; - let counter = 1; - - for (const otherNote of notes) { - const noteContent = otherNote.template.frontMatter.content; - - const outboundLinks = (noteContent.match(wikilink) || []).map(link => ( - link.slice(2, -2) - .split("|")[0] - .replace(/.(md|markdown)\s?$/i, "") - .replace("\\", "") - .trim() - )); - - if (outboundLinks.some(link => caselessCompare(link, currentFileSlug))) { - - let preview = noteContent.slice(0, 240); - backlinks.push({ - url: otherNote.url, - title: otherNote.data.page.fileSlug, - preview, - id: counter++ - }) - } - } - - return backlinks; - - }, - outbound: (data) => { - const notes = data.collections.note; - - if (!notes || notes.length == 0) { - return []; - } - - const currentNote = data.collections.gardenEntry && data.collections.gardenEntry[0]; - if (!currentNote) { - return []; - } - - - let counter = 1; - - const noteContent = currentNote.template.frontMatter.content; - - const outboundLinks = (noteContent.match(wikilink) || []).map(link => ( - link.slice(2, -2) - .split("|")[0] - .replace(/.(md|markdown)\s?$/i, "") - .replace("\\", "") - .trim() - )); - - let outbound = outboundLinks.map(fileslug => { - var outboundNote = notes.find(x => caselessCompare(x.data.page.filePathStem.replace("/notes/", ""), fileslug)); - if (!outboundNote) { - return null; - } - - return { - url: outboundNote.url, - title: outboundNote.data.page.fileSlug, - id: counter++ - } - }).filter(x => x); - - return outbound; - - }, + backlinks: (data) => getBacklinks(data), + outbound: (data) => getOutboundLinks(data, true), settings: (data) => { const currentnote = data.collections.gardenEntry && data.collections.gardenEntry[0]; if (currentnote && currentnote.data) { diff --git a/src/site/notes/notes.11tydata.js b/src/site/notes/notes.11tydata.js index ff26d7d..004846b 100644 --- a/src/site/notes/notes.11tydata.js +++ b/src/site/notes/notes.11tydata.js @@ -1,94 +1,14 @@ require("dotenv").config(); const settings = require("../../helpers/constants"); - -const wikilink = /\[\[(.*?\|.*?)\]\]/g - -function caselessCompare(a, b) { - return a.toLowerCase() === b.toLowerCase(); -} +const { getBacklinks, getOutboundLinks } = require("../../helpers/linkUtils"); const allSettings = settings.ALL_NOTE_SETTINGS; module.exports = { eleventyComputed: { - backlinks: (data) => { - const notes = data.collections.note; - if (!notes) { - return []; - } - const currentFileSlug = data.page.filePathStem.replace('/notes/', ''); - - let backlinks = []; - let counter = 1; - - for (const otherNote of notes) { - const noteContent = otherNote.template.frontMatter.content; - - const outboundLinks = (noteContent.match(wikilink) || []).map(link => ( - link.slice(2, -2) - .split("|")[0] - .replace(/.(md|markdown)\s?$/i, "") - .replace("\\", "") - .trim() - )); - - if (outboundLinks.some(link => caselessCompare(link, currentFileSlug))) { - - let preview = noteContent.slice(0, 240); - backlinks.push({ - url: otherNote.url, - title: otherNote.data.page.fileSlug, - preview, - id: counter++ - }) - } - } - - return backlinks; - - }, - outbound: (data) => { - const notes = data.collections.note; - const currentFileSlug = data.page.filePathStem.replace('/notes/', ''); - - if (!notes || notes.length == 0) { - return []; - } - - const currentNote = notes.find(x => x.data.page.filePathStem && caselessCompare(x.data.page.filePathStem.replace('/notes/', ''), currentFileSlug)); - if (!currentNote) { - return []; - } - - let counter = 1; - - const noteContent = currentNote.template.frontMatter.content; - - const outboundLinks = (noteContent.match(wikilink) || []).map(link => ( - link.slice(2, -2) - .split("|")[0] - .replace(/.(md|markdown)\s?$/i, "") - .replace("\\", "") - .trim() - )); - - let outbound = outboundLinks.map(fileslug => { - var outboundNote = notes.find(x => caselessCompare(x.data.page.filePathStem.replace("/notes/", ""), fileslug)); - if (!outboundNote) { - return null; - } - - return { - url: outboundNote.url, - title: outboundNote.data.page.fileSlug, - id: counter++ - } - }).filter(x => x); - - return outbound; - - }, + backlinks: (data) => getBacklinks(data), + outbound: (data) => getOutboundLinks(data), settings: (data) => { const noteSettings = {}; allSettings.forEach(setting => { diff --git a/src/site/styles/digital-garden-base.scss b/src/site/styles/digital-garden-base.scss index 29bdf11..67fde5e 100644 --- a/src/site/styles/digital-garden-base.scss +++ b/src/site/styles/digital-garden-base.scss @@ -40,6 +40,12 @@ body { div.translusion { border-left: 4px solid gray; padding-left: 10px; + position: relative; + .markdown-embed-link { + z-index: 99; + display: block; + width: auto !important; + } } .admonition-title {