use cli to pass in CSS vars
This commit is contained in:
parent
13a885ee11
commit
990667c2a7
58
cli.js
58
cli.js
|
@ -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);
|
||||
}
|
||||
|
|
38
gmi-web.1
38
gmi-web.1
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
60
to-html.js
60
to-html.js
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue