Fixing "30 seconds of code"
Latest update:
In the past, the JS portion of 30 seconds of code was a single, big
README in a github repo. You can still browse an old revision, of
course. It was near perfect for a cursory inspection or a quick search.
In full conformance with all that's bright must fade adage, the
README was scraped away for an alternative version that looks like
this:
Why, why did they do that?
Thankfully, they put each code "snippet" into a separate .md file
(there are 511 of them), which means we can concatenate them in 1
gargantuan file & create a TOC. I thought about an absolute minimum
amount of code one would need for that & came up with this:
$ cat Makefile
$(if $(i),,$(error i= param is missing))
out := _out
$(out)/%.html: $(i)/%.md
@mkdir -p $(dir $@)
echo '<h2 id="$(title)">$(title)</h2>' > $@
pandoc $< -t html --no-highlight >> $@
title = $(notdir $(basename $@))
$(out)/30-seconds-of-code.html: template.html $(patsubst $(i)/%.md, $(out)/%.html, $(sort $(wildcard $(i)/*.md)))
cat $^ > $@
echo '</main>' >> $@
.DELETE_ON_ERROR:
(i
should be a path to a repo directory with .md files, e.g. make -j4 i=~/Downloads/30-seconds-of-code/snippets
)
This converts each .md file to its .html counterpart & prepends
template.html
to the result:
What's in the template file?
- a TOC generator that runs once after DOM is ready;
- a handler for the
<input>
element that filters the TOC according to
user's input;
- CSS for a 2-column layout.
There is nothing interesting about #3, hence I'm skipping it.
Items 1-2 could be accomplished using 3 trivial functions (look Ma, no
React!):
$ sed -n '/script/,$p' template.html
<script>
document.addEventListener('DOMContentLoaded', main)
function main() {
let list = mk_list()
document.querySelector('#toc input').oninput = evt => {
render(list, evt.target.value)
}
render(list)
}
function render(list, filter) {
document.querySelector('#toc__list').innerHTML = list(filter).map( v => {
return `<li><a href="#${v}">${v}</a></li>`
}).join`\n`
}
function mk_list() {
let h2s = [...document.querySelectorAll('h2')].map( v => v.innerText)
return query => {
return query ? h2s.filter( v => v.toLowerCase().indexOf(query.toLowerCase()) !== -1) : h2s
}
}
</script>
<nav id="toc"><div><input type="search"><ul id="toc__list"></ul></div></nav>
<main id="doc">
This is all fine & dandy, but 30 seconds of code has many more
interesting repos, like snippets of css or reactjs code. They share the
same lamentable fate with the js one--once being in a single readme,
they have converged lately on a single, badly-searchable website, that
displays 1 recipe per user's query.
The difference between the css/react snippets & the plain js ones is
in a necessity of a preview: if you see a tasty recipe for a "Donut
spinner", you'd like to see how the donut spins, before copying the
example into your editor.
In such cases, people oft resort to pasting code into one of "Online
IDE"s & embedding the result into their tutorial. CodePen, for
example, has even more convenient feature: you create a form (with a
POST request) that holds a field with a json-formatted string which
contains html/css/js assets. That way you can easily make a button
"check this out on codepen". The downside is that a user leaves your
page to play with the code.
Another way to show previews alongside the docs is to create an iframe
& inject all assets from a snipped into it--in this implementation you
don't rely on 3rd parties & the docs stay fully usable in off-line
scenarios (nobody actually needs that, but it sounds useful to have
as an option).
This requires greatly expanding the examples above: either we need 3
separate templates: one for js snippets, some other for css recipes &
a disheartening one for reactjs chunks; or we force a single template
act differently depending on a payload content.
For the latter approach, see this
repo.
Tags: ойті
Authors: ag