add --author and --descriptions options
This commit is contained in:
parent
45e90e61ac
commit
5254445e77
23
cli.js
23
cli.js
|
@ -9,7 +9,7 @@ import toHTML, { BASE_CSS, html } from "./html.js";
|
||||||
|
|
||||||
const cli = yargs(process.argv.slice(2))
|
const cli = yargs(process.argv.slice(2))
|
||||||
.config("config", function (path) {
|
.config("config", function (path) {
|
||||||
return JSON.parse(readFileSync(path))
|
return JSON.parse(readFileSync(path));
|
||||||
})
|
})
|
||||||
.scriptName("gmi-web")
|
.scriptName("gmi-web")
|
||||||
.command("$0 [files..]", "Convert text/gemini to text/html.", (yargs) =>
|
.command("$0 [files..]", "Convert text/gemini to text/html.", (yargs) =>
|
||||||
|
@ -30,15 +30,23 @@ const cli = yargs(process.argv.slice(2))
|
||||||
type: "string",
|
type: "string",
|
||||||
requiresArg: true,
|
requiresArg: true,
|
||||||
},
|
},
|
||||||
charset: {
|
author: {
|
||||||
type: "string",
|
type: "string",
|
||||||
default: "utf-8",
|
|
||||||
requiresArg: true,
|
requiresArg: true,
|
||||||
},
|
},
|
||||||
|
descriptions: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
css: {
|
css: {
|
||||||
choices: ["gmi.css", "base", "none"],
|
choices: ["gmi.css", "base", "none"],
|
||||||
default: "gmi.css",
|
default: "gmi.css",
|
||||||
},
|
},
|
||||||
|
charset: {
|
||||||
|
type: "string",
|
||||||
|
hidden: true,
|
||||||
|
default: "utf-8",
|
||||||
|
requiresArg: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
cli.options({
|
cli.options({
|
||||||
|
@ -85,10 +93,13 @@ const GMI_CSS_VARS = [
|
||||||
});
|
});
|
||||||
|
|
||||||
const argv = cli
|
const argv = cli
|
||||||
|
.conflicts("author", "body")
|
||||||
|
.conflicts("description", "body")
|
||||||
.conflicts("html", "body")
|
.conflicts("html", "body")
|
||||||
.group(["html", "css", "body"], "Core:")
|
.group(["html", "body"], "Core:")
|
||||||
.group(GMI_CSS_VARS, "gmi.css:")
|
.group(["author", "description", "css"], "HTML:")
|
||||||
.group(["image", "audio", "video"], "Inline Media:")
|
.group(["image", "audio", "video"], "Inline Media:")
|
||||||
|
.group(GMI_CSS_VARS, "gmi.css:")
|
||||||
.alias("html", "language")
|
.alias("html", "language")
|
||||||
.alias("html", "lang")
|
.alias("html", "lang")
|
||||||
.showHelpOnFail(true)
|
.showHelpOnFail(true)
|
||||||
|
@ -100,7 +111,7 @@ if (argv.css === "gmi.css") {
|
||||||
if (argv[key]) {
|
if (argv[key]) {
|
||||||
style += `--${key}: ${argv[key]};`;
|
style += `--${key}: ${argv[key]};`;
|
||||||
}
|
}
|
||||||
return style
|
return style;
|
||||||
}, styles);
|
}, styles);
|
||||||
|
|
||||||
argv.css = new CleanCSS().minify(
|
argv.css = new CleanCSS().minify(
|
||||||
|
|
12
gmi-web.1
12
gmi-web.1
|
@ -31,6 +31,18 @@ Generate a full HTML5 document with the provided \fILANG\fR.
|
||||||
\fBgmi-web\fR --html en < doc.gmi
|
\fBgmi-web\fR --html en < doc.gmi
|
||||||
.P
|
.P
|
||||||
.RE
|
.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
|
\fB--body\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Generate only the HTML for the lines of the Gemini document.
|
Generate only the HTML for the lines of the Gemini document.
|
||||||
|
|
|
@ -22,6 +22,14 @@ and mobile-friendly fashion!
|
||||||
|
|
||||||
*gmi-web* --html en < doc.gmi
|
*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*
|
*--body*
|
||||||
Generate only the HTML for the lines of the Gemini document.
|
Generate only the HTML for the lines of the Gemini document.
|
||||||
|
|
||||||
|
|
17
html.js
17
html.js
|
@ -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>(.+)?))$/;
|
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) {
|
export function html(file, options) {
|
||||||
const tokens = file.contents
|
const tokens = file.contents
|
||||||
.toString("utf8")
|
.toString("utf8")
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.map((line) => GMI_REGEX.exec(line).groups);
|
.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);
|
if (options.body) return body(tokens, options);
|
||||||
|
|
||||||
return `<!DOCTYPE html>
|
return `<!DOCTYPE html>
|
||||||
|
@ -15,7 +23,7 @@ export function html(file, options) {
|
||||||
<head>${head(
|
<head>${head(
|
||||||
Object.assign(options, {
|
Object.assign(options, {
|
||||||
title: tokens[0].h1,
|
title: tokens[0].h1,
|
||||||
// TODO: description, canonical
|
description: description && truncate(description.text, 200),
|
||||||
})
|
})
|
||||||
)}</head>
|
)}</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -27,6 +35,7 @@ ${body(tokens, options)}
|
||||||
|
|
||||||
export const BASE_CSS =
|
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;}";
|
"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) {
|
export function head(options) {
|
||||||
return `
|
return `
|
||||||
<meta charset="${options.charset}">
|
<meta charset="${options.charset}">
|
||||||
|
@ -34,13 +43,15 @@ export function head(options) {
|
||||||
${options.css !== "" ? `<meta name="color-scheme" content="dark light">` : ""}
|
${options.css !== "" ? `<meta name="color-scheme" content="dark light">` : ""}
|
||||||
${options.css !== "" ? `<style>${options.css}</style>` : ""}
|
${options.css !== "" ? `<style>${options.css}</style>` : ""}
|
||||||
<title>${options.title}</title>${
|
<title>${options.title}</title>${
|
||||||
|
!options.author ? "" : `<meta name="author" content="${options.author}">`
|
||||||
|
}${
|
||||||
!options.description
|
!options.description
|
||||||
? ""
|
? ""
|
||||||
: `<meta name="description" content="${options.description}}">`
|
: `<meta name="description" content="${escape(options.description)}">`
|
||||||
}${
|
}${
|
||||||
!options.canonical
|
!options.canonical
|
||||||
? ""
|
? ""
|
||||||
: `<link rel="canonical" href="${options.canonical}}">`
|
: `<link rel="canonical" href="${options.canonical}">`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue