use cli to pass in CSS vars

This commit is contained in:
Talon Poole 2021-01-29 22:32:30 +00:00
parent 13a885ee11
commit 990667c2a7
4 changed files with 104 additions and 81 deletions

58
cli.js
View file

@ -5,10 +5,33 @@ const map = require("map-stream");
const tokenize = require("./tokenize");
const toHTML = require("./to-html");
// TODO: automatically pull these in from gmi.css (also for gmi.css(5))
const GMI_CSS_VARS = [
"foreground",
"background",
"p-size",
"p-indent",
"p-line-height",
"a-size",
"pre-size",
"pre-line-height",
"h1-size",
"h2-size",
"h3-size",
"heading-line-height",
"ul-size",
"ul-line-height",
"blockquote-size",
"blockquote-line-height",
"mono",
"serif",
"sans-serif",
];
require("yargs")
.scriptName("gmi-web")
.command(
"$0 <files..>",
"$0 [files..]",
"Convert .gmi to .html. See gmi-web(1) for more details.",
(yargs) =>
yargs
@ -19,52 +42,49 @@ require("yargs")
.option("images", {
type: "boolean",
default: false,
description: "Include images",
describe: "Include images",
})
.option("audio", {
type: "boolean",
default: false,
description: "Include audio",
describe: "Include audio",
})
.option("video", {
type: "boolean",
default: false,
description: "Include video",
})
.option("verbose", {
alias: "v",
type: "boolean",
default: false,
description: "No logging to stdout",
describe: "Include video",
})
.option("css", {
type: "boolean",
default: true,
description: "Include gmi.css",
describe:
"gmi.css is included by default. Use --no-css to for the bare-minimum <style>",
}),
(argv) => {
if (argv.verbose) console.log(argv);
const override = GMI_CSS_VARS.reduce((style, key) => {
if (argv[key]) {
style += `--${key}: ${argv[key]};`;
}
return style;
}, "");
fs.src(argv.files)
.pipe(map(tokenize))
.pipe(
map(
toHTML({
css: !argv.noCss,
css: argv.css,
inline: {
images: argv.images,
audio: argv.audio,
video: argv.video,
},
silent: argv.silent,
verbose: argv.verbose,
override,
})
)
)
.pipe(fs.dest((file) => path.dirname(file.path)));
}
)
.showHelpOnFail(true, "Specify --help for available options")
.help().argv;
function log(file, cb) {
console.log(file.path, file.contents ? file.contents.toString("utf8") : "");
cb(null, file);
}

View file

@ -13,9 +13,7 @@ gmi-web - A bridge between Gemini and HTML.
.P
.SH SYNOPSIS
.P
\fBgmi-web\fR [\fIOPTIONS\fR] <\fIFILES\fR>
.P
\fBgmi-web\fR --recursive [\fIOPTIONS\fR] <\fIDIR\fR> [\fIOUT\fR]
\fBgmi-web\fR <\fIOPTIONS\fR> [\fIFILES\fR]
.P
.SH DESCRIPTION
.P
@ -24,24 +22,12 @@ and mobile-friendly fashion!
.P
.SH OPTIONS
.P
\fBCSS variables\fR
\fBCSS Variables\fR
.RS 4
Any variable documented in \fBgmi.css(5)\fR can be set via \fIOPTIONS\fR of the same name.
Any variable documented in \fBgmi.css\fR(5) can be set via \fIOPTIONS\fR of the same
name.
.P
\fBgmi-web\fR --foreground "#FFFFF" --background "#00000" *.gmi
.P
.RE
\fB--recursive\fR <\fIDIR\fR> [\fIOUT\fR]
.RS 4
Recursively generate HTML for a \fIDIR\fR. Use \fIOUT\fR to put the .html somewhere
other than \fIDIR\fR.
.P
\fBgmi-web\fR --recursive capsule /srv/html/
.P
.RE
\fB--no-css\fR
.RS 4
Use only the bare-minimum <style>
\fBgmi-web\fR --foreground "#FFFFF" --background "#00000" $(find . -name *.gmi)
.P
.RE
\fB--images\fR \fB--audio\fR \fB--video\fR
@ -49,11 +35,21 @@ Use only the bare-minimum <style>
Include the respective media inline.
.P
.RE
\fB--verbose\fR
\fB--no-css\fR
.RS 4
Enable internal logs for debugging mostly.
Use only the bare-minimum <style>
.P
.RE
.SH EXAMPLES
.P
Render all the .gmi files in the current directory to .html
.P
.nf
.RS 4
gmi-web $(find \&. -name *\&.gmi)
.fi
.RE
.P
.SH SEE ALSO
.P
\fBgmi.css\fR(5)

