refactor css
This commit is contained in:
parent
fee09522ee
commit
873a9442e9
47
README.md
47
README.md
|
@ -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
2
cli.js
|
@ -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
22
core.css
Normal 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
22
css.js
|
@ -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
127
gmi.css
|
@ -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
11
html.js
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue