refactor css

This commit is contained in:
Talon Poole 2021-02-18 23:16:05 +00:00
parent fee09522ee
commit 873a9442e9
6 changed files with 126 additions and 105 deletions

View file

@ -1,6 +1,4 @@
# gmi-web This project is home to a [gmi-to-html reference](#gmi-to-html), the [gmi-web(1) ](#gmi-web-1) command-line tool and a [gmi.css](#gmi-css) stylesheet.
This repo is home to [a gmi-to-html reference](#gmi-to-html), [the gmi-web(1) command-line tool](#gmi-web-1) and [a gmi.css stylesheet](#gmi-css).
# gmi-to-html # gmi-to-html
@ -15,12 +13,12 @@ The converted Gemini document should exist inside the `<body>`. Consider if shar
<blockquote> ↔ > <blockquote> ↔ >
```` ````
List items must be wrapped with a `<ul>` tag. Empty lines should be represented as `<p><br></p>`. Take care to render `<pre>` blocks with their original formatting, DO NOT indent the generated List items must be wrapped with a `<ul>` tag. Take care to render `<pre>` blocks with their original formatting, DO NOT indent the generated
HTML for these tags. HTML for these tags.
`<a>` tags are categorized as [inline](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flow_Layout/Block_and_Inline_Layout_in_Normal_Flow) which CSS 2.1's _Normal Flow_ presents vertically—Gemini only deals with horizontally flowing content, this can be addressed by either using `a {display: block;}` at the CSS level or by wrapping `<a>` tags in a "block" level element such as `<p>`. [MDN: Changing Element Levels](https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements#changing_element_levels) `<a>` 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 `<img>`, `<audio>` or `<video>` you may insert the respective tag inline, instead of an `<a>`. 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 `<a>` and will need `display: block;` styling or to be wrapped in a "block" level element. If a link is consumable by `<img>`, `<audio>` or `<video>` you may insert the respective tag inline, instead of an `<a>`. 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 `<a>` 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) # gmi-web(1)
```sh ```sh
npm install --global gmi-web-cli npm install --global gmi-web-cli && gmi-web --help
gmi-web --help
``` ```
``` ```
@ -57,22 +54,8 @@ gmi-web [files..]
Convert text/gemini to text/html. 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: CSS:
--inline [boolean]
--serif [default: "georgia, times, serif"] --serif [default: "georgia, times, serif"]
--sans-serif [default: "avenir, helvetica, arial, sans-serif"] --sans-serif [default: "avenir, helvetica, arial, sans-serif"]
--mono [default: "consolas, monaco, monospace"] --mono [default: "consolas, monaco, monospace"]
@ -99,10 +82,24 @@ CSS:
--ul-line-height [default: "1.25"] --ul-line-height [default: "1.25"]
--quote-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: Options:
--version Show version number [boolean] --version Show version number [boolean]
--config Path to JSON config file --config Path to JSON config file
--inline [boolean]
--help Show help [boolean] --help Show help [boolean]
Examples: 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 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". [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. gmi-web is free and unencumbered public domain software. For more information, see http://unlicense.org/ or the accompanying UNLICENSE file.

2
cli.js
View file

@ -49,6 +49,7 @@ const cli = yargs(process.argv.slice(2))
}, },
inline: { inline: {
type: "boolean", type: "boolean",
group: "CSS:",
}, },
image: { image: {
type: "array", type: "array",
@ -72,6 +73,7 @@ const cli = yargs(process.argv.slice(2))
type: "boolean", type: "boolean",
hidden: true, hidden: true,
default: false, default: false,
group: "CSS:",
}, },
}) })
.group(["html", "body"], "Core:") .group(["html", "body"], "Core:")

22
core.css Normal file
View file

@ -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;
}

22
css.js
View file

