A book about creating news graphics for the web, targeting modern browsers.
There aren't any dependencies, and hardly any infrastructure to speak of. Source files are in src/
, and output goes in docs/
so that GitHub Pages can see it without maintaining a separate branch. Use npm run build
to rebuild after making changes. There's a docs/static
folder that's not touched, where you can keep images and stylesheets.
I recommend running a server in a second terminal or a tmux session from the output folder, so that you don't have to worry about the security sandbox, but pretty much everything should work from a file:// URL anyway.
The table of contents is generated from toc.json
, which contains an array of references to chapters and sections by filename. If you want to add a placeholder, you can just write in a string, and it'll echo that back out when it builds the TOC file.
Yeah, I made a new document format. Sorry. I like RST a lot, but there's no good Node libraries for it, and if I started writing a parser I'd never get the actual book done. I was inspired in part by Pollen, but of course I wasn't going to write the book in Racket. So I made something new, but at least I didn't dignify it with a goofy name.
For the most part, the inline format of a .text file is just HTML. It's a pretty good language. You don't have to wrap individual paragraphs in <p>
tags, it will do that for you. It'll also automatically create lists for any block of lines starting with *
or -
.
If you want to do something more special, you can use a @tag
to trigger some special behavior. Tags can be a single line:
@subhead Hello, this will produce a subhead
Or they can be multiple lines, with an argument in parentheses and content surrounded by ellipses:
@codeblock(html)... <b>Outputs a block of code, with HTML characters escaped</b> ...codeblock
It's easy to extend the tag system, since the directives are just JavaScript functions stored in scripts/directives.js
. Each function is passed three arguments: a context
object that contains shared data for the page, a content object with lines
and arg
values, and a process
function that you can call to parse sub-tags recursively. The function should return a string, which will be substituted for the directive during templating. For example, here's the code for the @sidebar
directive:
exports.sidebar = (context, { lines }, process) => `<aside class="sidebar"> ${process(lines).join("\n")} </aside>`;
@metadata
- Starts each page and sets up additional context values for templating. Each line is a new entry, formatted as "key:value".@paragraph
- You don't need to call this, it'll be run for you whenever there's a top-level paragraph not in a block of some kind.@html
- Lets you write multi-line raw HTML without triggering the automatic paragraph tags.@ul
- You don't need to call this either, it triggers when the parser sees a list block.@subhead
- Inserts a subhead, which is currently an<h2>
but in the future who knows.@codeblock
- You'll see a lot of these, they're used for code listings. HTML characters are escaped for display.@sidebar
- Pretty self-explanatory.@include
- Load a file into the page as raw content. Usually used to import interactive examples fromsrc/snippets
.
The content from the parsed .text files is loaded into template files from the (surprise!) templates/
folder. These files aren't processed for directives, but they do have various values injected using {{mustache}} tags. If you set a value in the @metadata
block for a page, like the title, it'll be used to replace "{{title}}" wherever it appears in the page template. Other values, like the next/previous links at the top and bottom of the page, are ad-hoc and defined in code for the scripts/build.js
file. I'm sorry.