diff --git a/.gitignore b/.gitignore
index 3038e2b..a9c0d11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
node_modules/
capsule/
+gmi.js
+gmi.min.js
diff --git a/README.md b/README.md
index 045e6ba..1968065 100644
--- a/README.md
+++ b/README.md
@@ -104,7 +104,7 @@ Or maybe by adding a style to the `` element.
When using `gmi-web(1)` they can be customized by providing _OPTIONS_ of the same name as the CSS variable.
```sh
-gmi-web --foreground "#FFFFF" --background "#00000" \*.gmi
+gmi-web --foreground "#FFFFF" --background "#00000" *.gmi
```
# License
diff --git a/gmi.js b/gmi.js
deleted file mode 100644
index 150a603..0000000
--- a/gmi.js
+++ /dev/null
@@ -1,234 +0,0 @@
-/* gmi.js is licensed under CC0 */
-class Gemini {
- static syntax = {
- P: "",
- A: "=>",
- UL: "*",
- BLOCKQUOTE: ">",
- PRE: "```",
- H1: "#",
- H2: "##",
- H3: "###",
- };
- static line(line, type) {
- if (typeof line === "string") line = { content: line, type: type || "P" };
- let dom = Gemini.render(line).dom;
- return {
- get dom() {
- return dom;
- },
- get type() {
- return this.dom.nodeName;
- },
- set type(type) {
- dom = Gemini.render({
- dom: this.dom,
- type,
- content: Gemini.contentFrom(this.dom),
- }).dom;
- },
- get content() {
- return Gemini.contentFrom(dom);
- },
- set content(content) {
- Gemini.render({ dom, type: dom.nodeName, content });
- },
- get editable() {
- return this.dom.contentEditable === "true";
- },
- set editable(value) {
- Gemini.render({
- dom: this.dom,
- type: this.type,
- content: this.content,
- editable: value,
- });
- },
- delete() {
- return this.dom.remove();
- },
- get gmi() {
- const syntax = Gemini.syntax[this.type];
- const content = Gemini.contentFrom(this.dom).replace(/\n?$/, "");
- switch (this.type.toUpperCase()) {
- case "PRE":
- return `${syntax}\n${content}\n${syntax}`;
- break;
- default:
- return content
- .split("\n")
- .map((line) => `${syntax !== "" ? syntax + " " : ""}${line}`)
- .join("\n");
- }
- },
- get before() {
- return Gemini.line(this.dom.previousElementSibling);
- },
- set before(line) {
- this.before.dom.after(line.dom);
- },
- get after() {
- return Gemini.line(this.dom.nextElementSibling);
- },
- set after(line) {
- this.after.dom.before(line.dom);
- },
- };
- }
- static render(line) {
- if (line.dom && line.dom.nodeName !== line.type) {
- const replacement = document.createElement(line.type);
- line.dom.replaceWith(replacement);
- line.dom = replacement;
- } else if (line.nodeName) {
- line = {
- dom: line,
- type: line.nodeName,
- content: Gemini.contentFrom(line),
- editable: line.contentEditable,
- };
- } else {
- line.dom = line.dom || document.createElement(line.type || "P");
- }
- line.dom.contentEditable = line.editable || "inherit";
- switch (line.type.toUpperCase()) {
- case "A":
- const { href, content } = Gemini.link(line.content);
- line.dom.innerHTML =
- line.editable && href !== content ? `${href} ${content}` : content;
- line.dom.href = href;
- break;
- case "UL":
- line.dom.innerHTML = line.content
- .split("\n")
- .map((content) => (content.length > 0 ? `
${content}` : ""))
- .join("\n");
- break;
- case "BLOCKQUOTE":
- line.dom.innerHTML = line.content
- .split("\n")
- .map((content) => `${content}
`)
- .join("\n");
- break;
- case "PRE":
- line.dom.textContent = line.content;
- break;
- default:
- line.dom.innerHTML = line.content.replace(/\n+/g, "
");
- }
- return line;
- }
- static contentFrom(dom) {
- switch (dom.nodeName.toUpperCase()) {
- case "BLOCKQUOTE":
- return Array.from(dom.childNodes)
- .map((child) => child.textContent)
- .join("\n");
- break;
- case "UL":
- return Array.from(dom.children)
- .map((child) => child.textContent)
- .join("\n");
- break;
- case "A":
- const { href, content } = Gemini.link(dom.textContent);
- return `${href || dom.href} ${content}`;
- break;
- case "PRE":
- return dom.textContent;
- break;
- default:
- return dom.innerHTML.replace(/
/g, "\n");
- }
- }
- // TODO: rename/move/idk this is awk
- static link(content = "") {
- return /((?[^\s]+\/\/[^\s]+)\s)?(?.+)/.exec(content).groups;
- }
-
- constructor(root) {
- this.root = root;
- }
- get editable() {
- return this.root.contentEditable === "true";
- }
- set editable(value) {
- this.root.contentEditable = value;
- this.lines.forEach((line) => (line.editable = value));
- }
- get lines() {
- return Array.from(this.root.children)
- .filter((el) =>
- ["P", "BLOCKQUOTE", "A", "PRE", "UL", "H1", "H2", "H3"].includes(
- el.nodeName
- )
- )
- .map(Gemini.line);
- }
- set lines(lines) {
- this.root.textContent = "";
- this.root.append(...lines.map((line) => line.dom));
- }
- get source() {
- return this.lines.map((line) => line.gmi).join("\n");
- }
- // TODO: set source is a DOM thing, but parsing should be isomorphic
- // set source(gmi) {}
- download() {
- const el = document.createElement("a");
- el.setAttribute(
- "href",
- "data:text/gemini;charset=utf-8," + encodeURIComponent(this.source)
- );
- el.setAttribute(
- "download",
- `${this.lines[0].content.replace(/\s/g, "_")}.gmi`
- );
- el.style.display = "none";
- document.body.appendChild(el);
- el.click();
- document.body.removeChild(el);
- }
- get foreground() {
- return getComputedStyle(this.root).getPropertyValue("--foreground");
- }
- set foreground(value) {
- return this.root.style.setProperty("--foreground", value);
- }
- get background() {
- return getComputedStyle(this.root).getPropertyValue("--background");
- }
- set background(value) {
- return this.root.style.setProperty("--background", value);
- }
- get size() {
- return getComputedStyle(this.root).getPropertyValue("--font-size");
- }
- set size(value) {
- return this.root.style.setProperty("--font-size", value);
- }
- get lineHeight() {
- return getComputedStyle(this.root).getPropertyValue("--line-height");
- }
- set lineHeight(value) {
- return this.root.style.setProperty("--line-height", value);
- }
- get serif() {
- return getComputedStyle(this.root).getPropertyValue("--serif");
- }
- set serif(value) {
- return this.root.style.setProperty("--serif", value);
- }
- get sans() {
- return getComputedStyle(this.root).getPropertyValue("--sans");
- }
- set sans(value) {
- return this.root.style.setProperty("--sans", value);
- }
- get mono() {
- return getComputedStyle(this.root).getPropertyValue("--mono");
- }
- set mono(value) {
- return this.root.style.setProperty("--mono", value);
- }
-}