initial commit
This commit is contained in:
commit
61eb3ed3ec
|
@ -0,0 +1,67 @@
|
|||
# Geminut, a Gemini -> HTML and Markdown converter in Node.js
|
||||
|
||||
```
|
||||
______ _ __
|
||||
/ ____/__ ____ ___ (_)___ __ __/ /_
|
||||
/ / __/ _ \/ __ `__ \/ / __ \/ / / / __/
|
||||
/ /_/ / __/ / / / / / / / / / /_/ / /_
|
||||
\____/\___/_/ /_/ /_/_/_/ /_/\__,_/\__/
|
||||
```
|
||||
|
||||
![](gemini-icon.svg)
|
||||
|
||||
Geminut is a simple CLI software to convert a gemlog (aka gemini capsule) to HTML or markdown. The goal is to make a simplified process for the user writing in gemini specfied syntax to be able to simultaneously post to a gemlog as well as a simple HTML blog or git repo or markdown documentation without having to hand convert.
|
||||
|
||||
This documentation was written in gemtext and then converted via Geminut if you are currently reading this in HTML or markdown. See the README.md source file for the original if you're not viewing this in Gemini. The HTML output includes a gemini syntax-like css stylesheet.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
node geminut.js input.gmi output.html
|
||||
```
|
||||
|
||||
OR
|
||||
|
||||
```
|
||||
node geminut.js input.gmi output.md
|
||||
```
|
||||
|
||||
## Screenshot
|
||||
|
||||
![Screenshot of HTML output](screenshot.jpg)
|
||||
|
||||
## Method
|
||||
|
||||
gmi links are converted to .html and .md depending on output choice, as it's expected this is to be used to convert a blog. Links for HTML are wrapped in paragraph tags to ease readability of converted page. List items and links get an added newline break when converted to markdown to ease readability.
|
||||
|
||||
HTML outputs a head section and wraps output inside body, inside proper html doctype. It includes a gmi.css stylesheet by default.
|
||||
|
||||
## Similar projects
|
||||
|
||||
I have not used any of these but you may wish to check these as well:
|
||||
|
||||
[gemini-pandoc-lua-filter - A Lua filter for pandoc to output gemini text.](https://github.com/kr1sp1n/gemini-pandoc-lua-filter)
|
||||
|
||||
[gemini to html - another node.js library](https://github.com/RangerMauve/gemini-to-html)
|
||||
|
||||
[gmitohtml - conversion to HTML and daemon in Golang](https://gitlab.com/tslocum/gmitohtml)
|
||||
|
||||
[gmi2html - conversion to HTML in Zig](https://github.com/shtanton/gmi2html)
|
||||
|
||||
[Hugo to gemini - converts Hugo blogs to gemini](https://git.tdem.in/tdemin/gmnhg)
|
||||
|
||||
[md2gemini - a CLI program and Python module to convert markdown to gemini by the creator of the Amfora gemini client ](https://github.com/makeworld-the-better-one/md2gemini)
|
||||
|
||||
|
||||
## Notes and Resources
|
||||
|
||||
[Gemini spec syntax](https://gemini.circumlunar.space/docs/specification.html)
|
||||
|
||||
* Gemini unordered list items * are converted to their own individual list in HTML rather than added to a larger list.
|
||||
|
||||
[I consulted this Simple Markdown Parser with JavaScript and Regular Expressions for starter code](https://medium.com/javascript-in-plain-english/simple-markdown-parser-with-javascript-and-regular-expressions-f0c8d53449a4)
|
||||
|
||||
[I learned figcaption is the proper way to caption photos in HTML](https://www.w3schools.com/TAGS/tag_figcaption.asp)
|
||||
|
||||
[The stylesheet file was adapted from gmi-web, a public domain project](https://codeberg.org/talon/gmi-web)
|
||||
|
|
@ -0,0 +1 @@
|
|||
<svg height='100px' width='100px' fill="#000000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 75 75" style="enable-background:new 0 0 75 75;" xml:space="preserve"><g><path d="M63.8,50.8c-0.4,0-0.7,0.2-0.8,0.5h-1.7c-0.2-0.6-0.8-1-1.4-1c-0.3,0-0.6,0.1-0.8,0.3l-6.7-6.2 c0-0.1,0-0.1,0-0.2c0-0.6-0.4-1-1-1c0,0,0,0-0.1,0L38,23.6c0.2-0.3,0.4-0.6,0.4-1c0-0.3-0.1-0.5-0.2-0.7l3.7-4c0.1,0,0.1,0,0.2,0 c0.6,0,1-0.4,1-1c0-0.6-0.4-1-1-1s-1,0.4-1,1c0,0.1,0,0.2,0.1,0.3l-3.7,4c-0.2-0.1-0.4-0.1-0.6-0.1c-0.4,0-0.8,0.2-1.1,0.4L29.6,18 c0,0,0,0,0,0c0-0.6-0.4-1-1-1s-1,0.4-1,1c0,0.6,0.4,1,1,1c0.2,0,0.3-0.1,0.5-0.1l6.2,3.6c0,0.1,0,0.1,0,0.2c0,0.1,0,0.2,0,0.2 l-11.5,6c-0.2-0.1-0.3-0.2-0.5-0.2c-0.5,0-0.8,0.3-0.9,0.7l-2.9,0.7c-0.2-0.2-0.4-0.3-0.7-0.3c-0.1,0-0.1,0-0.2,0l-3.6-4.4 c0-0.1,0.1-0.2,0.1-0.4c0-0.6-0.4-1-1-1s-1,0.4-1,1c0,0.6,0.4,1,1,1c0.1,0,0.1,0,0.1,0l3.6,4.4c0,0.1-0.1,0.2-0.1,0.3 c0,0.2,0,0.3,0.1,0.4L14,38c-0.5,0-1,0.4-1,1c0,0.6,0.4,1,1,1s1-0.4,1-1c0-0.2-0.1-0.3-0.1-0.5l3.8-6.6L26.4,46 c-0.2,0.3-0.4,0.6-0.4,1c0,0.6,0.3,1,0.7,1.3l-1.7,8.9l10.4,10.3c-0.1,0.2-0.1,0.4-0.1,0.6c0,0.8,0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5 s-0.7-1.5-1.5-1.5c-0.2,0-0.5,0.1-0.6,0.2l-10-9.9l1.6-8.4c0.5-0.1,0.9-0.4,1.1-0.8L39.2,49l6.1,9.6c-0.2,0.3-0.3,0.6-0.3,0.9 c0,0.8,0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5S47.3,58,46.5,58c-0.1,0-0.2,0-0.3,0l-6.4-10L29,46.7c-0.1-0.7-0.7-1.2-1.5-1.2 c-0.1,0-0.2,0-0.2,0l-7.8-14.1c0.1-0.1,0.1-0.2,0.1-0.3l2.9-0.7c0.2,0.2,0.4,0.3,0.7,0.3c0.5,0,1-0.4,1-1l11.5-6 c0.3,0.2,0.6,0.4,1,0.4c0.1,0,0.2,0,0.3,0l13.3,19.5c-0.1,0.1-0.1,0.3-0.1,0.4c0,0.4,0.3,0.8,0.6,0.9L52.5,57 c-0.2,0.2-0.4,0.5-0.4,0.8c0,0.6,0.4,1,1,1s1-0.4,1-1c0-0.4-0.3-0.8-0.6-0.9l-1.6-11.4l6.4,5.9c0,0.1-0.1,0.3-0.1,0.4 c0,0.8,0.7,1.5,1.5,1.5c0.7,0,1.2-0.4,1.4-1h1.7c0.2,0.3,0.5,0.5,0.8,0.5c0.6,0,1-0.4,1-1C64.8,51.2,64.3,50.8,63.8,50.8z"></path></g></svg>
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,56 @@
|
|||
# Geminut, a Gemini -> HTML and Markdown converter in Node.js
|
||||
|
||||
```
|
||||
______ _ __
|
||||
/ ____/__ ____ ___ (_)___ __ __/ /_
|
||||
/ / __/ _ \/ __ `__ \/ / __ \/ / / / __/
|
||||
/ /_/ / __/ / / / / / / / / / /_/ / /_
|
||||
\____/\___/_/ /_/ /_/_/_/ /_/\__,_/\__/
|
||||
```
|
||||
|
||||
=> gemini-icon.svg
|
||||
|
||||
Geminut is a simple CLI software to convert a gemlog (aka gemini capsule) to HTML or markdown. The goal is to make a simplified process for the user writing in gemini specfied syntax to be able to simultaneously post to a gemlog as well as a simple HTML blog or git repo or markdown documentation without having to hand convert.
|
||||
|
||||
This documentation was written in gemtext and then converted via Geminut if you are currently reading this in HTML or markdown. See the README.gmi source file for the original if you're not viewing this in Gemini. The HTML output includes a gemini syntax-like css stylesheet.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
node geminut.js input.gmi output.html
|
||||
```
|
||||
|
||||
OR
|
||||
|
||||
```
|
||||
node geminut.js input.gmi output.md
|
||||
```
|
||||
|
||||
## Screenshot
|
||||
|
||||
=> screenshot.jpg Screenshot of HTML output
|
||||
|
||||
## Method
|
||||
|
||||
gmi links are converted to .html and .md depending on output choice, as it's expected this is to be used to convert a blog. Links for HTML are wrapped in paragraph tags to ease readability of converted page. List items and links get an added newline break when converted to markdown to ease readability.
|
||||
|
||||
HTML outputs a head section and wraps output inside body, inside proper html doctype. It includes a gmi.css stylesheet by default.
|
||||
|
||||
## Similar projects
|
||||
|
||||
I have not used any of these but you may wish to check these as well:
|
||||
|
||||
=> https://github.com/kr1sp1n/gemini-pandoc-lua-filter gemini-pandoc-lua-filter - A Lua filter for pandoc to output gemini text.
|
||||
=> https://github.com/RangerMauve/gemini-to-html gemini to html - another node.js library
|
||||
=> https://gitlab.com/tslocum/gmitohtml gmitohtml - conversion to HTML and daemon in Golang
|
||||
=> https://github.com/shtanton/gmi2html gmi2html - conversion to HTML in Zig
|
||||
=> https://git.tdem.in/tdemin/gmnhg Hugo to gemini - converts Hugo blogs to gemini
|
||||
=> https://github.com/makeworld-the-better-one/md2gemini md2gemini - a CLI program and Python module to convert markdown to gemini by the creator of the Amfora gemini client
|
||||
|
||||
## Notes and Resources
|
||||
|
||||
=> https://gemini.circumlunar.space/docs/specification.html Gemini spec syntax
|
||||
* Gemini unordered list items * are converted to their own individual list in HTML rather than added to a larger list.
|
||||
=> https://medium.com/javascript-in-plain-english/simple-markdown-parser-with-javascript-and-regular-expressions-f0c8d53449a4 I consulted this Simple Markdown Parser with JavaScript and Regular Expressions for starter code
|
||||
=> https://www.w3schools.com/TAGS/tag_figcaption.asp I learned figcaption is the proper way to caption photos in HTML
|
||||
=> https://codeberg.org/talon/gmi-web The stylesheet file was adapted from gmi-web, a public domain project
|
|
@ -0,0 +1,168 @@
|
|||
const path = require("path");
|
||||
const fs = require("fs"),
|
||||
readline = require("readline");
|
||||
|
||||
let preformattedText = false;
|
||||
//take input
|
||||
const args = process.argv.slice(2);
|
||||
const inputFile = args[0];
|
||||
const outputFile = args[1];
|
||||
let toMarkdown = false;
|
||||
|
||||
const header =
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="generator" content="geminut" />
|
||||
<link rel="stylesheet" href="gmi.css">
|
||||
|
||||
<title>` +
|
||||
outputFile +
|
||||
`</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
`;
|
||||
|
||||
const footer = `
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const inputExtension = path.extname(inputFile);
|
||||
const outputExtension = path.extname(outputFile);
|
||||
if (outputExtension == ".md") {
|
||||
toMarkdown = true;
|
||||
}
|
||||
|
||||
if (!inputFile || !outputFile) {
|
||||
console.log("USAGE: node geminut.js <input.gmi> {output.html | output.md}");
|
||||
process.exit(1);
|
||||
}
|
||||
if (inputExtension !== ".gmi") {
|
||||
console.log("Input must be a gemini .gmi file");
|
||||
console.log("USAGE: node geminut.js <input.gmi> {output.html | output.md}");
|
||||
process.exit(1);
|
||||
}
|
||||
if (!(outputExtension == ".html" || outputExtension == ".md")) {
|
||||
console.log("Output must be a .html HTML or .md Markdown file");
|
||||
console.log("USAGE: node geminut.js <input.gmi> {output.html | output.md}");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (fs.existsSync(outputFile)) {
|
||||
//if already exists we remove first
|
||||
fs.unlinkSync(outputFile);
|
||||
}
|
||||
|
||||
if (!toMarkdown) {
|
||||
fs.appendFileSync(outputFile, header);
|
||||
}
|
||||
|
||||
const rd = readline.createInterface({
|
||||
input: fs.createReadStream(inputFile),
|
||||
//output: process.stdout,
|
||||
console: false
|
||||
});
|
||||
|
||||
rd.on("line", function(line) {
|
||||
// console.log(line);
|
||||
let data;
|
||||
|
||||
if (toMarkdown) {
|
||||
data = parseGemtextToMarkdown(line);
|
||||
fs.appendFileSync(outputFile, data + "\n");
|
||||
} else {
|
||||
data = parseGemtextToHTML(line);
|
||||
fs.appendFileSync(outputFile, data + "\n");
|
||||
}
|
||||
});
|
||||
|
||||
rd.on("close", function() {
|
||||
if (!toMarkdown) {
|
||||
fs.appendFileSync(outputFile, footer);
|
||||
}
|
||||
});
|
||||
|
||||
function parseGemtextToHTML(gmiText) {
|
||||
let htmlText;
|
||||
|
||||
//CODE BLOCK SECTION PARSER / CONVERTER
|
||||
if (gmiText.match(/^```*(.*$)/gim)) {
|
||||
//We are triggering a pre/codeblock to start or end
|
||||
//check for code block toggle
|
||||
if (!preformattedText) {
|
||||
htmlText = gmiText.replace(/^```*(.*$)/gim, "<pre>$1");
|
||||
} else {
|
||||
htmlText = gmiText.replace(/^```*(.*$)/gim, "</pre>$1");
|
||||
}
|
||||
preformattedText = !preformattedText; //toggle!
|
||||
//END CODE BLOCK SECTION
|
||||
} else {
|
||||
//we are not on a line with pre/codeblock
|
||||
|
||||
if (!preformattedText) {
|
||||
//outside of a codeblock
|
||||
htmlText = gmiText
|
||||
.replace(/^### (.*$)/gim, "<h3>$1</h3>")
|
||||
.replace(/^## (.*$)/gim, "<h2>$1</h2>")
|
||||
.replace(/^# (.*$)/gim, "<h1>$1</h1>")
|
||||
.replace(/^\* (.*$)/gim, "<ul><li>$1</ul></li>") //hack, would be better to add to ul list
|
||||
.replace(/^\> (.*$)/gim, "<blockquote>$1</blockquote>")
|
||||
.replace(
|
||||
/^=>\s+(\S+(.jpg|.jpeg|.png|.gif|.svg))\s*(.*)/gim,
|
||||
"<figure>\n<img src='$1' alt='$3'>\n<figcaption>$3</figcaption>\n</figure>"
|
||||
) //for images, must be before links replacement below or else will be captured and converted
|
||||
.replace(/^=>\s+(\S+)\s*(.*)/gim, "<p><a href='$1'>$2</a></p>") //close, need to remove gmi
|
||||
.replace(".gmi", ".html") //a hack. will break for remote *.gmi url's
|
||||
.replace(/^([a-zA-Z0-9].*$)/gim, "<p>$1</p>"); //lines starting with text or number are paragraph
|
||||
} else {
|
||||
//we are inside a pre/codeblock
|
||||
|
||||
htmlText = gmiText;
|
||||
}
|
||||
}
|
||||
|
||||
return htmlText;
|
||||
}
|
||||
|
||||
function parseGemtextToMarkdown(gmiText) {
|
||||
let mdText;
|
||||
|
||||
//CODE BLOCK SECTION PARSER / CONVERTER
|
||||
if (gmiText.match(/^```*(.*$)/gim)) {
|
||||
//We are triggering a pre/codeblock to start or end
|
||||
//check for code block toggle
|
||||
if (!preformattedText) {
|
||||
mdText = gmiText.replace(/^```*(.*$)/gim, "```$1");
|
||||
} else {
|
||||
mdText = gmiText.replace(/^```*(.*$)/gim, "```$1");
|
||||
}
|
||||
preformattedText = !preformattedText; //toggle!
|
||||
//END CODE BLOCK SECTION
|
||||
} else {
|
||||
//we are not on a line with pre/codeblock
|
||||
|
||||
if (!preformattedText) {
|
||||
//outside of a codeblock
|
||||
mdText = gmiText
|
||||
.replace(
|
||||
/^=>\s+(\S+(.jpg|.jpeg|.png|.gif|.svg))\s*(.*)/gim,
|
||||
"![$3]($1)"
|
||||
) //for images, must be before links replacement below or else will be captured and converted
|
||||
.replace(/^\* (.*$)/gim, "* $1\n") //hack, would be better to add to ul list
|
||||
.replace(/^=>\s+(\S+)\s*(.*)/gim, "[$2]($1)\n") //close, need to remove gmi, add break
|
||||
.replace(".gmi", ".md"); //a hack. will break for remote *.gmi url's
|
||||
} else {
|
||||
//we are inside a pre/codeblock
|
||||
|
||||
mdText = gmiText;
|
||||
}
|
||||
}
|
||||
|
||||
return mdText;
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
:root {
|
||||
--body-width: 48rem;
|
||||
--serif: georgia, times, serif;
|
||||
--sans-serif: avenir, helvetica, arial, sans-serif;
|
||||
--mono: consolas, monaco, monospace;
|
||||
--foreground: black;
|
||||
--background: Honeydew;
|
||||
|
||||
--a-decoration: none;
|
||||
--a-style: normal;
|
||||
--a-prefix: "⇒";
|
||||
--ul-bullet: "*";
|
||||
--p-indent: 0rem;
|
||||
--quote-style: italic;
|
||||
|
||||
--p-size: 1.25rem;
|
||||
--a-size: var(--p-size);
|
||||
--pre-size: 1rem;
|
||||
--h1-size: 3rem;
|
||||
--h2-size: 2.25rem;
|
||||
--h3-size: 1.5rem;
|
||||
--ul-size: var(--p-size);
|
||||
--quote-size: var(--p-size);
|
||||
|
||||
--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;
|
||||
}
|
||||
|
||||
body {
|
||||
max-width: var(--body-width);
|
||||
padding: 0.5rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
p,
|
||||
a,
|
||||
pre,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
ul,
|
||||
blockquote,
|
||||
img,
|
||||
audio,
|
||||
video {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-family: var(--sans-serif);
|
||||
line-height: var(--h-line-height);
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: var(--p-size);
|
||||
font-family: var(--serif);
|
||||
text-indent: var(--p-indent);
|
||||
line-height: var(--p-line-height);
|
||||
margin: 1.5vmin;
|
||||
}
|
||||
|
||||
a::before {
|
||||
font-size: var(--a-size);
|
||||
font-family: var(--mono);
|
||||
content: var(--a-prefix);
|
||||
line-height: var(--a-line-height);
|
||||
padding-right: 0.25rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: var(--a-size);
|
||||
font-style: var(--a-style);
|
||||
font-family: var(--serif);
|
||||
text-decoration: var(--a-decoration);
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: var(--pre-size);
|
||||
font-family: var(--mono);
|
||||
line-height: var(--pre-line-height);
|
||||
padding: 1.25rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: var(--h1-size);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: var(--h2-size);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: var(--h3-size);
|
||||
}
|
||||
|
||||
ul {
|
||||
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(--mono);
|
||||
content: var(--ul-bullet);
|
||||
vertical-align: middle;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
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;
|
||||
}
|
||||
|
||||
/* foreground and background colors */
|
||||
html,
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
p,
|
||||
a,
|
||||
ul,
|
||||
blockquote,
|
||||
pre::selection {
|
||||
color: var(--foreground);
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 0.5rem solid var(--foreground);
|
||||
}
|
||||
|
||||
pre,
|
||||
::selection,
|
||||
a:hover {
|
||||
color: var(--background);
|
||||
background-color: var(--foreground);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html,
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
p,
|
||||
a,
|
||||
ul,
|
||||
blockquote,
|
||||
pre::selection {
|
||||
color: var(--background);
|
||||
background-color: var(--foreground);
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 0.5rem solid var(--background);
|
||||
}
|
||||
|
||||
pre,
|
||||
::selection,
|
||||
a:hover {
|
||||
color: var(--foreground);
|
||||
background-color: var(--background);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="generator" content="geminut" />
|
||||
<link rel="stylesheet" href="gmi.css">
|
||||
|
||||
<title>index.html</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1>Geminut, a Gemini -> HTML and Markdown converter in Node.js</h1>
|
||||
|
||||
<pre>
|
||||
______ _ __
|
||||
/ ____/__ ____ ___ (_)___ __ __/ /_
|
||||
/ / __/ _ \/ __ `__ \/ / __ \/ / / / __/
|
||||
/ /_/ / __/ / / / / / / / / / /_/ / /_
|
||||
\____/\___/_/ /_/ /_/_/_/ /_/\__,_/\__/
|
||||
</pre>
|
||||
|
||||
<figure>
|
||||
<img src='gemini-icon.svg' alt=''>
|
||||
<figcaption></figcaption>
|
||||
</figure>
|
||||
|
||||
<p>Geminut is a simple CLI software to convert a gemlog (aka gemini capsule) to HTML or markdown. The goal is to make a simplified process for the user writing in gemini specfied syntax to be able to simultaneously post to a gemlog as well as a simple HTML blog or git repo or markdown documentation without having to hand convert.</p>
|
||||
|
||||
<p>This documentation was written in gemtext and then converted via Geminut if you are currently reading this in HTML or markdown. See the README.html source file for the original if you're not viewing this in Gemini. The HTML output includes a gemini syntax-like css stylesheet.</p>
|
||||
|
||||
<h2>Usage</h2>
|
||||
|
||||
<pre>
|
||||
node geminut.js input.gmi output.html
|
||||
</pre>
|
||||
|
||||
<p>OR</p>
|
||||
|
||||
<pre>
|
||||
node geminut.js input.gmi output.md
|
||||
</pre>
|
||||
|
||||
<h2>Screenshot</h2>
|
||||
|
||||
<figure>
|
||||
<img src='screenshot.jpg' alt='Screenshot of HTML output'>
|
||||
<figcaption>Screenshot of HTML output</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2>Method</h2>
|
||||
|
||||
<p>gmi links are converted to .html and .md depending on output choice, as it's expected this is to be used to convert a blog. Links for HTML are wrapped in paragraph tags to ease readability of converted page. List items and links get an added newline break when converted to markdown to ease readability.</p>
|
||||
|
||||
<p>HTML outputs a head section and wraps output inside body, inside proper html doctype. It includes a gmi.css stylesheet by default. </p>
|
||||
|
||||
<h2>Similar projects</h2>
|
||||
|
||||
<p>I have not used any of these but you may wish to check these as well: </p>
|
||||
|
||||
<p><a href='https://github.com/kr1sp1n/gemini-pandoc-lua-filter'>gemini-pandoc-lua-filter - A Lua filter for pandoc to output gemini text.</a></p>
|
||||
<p><a href='https://github.com/RangerMauve/gemini-to-html'>gemini to html - another node.js library</a></p>
|
||||
<p><a href='https://gitlab.com/tslocum/gmitohtml'>gmitohtml - conversion to HTML and daemon in Golang</a></p>
|
||||
<p><a href='https://github.com/shtanton/gmi2html'>gmi2html - conversion to HTML in Zig</a></p>
|
||||
<p><a href='https://git.tdem.in/tdemin/gmnhg'>Hugo to gemini - converts Hugo blogs to gemini</a></p>
|
||||
<p><a href='https://github.com/makeworld-the-better-one/md2gemini'>md2gemini - a CLI program and Python module to convert markdown to gemini by the creator of the Amfora gemini client </a></p>
|
||||
|
||||
<h2>Notes and Resources </h2>
|
||||
|
||||
<p><a href='https://gemini.circumlunar.space/docs/specification.html'>Gemini spec syntax</a></p>
|
||||
<ul><li>Gemini unordered list items * are converted to their own individual list in HTML rather than added to a larger list. </ul></li>
|
||||
<p><a href='https://medium.com/javascript-in-plain-english/simple-markdown-parser-with-javascript-and-regular-expressions-f0c8d53449a4'>I consulted this Simple Markdown Parser with JavaScript and Regular Expressions for starter code</a></p>
|
||||
<p><a href='https://www.w3schools.com/TAGS/tag_figcaption.asp'>I learned figcaption is the proper way to caption photos in HTML</a></p>
|
||||
<p><a href='https://codeberg.org/talon/gmi-web'>The stylesheet file was adapted from gmi-web, a public domain project</a></p>
|
||||
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
Loading…
Reference in New Issue