Extending gatsby-remark-embed-gist to support line selection
For years i've battled with Wordpress to manage my content, it was full of bloatware and it became demotivating to use. WP is also expensive to run compared to Gatsby which is a statically generated bundle of files that can be hosted behind a CDN for cheap, fast, global access.
I stumbled across Gatsby and I was hooked. I get to write my content in Markdown and the gatsby-transformer-remark
plugin translates that into HTML.
For my site I needed to be able to include short snippets of code from GitHub. Luckily Patricio Treviño had already created a plugin that lets you embed a Gist gatsby-remark-embed-gist
This plugin allows you to highlight lines but I also needed to be able to include only specific lines. This feature is not native to the Gist API, but I found some comments online that suggested it was possible with Javascript.
Digging into the code, I found that the highlight feature works by adding a class to the DOM node of the lines that are chosen to be highlighted.
▼ gist:botoxparty/3eaf29fbb8b69e52fd2f27d6d2e7dcd3#index.js?lines=64-73,153-157
// explode the highlights ranges, if any | |
let highlights = []; | |
if (typeof query.highlights === "string") { | |
highlights = rangeParser.parse(query.highlights); | |
} else if (Array.isArray(query.highlights)) { | |
highlights = query.highlights; | |
} | |
query.highlights = highlights; | |
if (hasHighlights) { | |
query.highlights.forEach(line => { | |
$(`#file-${file}-LC${line}`).addClass("highlighted"); | |
}); | |
} |
So we need to remove certain lines, we can use that same process to remove DOM nodes too!
▼ gist:botoxparty/3eaf29fbb8b69e52fd2f27d6d2e7dcd3#index.js?highlights=74-81,159-170&lines=64-82,143-171
// explode the highlights ranges, if any | |
let highlights = []; | |
if (typeof query.highlights === "string") { | |
highlights = rangeParser.parse(query.highlights); | |
} else if (Array.isArray(query.highlights)) { | |
highlights = query.highlights; | |
} | |
query.highlights = highlights; | |
// get the range of lines to display | |
let lines = []; | |
if (typeof query.lines === "string") { | |
lines = rangeParser.parse(query.lines); | |
} else if (Array.isArray(query.lines)) { | |
lines = query.lines; | |
} | |
query.lines = lines; | |
const hasHighlights = query.highlights.length > 0; | |
const hasLines = query.lines.length > 0; | |
if (hasHighlights || hasLines) { | |
const $ = cheerio.load(html); | |
const file = query.file | |
? query.file.replace(/[^a-zA-Z0-9_]+/g, "-").toLowerCase() | |
: ""; | |
// highlight the specify lines, if any | |
if (hasHighlights) { | |
query.highlights.forEach(line => { | |
$(`#file-${file}-LC${line}`).addClass("highlighted"); | |
}); | |
} | |
// remove the specific lines, if any | |
if (hasLines) { | |
const codeLines = rangeParser.parse(`1-${$("table tr").length}`); | |
codeLines.forEach(line => { | |
if (query.lines.includes(line)) { | |
return; | |
} | |
$(`#file-${file}-LC${line}`) | |
.parent() | |
.remove(); | |
}); | |
} | |