View file

@ -6,9 +6,7 @@ gmi-web - A bridge between Gemini and HTML.
# SYNOPSIS
*gmi-web* [_OPTIONS_] <_FILES_>
*gmi-web* --recursive [_OPTIONS_] <_DIR_> [_OUT_]
*gmi-web* <_OPTIONS_> [_FILES_]
# DESCRIPTION
@ -17,26 +15,25 @@ and mobile-friendly fashion!
# OPTIONS
*CSS variables*
*CSS Variables*
Any variable documented in *gmi.css*(5) can be set via _OPTIONS_ of the same
name.
*gmi-web* --foreground "#FFFFF" --background "#00000" \*.gmi
*--recursive* <_DIR_> [_OUT_]
Recursively generate HTML for a _DIR_. Use _OUT_ to put the .html somewhere
other than _DIR_.
*gmi-web* --recursive capsule /srv/html/
*--no-css*
Use only the bare-minimum <style>
*gmi-web* --foreground "#FFFFF" --background "#00000" $(find . -name \*.gmi)
*--images* *--audio* *--video*
Include the respective media inline.
*--verbose*
Enable internal logs for debugging mostly.
*--no-css*
Use only the bare-minimum <style>
# EXAMPLES
Render all the .gmi files in the current directory to .html
```
gmi-web $(find . -name \*.gmi)
```
# SEE ALSO

View file

@ -2,40 +2,45 @@ const fs = require("fs");
const path = require("path");
const TOKENS_EXT = /\.tokens\.json$/;
// https://developer.mozilla.org/en-US/docs/Web/Media/Formats
const IMG_EXT = /\.(apng|avif|gif|jpg|jpeg|jfif|pjpeg|pjp|png|svg|webp)$/;
const AUDIO_EXT = /\.(mp3|wav|aac|aacp|mpeg|off|flac)$/;
const VIDEO_EXT = /\.(mp4|webm)$/;
const IMG_EXT = (exports.IMG_EXT = /\.(apng|avif|gif|jpg|jpeg|jfif|pjpeg|pjp|png|svg|webp)$/);
const AUDIO_EXT = (exports.AUDIO_EXT = /\.(mp3|wav|aac|aacp|mpeg|off|flac)$/);
const VIDEO_EXT = (exports.VIDEO_EXT = /\.(mp4|webm)$/);
const BASE_STYLE = (exports.baseStyle =
"<style>p,a,pre,h1,h2,h3,ul,blockquote,img,audio,video{display:block;max-width:100%;margin:0;padding:0;overflow-wrap:anywhere;}</style>");
module.exports = (options) => (file, cb) => {
if (!TOKENS_EXT.test(file.path)) return cb(null);
// TODO: meta: language, description, canonical
file.contents = Buffer.from(`<!DOCTYPE html>
<html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">${
options.css
? `\n<meta name="color-scheme" content="dark light">\n<style>${fs.readFileSync(
path.resolve(__dirname, "./gmi.min.css"),
"utf8"
)}</style>\n<style>${fs.readFileSync(
path.resolve(path.dirname(file.path), "./gmi.css"),
"utf8"
)}</style>`
: "<style>p,a,pre,h1,h2,h3,ul,blockquote,img,audio,video{display:block;max-width:100%;margin:0;padding:0;overflow-wrap:anywhere;}</style>"
}
const toHTML = (exports.toHTML = (file, options) => `<!DOCTYPE html>
<html style="${options.override}">
${head(file.path, options)}
<body>
${toHTML(JSON.parse(file.contents.toString("utf8")), options)}
${gemtext(JSON.parse(file.contents.toString("utf8")), options)}
</body>
</html>
`);
module.exports = (options) => (file, cb) => {
if (!TOKENS_EXT.test(file.path)) return cb(null);
file.contents = Buffer.from(toHTML(file, options));
file.path = file.path.replace(TOKENS_EXT, ".html");
if (!options.silent) console.log(file.path);
if (options.verbose) console.log(file.path);
return cb(null, file);
};
function toHTML(tokens, options) {
// TODO: meta: language, description, canonical
function head(file, options) {
return `<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">${
!options.css
? BASE_STYLE
: `\n<meta name="color-scheme" content="dark light">\n<style>${fs.readFileSync(
path.resolve(__dirname, "./gmi.min.css"),
"utf8"
)}</style>`
}
</head>
`;
}
function gemtext(tokens, options) {
let body = [];
let cursor = tokens.shift();
@ -83,3 +88,8 @@ function line(
if (quote) return `<blockquote>${quote}</blockquote>`;
return `<p><br></p>`;
}
function omit(key, obj) {
const { [key]: omitted, ...rest } = obj;
return rest;
}