` tags in a "block" level element such as ``. [MDN: Changing Element Levels](https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements#changing_element_levels)
+`` tags are categorized as [inline](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flow_Layout/Block_and_Inline_Layout_in_Normal_Flow#elements_participating_in_an_inline_formatting_context) which CSS 2.1's [Normal Flow](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow) presents _vertically_—Gemini only deals with _horizontally_ flowing content, this can be addressed by using [`display: block;` at the CSS level.](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flow_Layout/Block_and_Inline_Layout_in_Normal_Flow#changing_the_formatting_context_an_element_participates_in)
-### Optional: inline media
+### optional: inline media
If a link is consumable by ` `, `` or `` you may insert the respective tag inline, instead of an ``. Images and video should be styled to have `max-width: 100%;` so they don't overflow the body. It's a good idea to also include the `controls` attribute. These are all categorized as inline just like ` ` and will need `display: block;` styling or to be wrapped in a "block" level element.
@@ -48,8 +46,7 @@ These may also be nice to have:
# gmi-web(1)
```sh
-npm install --global gmi-web-cli
-gmi-web --help
+npm install --global gmi-web-cli && gmi-web --help
```
```
@@ -57,22 +54,8 @@ gmi-web [files..]
Convert text/gemini to text/html.
-Core:
- --html, --language, --lang [string]
- --body [boolean]
-
-HTML:
- --author [string]
- --descriptions [number] [default: 0]
- --css [default: "full"]
- --dir [string] [choices: "rtl", "ltr"] [default: "ltr"]
-
-Inline Media:
- --image [array]
- --audio [array]
- --video [array]
-
CSS:
+ --inline [boolean]
--serif [default: "georgia, times, serif"]
--sans-serif [default: "avenir, helvetica, arial, sans-serif"]
--mono [default: "consolas, monaco, monospace"]
@@ -99,10 +82,24 @@ CSS:
--ul-line-height [default: "1.25"]
--quote-line-height [default: "1.25"]
+Core:
+ --html, --language, --lang [string]
+ --body [boolean]
+
+HTML:
+ --author [string]
+ --descriptions [number] [default: 0]
+ --css [default: "full"]
+ --dir [string] [choices: "rtl", "ltr"] [default: "ltr"]
+
+Inline Media:
+ --image [array]
+ --audio [array]
+ --video [array]
+
Options:
--version Show version number [boolean]
--config Path to JSON config file
- --inline [boolean]
--help Show help [boolean]
Examples:
@@ -152,6 +149,6 @@ The CSS variables exposed by gmi-web(1) are derived from [gmi.css](./gmi.css), w
The `--foreground` and `--background` variables will be inverted when
[prefers-color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) is "dark".
-# License
+# license
gmi-web is free and unencumbered public domain software. For more information, see http://unlicense.org/ or the accompanying UNLICENSE file.
diff --git a/cli.js b/cli.js
index 6cc9a04..1d95cf7 100755
--- a/cli.js
+++ b/cli.js
@@ -49,6 +49,7 @@ const cli = yargs(process.argv.slice(2))
},
inline: {
type: "boolean",
+ group: "CSS:",
},
image: {
type: "array",
@@ -72,6 +73,7 @@ const cli = yargs(process.argv.slice(2))
type: "boolean",
hidden: true,
default: false,
+ group: "CSS:",
},
})
.group(["html", "body"], "Core:")
diff --git a/core.css b/core.css
new file mode 100644
index 0000000..73360fe
--- /dev/null
+++ b/core.css
@@ -0,0 +1,22 @@
+p,
+pre,
+ul,
+blockquote,
+h1,
+h2,
+h3 {
+ margin-top: 0;
+ margin-bottom: 0;
+ overflow-wrap: break-word;
+}
+p:empty {
+ margin: revert;
+}
+
+a {
+ display: block;
+}
+
+pre {
+ overflow-y: auto;
+}
diff --git a/css.js b/css.js
index 3322952..9c6aab5 100644
--- a/css.js
+++ b/css.js
@@ -1,24 +1,16 @@
import { readFileSync } from "fs";
+// TODO import.meta.resolve is supposed to accomplish this without "path"
import path from "path";
import { stringify, parse } from "css";
export { stringify, parse };
-export const CORE = parse(`p, pre, ul, blockquote, h1, h2, h3 {
- margin-top: 0;
- margin-bottom: 0;
- overflow-wrap: break-word;
- hyphens: auto;
-}
+export const CORE = parse(
+ readFileSync(
+ path.resolve(path.dirname(new URL(import.meta.url).pathname), "./core.css"),
+ "utf-8"
+ )
+);
-a { display: block; }
-
-img, audio, video {
- display: block;
- max-width: 100%;
-}
-`);
-
-// TODO import.meta.resolve is supposed to accomplish this without "path"
export const FULL = parse(
readFileSync(
path.resolve(path.dirname(new URL(import.meta.url).pathname), "./gmi.css"),
diff --git a/gmi.css b/gmi.css
index 5767033..36a9474 100644
--- a/gmi.css
+++ b/gmi.css
@@ -1,23 +1,26 @@
p,
pre,
ul,
+blockquote,
h1,
h2,
h3 {
margin-top: 0;
margin-bottom: 0;
overflow-wrap: break-word;
- hyphens: auto;
}
-
-blockquote {
- margin: 0;
+p:empty {
+ margin: revert;
}
a {
display: block;
}
+pre {
+ overflow-y: auto;
+}
+
img,
audio,
video {
@@ -26,110 +29,116 @@ video {
}
:root {
- --serif: georgia, times, serif;
- --sans-serif: avenir, helvetica, arial, sans-serif;
- --mono: consolas, monaco, monospace;
--foreground: black;
--background: white;
+ --body-width: 48rem;
+ --hyphens: manual;
+
+ --serif: georgia, times, serif;
+ --sans-serif: avenir, helvetica, arial, sans-serif;
+ --mono: consolas, monaco, monospace;
+
+ --p-family: var(--serif);
+ --p-size: 1.25rem;
+ --p-height: 1.5;
+ --p-indent: 0rem;
+
+ --a-family: var(--serif);
+ --a-size: var(--p-size);
+ --a-height: 1.5;
--a-decoration: underline;
--a-style: normal;
- --ul-bullet: "*";
- --p-indent: 0rem;
- --quote-style: italic;
- --body-width: 48rem;
- --p-size: 1.25rem;
- --a-size: var(--p-size);
+ --pre-family: var(--mono);
--pre-size: 1rem;
- --h1-size: 3rem;
- --h2-size: 2.25rem;
- --h3-size: 1.5rem;
- --ul-size: var(--p-size);
- --quote-size: var(--p-size);
+ --pre-height: 1;
- --p-line-height: 1.5;
- --a-line-height: 1.5;
- --pre-line-height: 1;
- --h-line-height: 1.25;
- --ul-line-height: 1.25;
- --quote-line-height: 1.25;
+ --h1-family: var(--sans-serif);
+ --h1-size: 3rem;
+ --h1-height: 1.25;
+
+ --h2-family: var(--sans-serif);
+ --h2-size: 2.25rem;
+ --h2-height: 1.25;
+
+ --h3-family: var(--sans-serif);
+ --h3-size: 1.5rem;
+ --h3-height: 1.25;
+
+ --ul-family: var(--serif);
+ --ul-size: var(--p-size);
+ --ul-height: 1.25;
+
+ --quote-family: var(--serif);
+ --quote-size: var(--p-size);
+ --quote-height: 1.25;
+ --quote-style: italic;
}
body {
- max-width: var(--body-width);
- padding: 0.5rem;
margin: 0 auto;
-}
-
-h1,
-h2,
-h3 {
- font-family: var(--sans-serif);
- line-height: var(--h-line-height);
+ padding: 0.5rem;
+ max-width: var(--body-width);
+ hyphens: var(--hyphens);
}
p {
+ font-family: var(--p-family);
font-size: var(--p-size);
- font-family: var(--serif);
+ line-height: var(--p-height);
text-indent: var(--p-indent);
- line-height: var(--p-line-height);
}
a {
font-size: var(--a-size);
font-style: var(--a-style);
font-family: var(--serif);
+ line-height: var(--a-line-height);
text-decoration: var(--a-decoration);
}
pre {
+ padding: 1rem;
+ font-family: var(--pre-family);
font-size: var(--pre-size);
- font-family: var(--mono);
- line-height: var(--pre-line-height);
- padding: 1.25rem;
- overflow-y: auto;
+ line-height: var(--pre-height);
}
h1 {
+ font-family: var(--h1-family);
font-size: var(--h1-size);
+ line-height: var(--h1-height);
}
h2 {
+ font-family: var(--h2-family);
font-size: var(--h2-size);
+ line-height: var(--h2-height);
}
h3 {
+ font-family: var(--h3-family);
font-size: var(--h3-size);
+ line-height: var(--h3-height);
}
ul {
- padding-left: 0;
+ padding-left: 1rem;
+ list-style-type: var(--ul-style);
font-size: var(--ul-size);
- font-family: var(--serif);
- line-height: var(--ul-line-height);
- list-style-type: none;
-}
-
-li::before {
- font-size: var(--ul-size);
- font-family: var(--serif);
- content: var(--ul-bullet);
- vertical-align: middle;
- padding-right: 0.5rem;
+ font-family: var(--ul-family);
+ line-height: var(--ul-height);
}
blockquote {
+ margin-left: 0;
+ margin-right: 0;
+ padding-left: 0.5rem;
+ font-family: var(--quote-family);
font-size: var(--quote-size);
- font-family: var(--serif);
font-style: var(--quote-style);
- line-height: var(--quote-line-height);
- padding-left: 0.75rem;
-}
-
-pre + blockquote {
- padding-top: 0.5rem;
- padding-bottom: 0.5rem;
+ line-height: var(--quote-height);
}
/* foreground and background colors */
diff --git a/html.js b/html.js
index 1a7e509..671b816 100644
--- a/html.js
+++ b/html.js
@@ -11,8 +11,8 @@ export function block(
) {
let type = "p";
let props = "";
- let content = " ";
- if (text && text !== "") {
+ let content = "";
+ if (text) {
content = text;
}
if (h1) {
@@ -53,11 +53,10 @@ export function block(
props += ` href=${href}`;
}
}
- if (options.body || options.inline) props += CSS.inline(type, options);
+ if (options.body || options.inline)
+ content !== "" ? (props += CSS.inline(type, options)) : "";
- return `<${type}${props}>${
- content !== " " ? escape(content) : content
- }${type}>`;
+ return `<${type}${props}>${escape(content)}${type}>`;
}
export function body(tokens, options) {