add --author and --descriptions options

This commit is contained in:
Talon Poole 2021-02-12 21:59:18 +00:00
parent 45e90e61ac
commit 5254445e77
4 changed files with 51 additions and 9 deletions

23
cli.js
View file

@ -9,7 +9,7 @@ import toHTML, { BASE_CSS, html } from "./html.js";
const cli = yargs(process.argv.slice(2))
.config("config", function (path) {
return JSON.parse(readFileSync(path))
return JSON.parse(readFileSync(path));
})
.scriptName("gmi-web")
.command("$0 [files..]", "Convert text/gemini to text/html.", (yargs) =>
@ -30,15 +30,23 @@ const cli = yargs(process.argv.slice(2))
type: "string",
requiresArg: true,
},
charset: {
author: {
type: "string",
default: "utf-8",
requiresArg: true,
},
descriptions: {
type: "boolean",
},
css: {
choices: ["gmi.css", "base", "none"],
default: "gmi.css",
},
charset: {
type: "string",
hidden: true,
default: "utf-8",
requiresArg: true,
},
});
cli.options({
@ -85,10 +93,13 @@ const GMI_CSS_VARS = [
});
const argv = cli
.conflicts("author", "body")
.conflicts("description", "body")
.conflicts("html", "body")
.group(["html", "css", "body"], "Core:")
.group(GMI_CSS_VARS, "gmi.css:")
.group(["html", "body"], "Core:")
.group(["author", "description", "css"], "HTML:")
.group(["image", "audio", "video"], "Inline Media:")
.group(GMI_CSS_VARS, "gmi.css:")
.alias("html", "language")
.alias("html", "lang")
.showHelpOnFail(true)
@ -100,7 +111,7 @@ if (argv.css === "gmi.css") {
if (argv[key]) {
style += `--${key}: ${argv[key]};`;
}
return style
return style;
}, styles);
argv.css = new CleanCSS().minify(

View file

@ -31,6 +31,18 @@ Generate a full HTML5 document with the provided \fILANG\fR.
\fBgmi-web\fR --html en < doc.gmi
.P
.RE
\fB--descriptions\fR
.RS 4
If this flag is set the first non-empty text line of each Gemini file will
be used for the description <meta> tag. This will be truncated to 200
characters using an ellipsis.
.P
.RE
\fB--author\fR
.RS 4
If provided this will be used for the author <meta> tag on every file.
.P
.RE
\fB--body\fR
.RS 4
Generate only the HTML for the lines of the Gemini document.

View file

@ -22,6 +22,14 @@ and mobile-friendly fashion!
*gmi-web* --html en < doc.gmi
*--descriptions*
If this flag is set the first non-empty text line of each Gemini file will
be used for the description <meta> tag. This will be truncated to 200
characters using an ellipsis.
*--author*
If provided this will be used for the author <meta> tag on every file.
*--body*
Generate only the HTML for the lines of the Gemini document.

17
html.js
View file

@ -2,12 +2,20 @@ import escape from "escape-html";
export const GMI_REGEX = /^((=>\s?(?<href>[^\s]+)(\s(?<title>.+))?)|(?<pre>```\s?(?<alt>.+)?)|(###\s?(?<h3>.+))|(##\s?(?<h2>.+))|(#\s?(?<h1>.+))|(\*\s?(?<li>.+))|(>\s?(?<quote>.+))|(?<text>(.+)?))$/;
const truncate = (text, limit) =>
text.length > limit ? `${text.substring(0, limit)}...` : text;
export function html(file, options) {
const tokens = file.contents
.toString("utf8")
.split("\n")
.map((line) => GMI_REGEX.exec(line).groups);
let description = options.descriptions
? tokens.find((token) => {
return token.text && token.text !== "";
})
: false;
if (options.body) return body(tokens, options);
return `<!DOCTYPE html>
@ -15,7 +23,7 @@ export function html(file, options) {
<head>${head(
Object.assign(options, {
title: tokens[0].h1,
// TODO: description, canonical
description: description && truncate(description.text, 200),
})
)}</head>
<body>
@ -27,6 +35,7 @@ ${body(tokens, options)}
export const BASE_CSS =
"p,a,pre,h1,h2,h3,ul,blockquote,img,audio,video{display:block;max-width:100%;margin:0;padding:0;overflow-wrap:anywhere;}";
export function head(options) {
return `
<meta charset="${options.charset}">
@ -34,13 +43,15 @@ export function head(options) {
${options.css !== "" ? `<meta name="color-scheme" content="dark light">` : ""}
${options.css !== "" ? `<style>${options.css}</style>` : ""}
<title>${options.title}</title>${
!options.author ? "" : `<meta name="author" content="${options.author}">`
}${
!options.description
? ""
: `<meta name="description" content="${options.description}}">`
: `<meta name="description" content="${escape(options.description)}">`
}${
!options.canonical
? ""
: `<link rel="canonical" href="${options.canonical}}">`
: `<link rel="canonical" href="${options.canonical}">`
}
`;
}