@ -1,24 +1,16 @@
import { readFileSync } from "fs"; import { readFileSync } from "fs";
// TODO import.meta.resolve is supposed to accomplish this without "path"
import path from "path"; import path from "path";
import { stringify, parse } from "css"; import { stringify, parse } from "css";
export { stringify, parse }; export { stringify, parse };
export const CORE = parse(`p, pre, ul, blockquote, h1, h2, h3 { export const CORE = parse(
margin-top: 0; readFileSync(
margin-bottom: 0; path.resolve(path.dirname(new URL(import.meta.url).pathname), "./core.css"),
overflow-wrap: break-word; "utf-8"
hyphens: auto; )
} );
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( export const FULL = parse(
readFileSync( readFileSync(
path.resolve(path.dirname(new URL(import.meta.url).pathname), "./gmi.css"), path.resolve(path.dirname(new URL(import.meta.url).pathname), "./gmi.css"),

127
gmi.css
View file

@ -1,23 +1,26 @@
p, p,
pre, pre,
ul, ul,
blockquote,
h1, h1,
h2, h2,
h3 { h3 {
margin-top: 0; margin-top: 0;
margin-bottom: 0; margin-bottom: 0;
overflow-wrap: break-word; overflow-wrap: break-word;
hyphens: auto;
} }
p:empty {
blockquote { margin: revert;
margin: 0;
} }
a { a {
display: block; display: block;
} }
pre {
overflow-y: auto;
}
img, img,
audio, audio,
video { video {
@ -26,110 +29,116 @@ video {
} }
:root { :root {
--serif: georgia, times, serif;
--sans-serif: avenir, helvetica, arial, sans-serif;
--mono: consolas, monaco, monospace;
--foreground: black; --foreground: black;
--background: white; --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-decoration: underline;
--a-style: normal; --a-style: normal;
--ul-bullet: "*";
--p-indent: 0rem;
--quote-style: italic;
--body-width: 48rem; --pre-family: var(--mono);
--p-size: 1.25rem;
--a-size: var(--p-size);
--pre-size: 1rem; --pre-size: 1rem;
--h1-size: 3rem; --pre-height: 1;
--h2-size: 2.25rem;
--h3-size: 1.5rem;
--ul-size: var(--p-size);
--quote-size: var(--p-size);
--p-line-height: 1.5; --h1-family: var(--sans-serif);
--a-line-height: 1.5; --h1-size: 3rem;
--pre-line-height: 1; --h1-height: 1.25;
--h-line-height: 1.25;
--ul-line-height: 1.25; --h2-family: var(--sans-serif);
--quote-line-height: 1.25; --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 { body {
max-width: var(--body-width);
padding: 0.5rem;
margin: 0 auto; margin: 0 auto;
} padding: 0.5rem;
max-width: var(--body-width);
h1, hyphens: var(--hyphens);
h2,
h3 {
font-family: var(--sans-serif);
line-height: var(--h-line-height);
} }
p { p {
font-family: var(--p-family);
font-size: var(--p-size); font-size: var(--p-size);
font-family: var(--serif); line-height: var(--p-height);
text-indent: var(--p-indent); text-indent: var(--p-indent);
line-height: var(--p-line-height);
} }
a { a {
font-size: var(--a-size); font-size: var(--a-size);
font-style: var(--a-style); font-style: var(--a-style);
font-family: var(--serif); font-family: var(--serif);
line-height: var(--a-line-height);
text-decoration: var(--a-decoration); text-decoration: var(--a-decoration);
} }
pre { pre {
padding: 1rem;
font-family: var(--pre-family);
font-size: var(--pre-size); font-size: var(--pre-size);
font-family: var(--mono); line-height: var(--pre-height);
line-height: var(--pre-line-height);
padding: 1.25rem;
overflow-y: auto;
} }
h1 { h1 {
font-family: var(--h1-family);
font-size: var(--h1-size); font-size: var(--h1-size);
line-height: var(--h1-height);
} }
h2 { h2 {
font-family: var(--h2-family);
font-size: var(--h2-size); font-size: var(--h2-size);
line-height: var(--h2-height);
} }
h3 { h3 {
font-family: var(--h3-family);
font-size: var(--h3-size); font-size: var(--h3-size);
line-height: var(--h3-height);
} }
ul { ul {
padding-left: 0; padding-left: 1rem;
list-style-type: var(--ul-style);
font-size: var(--ul-size); font-size: var(--ul-size);
font-family: var(--serif); font-family: var(--ul-family);
line-height: var(--ul-line-height); line-height: var(--ul-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;
} }
blockquote { blockquote {
margin-left: 0;
margin-right: 0;
padding-left: 0.5rem;
font-family: var(--quote-family);
font-size: var(--quote-size); font-size: var(--quote-size);
font-family: var(--serif);
font-style: var(--quote-style); font-style: var(--quote-style);
line-height: var(--quote-line-height); line-height: var(--quote-height);
padding-left: 0.75rem;
}
pre + blockquote {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
} }
/* foreground and background colors */ /* foreground and background colors */

11
html.js
View file

@ -11,8 +11,8 @@ export function block(
) { ) {
let type = "p"; let type = "p";
let props = ""; let props = "";
let content = "<br>"; let content = "";
if (text && text !== "") { if (text) {
content = text; content = text;
} }
if (h1) { if (h1) {
@ -53,11 +53,10 @@ export function block(
props += ` href=${href}`; 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}>${ return `<${type}${props}>${escape(content)}</${type}>`;
content !== "<br>" ? escape(content) : content
}</${type}>`;
} }
export function body(tokens, options) { export function body(tokens, options) {