install via npm
This commit is contained in:
parent
21c5e5bfef
commit
d77cc84a06
7
Makefile
7
Makefile
|
@ -1,6 +1,5 @@
|
|||
PREFIX=/usr/local
|
||||
INSTALLDIR=$(DESTDIR)$(PREFIX)
|
||||
MANDIR=$(INSTALLDIR)/share/man
|
||||
|
||||
format:
|
||||
./node_modules/prettier/bin-prettier.js --write gmi.css
|
||||
|
@ -12,11 +11,9 @@ gmi.min.css: gmi.css
|
|||
gmi-web.1: gmi-web.1.scd
|
||||
scdoc < $< > $@
|
||||
|
||||
install: gmi.min.css gmi-web.1
|
||||
sudo npm link
|
||||
install -Dm644 gmi-web.1 $(MANDIR)/man1/gmi-web.1
|
||||
build: format gmi.min.css gmi-web.1
|
||||
|
||||
clean:
|
||||
rm -rf gmi.min.* gmi-web.1
|
||||
|
||||
.PHONY: install clean
|
||||
.PHONY: install clean format
|
||||
|
|
55
README.md
55
README.md
|
@ -8,48 +8,35 @@ Check out the annotated [example.html](https://gmi.eattherich.club/example.html)
|
|||
|
||||
Due to the ambiguity of HTML several translations from Gemini exist in the wild. I propose the following standard:
|
||||
|
||||
````
|
||||
<ul> ↔ *
|
||||
<blockquote> ↔ >
|
||||
<pre> ↔ ```
|
||||
<a> ↔ =>
|
||||
<h[1-3]> ↔ #[##]
|
||||
```
|
||||
<ul><li></ul> ↔ *
|
||||
<blockquote> ↔ >
|
||||
<pre> ↔ ```
|
||||
<a> ↔ =>
|
||||
<h[1-3]> ↔ #[##]
|
||||
<p>
|
||||
````
|
||||
```
|
||||
|
||||
The `<a>` for a link should be presented without any parent elements. Many implementations use `<div>` to enforce "block" styling as opposed to the default "inline" which renders the link next to the previous block instead of below it. But the nested markup adds an unnecessary layer of indirection in semantics and when parsing. `<a style="display: block;">` has the same effect (gmi.css uses this).
|
||||
|
||||
Empty lines should simply be represented as `<p><br></p>` this sets up `contenteditable=true` to add content to the line compared to just `<br>`.
|
||||
|
||||
### inline media
|
||||
|
||||
Optionally, if a link is consumable by `<img>`, `<audio>` or `<video>` you may insert the media inline. 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 for videos and audio. `<audio>` tags require `display: block;` just like `<a>`.
|
||||
|
||||
### contenteditable
|
||||
|
||||
Empty lines should simply be represented as `<p><br></p>` this sets up `contenteditable=true` to add content to the line compared to just `<br>`.
|
||||
|
||||
When `contenteditable=true`, `<p>`, `<ul>`, `<blockquote>` and `<pre>` may also have line-breaks which will be represented in `.innerHTML` like so:
|
||||
|
||||
```
|
||||
<p> ↔ <br>
|
||||
<blockquote> ↔ <div><br></div>
|
||||
<ul> ↔ <li><br></li>
|
||||
<pre> ↔ \n (or <br>)
|
||||
```
|
||||
|
||||
This is important mostly for DOM development (as opposed to static HTML generation) where it is likely to occur.
|
||||
|
||||
## gmi.css
|
||||
|
||||
Style your HTML generated Gemini content in a readable, predictable and mobile-friendly fashion!
|
||||
|
||||
```
|
||||
```html
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="https://talon.computer/gmi.min.css"/>
|
||||
<link rel="stylesheet" href="gmi.min.css"/>
|
||||
```
|
||||
|
||||
The following variables (shown with their defaults) can be customized using the style attribute of your document's `<html>` tag.
|
||||
|
||||
```
|
||||
```css
|
||||
--foreground: black;
|
||||
--background: white;
|
||||
--p-size: 1.25rem;
|
||||
|
@ -68,12 +55,21 @@ The following variables (shown with their defaults) can be customized using the
|
|||
|
||||
gmi.css will respect system dark mode preferences by inverting `--foreground` and `--background`.
|
||||
|
||||
```
|
||||
```html
|
||||
<html style="--foreground:#555555; --background:#9EEBCF;">
|
||||
```
|
||||
|
||||
## gmi-web(1)
|
||||
|
||||
A reference implementation of what has been discussed above.
|
||||
|
||||
*You will need*:
|
||||
- [node(1) w/ npm(1)](https://nodejs.org/en/)
|
||||
|
||||
```sh
|
||||
npm install -g git+https://codeberg.org/talon/gmi-web.git
|
||||
```
|
||||
|
||||
```
|
||||
gmi-web [--css] [files..]
|
||||
|
||||
|
@ -91,13 +87,6 @@ Options:
|
|||
--css Include gmi.css [boolean] [default: true]
|
||||
```
|
||||
|
||||
*You will need*:
|
||||
- [node(1) (w/ npm(1))](https://nodejs.org/en/) (to build/run the cli)
|
||||
|
||||
```
|
||||
npm install -g git+https://codeberg.org/talon/gmi-web.git
|
||||
```
|
||||
|
||||
<!-- TODO
|
||||
### gmi.js
|
||||
|
||||
|
|
15
example.html
15
example.html
|
@ -1,10 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="gmi.min.css">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="gmi.min.css">
|
||||
</head>
|
||||
<body contenteditable="false">
|
||||
<h1>gmi-web</h1>
|
||||
|
@ -28,9 +28,9 @@ including newlines
|
|||
</pre>
|
||||
<p><br></p>
|
||||
<ul>
|
||||
<li>milk</li>
|
||||
<li></li> <!-- empty list item -->
|
||||
<li>bread</li>
|
||||
<li>milk</li>
|
||||
<li></li> <!-- empty list item -->
|
||||
<li>bread</li>
|
||||
</ul>
|
||||
<p><br></p>
|
||||
<p>Optionally, if a link is consumable by "img", "audio" or "video" you may insert the media inline. 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 for videos and audio. "audio" tags require "display: block;" just like "a".</p>
|
||||
|
@ -41,6 +41,7 @@ including newlines
|
|||
<h3>contenteditable</h3>
|
||||
<p>
|
||||
While Gemini does not support newlines on a regular text line when editing a "p" tag in the browser
|
||||
<br>
|
||||
the default behavior for "enter" will create a "br" and not a new "p".
|
||||
</p>
|
||||
<p><br></p>
|
||||
|
|
1
gmi.min.js
vendored
1
gmi.min.js
vendored
|
@ -1 +0,0 @@
|
|||
class Gemini{static syntax={P:"",A:"=>",UL:"*",BLOCKQUOTE:">",PRE:"```",H1:"#",H2:"##",H3:"###"};static line(e,t){"string"==typeof e&&(e={content:e,type:t||"P"});let n=Gemini.render(e).dom;return{get dom(){return n},get type(){return this.dom.nodeName},set type(e){n=Gemini.render({dom:this.dom,type:e,content:Gemini.contentFrom(this.dom)}).dom},get content(){return Gemini.contentFrom(n)},set content(e){Gemini.render({dom:n,type:n.nodeName,content:e})},get editable(){return"true"===this.dom.contentEditable},set editable(e){Gemini.render({dom:this.dom,type:this.type,content:this.content,editable:e})},delete(){return this.dom.remove()},get gmi(){const e=Gemini.syntax[this.type],t=Gemini.contentFrom(this.dom).replace(/\n?$/,"");switch(this.type.toUpperCase()){case"PRE":return`${e}\n${t}\n${e}`;default:return t.split("\n").map((t=>`${""!==e?e+" ":""}${t}`)).join("\n")}},get before(){return Gemini.line(this.dom.previousElementSibling)},set before(e){this.before.dom.after(e.dom)},get after(){return Gemini.line(this.dom.nextElementSibling)},set after(e){this.after.dom.before(e.dom)}}}static render(e){if(e.dom&&e.dom.nodeName!==e.type){const t=document.createElement(e.type);e.dom.replaceWith(t),e.dom=t}else e.nodeName?e={dom:e,type:e.nodeName,content:Gemini.contentFrom(e),editable:e.contentEditable}:e.dom=e.dom||document.createElement(e.type||"P");switch(e.dom.contentEditable=e.editable||"inherit",e.type.toUpperCase()){case"A":const{href:t,content:n}=Gemini.link(e.content);e.dom.innerHTML=e.editable&&t!==n?`${t} ${n}`:n,e.dom.href=t;break;case"UL":e.dom.innerHTML=e.content.split("\n").map((e=>e.length>0?`<li>${e}</li>`:"")).join("\n");break;case"BLOCKQUOTE":e.dom.innerHTML=e.content.split("\n").map((e=>`<div>${e}</div>`)).join("\n");break;case"PRE":e.dom.textContent=e.content;break;default:e.dom.innerHTML=e.content.replace(/\n+/g,"<br>")}return e}static contentFrom(e){switch(e.nodeName.toUpperCase()){case"BLOCKQUOTE":return Array.from(e.childNodes).map((e=>e.textContent)).join("\n");case"UL":return Array.from(e.children).map((e=>e.textContent)).join("\n");case"A":const{href:t,content:n}=Gemini.link(e.textContent);return`${t||e.href} ${n}`;case"PRE":return e.textContent;default:return e.innerHTML.replace(/<br>/g,"\n")}}static link(e=""){return/((?<href>[^\s]+\/\/[^\s]+)\s)?(?<content>.+)/.exec(e).groups}constructor(e){this.root=e}get editable(){return"true"===this.root.contentEditable}set editable(e){this.root.contentEditable=e,this.lines.forEach((t=>t.editable=e))}get lines(){return Array.from(this.root.children).filter((e=>["P","BLOCKQUOTE","A","PRE","UL","H1","H2","H3"].includes(e.nodeName))).map(Gemini.line)}set lines(e){this.root.textContent="",this.root.append(...e.map((e=>e.dom)))}get source(){return this.lines.map((e=>e.gmi)).join("\n")}download(){const e=document.createElement("a");e.setAttribute("href","data:text/gemini;charset=utf-8,"+encodeURIComponent(this.source)),e.setAttribute("download",`${this.lines[0].content.replace(/\s/g,"_")}.gmi`),e.style.display="none",document.body.appendChild(e),e.click(),document.body.removeChild(e)}get foreground(){return getComputedStyle(this.root).getPropertyValue("--foreground")}set foreground(e){return this.root.style.setProperty("--foreground",e)}get background(){return getComputedStyle(this.root).getPropertyValue("--background")}set background(e){return this.root.style.setProperty("--background",e)}get size(){return getComputedStyle(this.root).getPropertyValue("--font-size")}set size(e){return this.root.style.setProperty("--font-size",e)}get lineHeight(){return getComputedStyle(this.root).getPropertyValue("--line-height")}set lineHeight(e){return this.root.style.setProperty("--line-height",e)}get serif(){return getComputedStyle(this.root).getPropertyValue("--serif")}set serif(e){return this.root.style.setProperty("--serif",e)}get sans(){return getComputedStyle(this.root).getPropertyValue("--sans")}set sans(e){return this.root.style.setProperty("--sans",e)}get mono(){return getComputedStyle(this.root).getPropertyValue("--mono")}set mono(e){return this.root.style.setProperty("--mono",e)}}
|
|
@ -19,7 +19,7 @@ module.exports = (options) => (file, cb) => {
|
|||
path.resolve(__dirname, "./gmi.min.css"),
|
||||
"utf8"
|
||||
)}</style>`
|
||||
: ""
|
||||
: "a, audio {display: block;}"
|
||||
}
|
||||
<body>
|
||||
${toHTML(JSON.parse(file.contents.toString("utf8")), options)}
|
||||
|
|
Loading…
Reference in a new issue