diff --git a/README.md b/README.md
index 3f41137..43adc9a 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,8 @@
-# GitBlog.md
-
-
[](https://travis-ci.org/Klemek/GitBlog.md)
[](https://coveralls.io/github/Klemek/GitBlog.md?branch=master)
+# GitBlog.md
+
A static blog using Markdown pulled from your git repository.
> Step 1 : ```$ vi 2019/06/21/index.md```
@@ -245,6 +244,9 @@ Any URL like `/year/month/day/anything/` will redirect to this article (and link
It allows you to add math equations to your articles by simply writing LaTeX between `$$` for full size (and between $ for inline) (more info [here](https://www.mathjax.org/))
* **PlantUML**
It allows you to add UML diagrams with PlantUML Syntax between `@startuml` and `@enduml` (more info [here](http://www.plantuml.com))
+* **fa-diagrams**
+ It allows you to define SVG diagrams with Font-Awesome icons in YAML between `@startfad` and `@endfad` (more info [here](https://github.com/Klemek/fa-diagrams))
+
## Configuration
[back to top](#gitblog-md)
@@ -273,6 +275,8 @@ Any URL like `/year/month/day/anything/` will redirect to this article (and link
activate MathJax equations formatting
* `plantuml` (default: true)
activate PlantUML diagram rendering
+ * `fa-diagrams` (default: true)
+ activate fa-diagrams rendering
* `home`
* `title` (default: GitBlog.md)
the title of your blog, **strongly advised to be changed**
diff --git a/package-lock.json b/package-lock.json
index e7cf978..356f460 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "gitblog.md",
- "version": "1.1.5",
+ "version": "1.2.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1337,7 +1337,6 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
"requires": {
"sprintf-js": "~1.0.2"
}
@@ -3190,6 +3189,14 @@
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
+ "fa-diagrams": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/fa-diagrams/-/fa-diagrams-1.0.3.tgz",
+ "integrity": "sha512-z9pFYYnc6s1sUs4lq+DY2m5ddLCKN3jdo5O6hv450WwjiQ7otk1RoGQsvpMcwSU1kMEzPJUI6AeTVvzyIElhwQ==",
+ "requires": {
+ "xml-js": "^1.6.11"
+ }
+ },
"fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
@@ -6617,7 +6624,6 @@
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
- "dev": true,
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -6626,8 +6632,7 @@
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
}
}
},
@@ -9087,8 +9092,7 @@
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
- "dev": true
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"sshpk": {
"version": "1.16.1",
@@ -9777,6 +9781,14 @@
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
"integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU="
},
+ "xml-js": {
+ "version": "1.6.11",
+ "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
+ "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
+ "requires": {
+ "sax": "^1.2.4"
+ }
+ },
"xml-name-validator": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
diff --git a/package.json b/package.json
index b05cb18..ebb236b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "gitblog.md",
- "version": "1.2.5",
+ "version": "1.2.6",
"description": "A static blog using Markdown pulled from your git repository.",
"main": "src/server.js",
"dependencies": {
@@ -8,6 +8,8 @@
"crypto": "^1.0.1",
"ejs": "^2.6.2",
"express": "^4.17.1",
+ "fa-diagrams": "^1.0.3",
+ "js-yaml": "^3.13.1",
"mathjax-node": "^2.1.1",
"ncp": "^2.0.0",
"node-prismjs": "^0.1.2",
diff --git a/sample_data/article/index.md b/sample_data/article/index.md
index 2154e57..481db60 100644
--- a/sample_data/article/index.md
+++ b/sample_data/article/index.md
@@ -19,6 +19,7 @@ If you see this page, that means it's working
* [Spoilers](#spoilers)
* [Math Equations](#mathequations)
* [UML](#uml)
+* [Diagrams](#diagrams)
* [Youtube Videos](#youtubevideos)
### Headers
@@ -253,6 +254,30 @@ showdown -left-> express : 4. html
express -up-> web : 5. html
@enduml
+### Diagrams
+[Back to top](#top)
+
+You can use [fa-diagrams](https://github.com/Klemek/fa-diagrams) with `@startfad` and `@endfad` tags and using YAML inside
+
+@startuml
+nodes:
+ - name: node1
+ icon: laptop-code
+ color: '#4E342E'
+ bottom: my app
+ - name: node2
+ icon: globe
+ color: '#455A64'
+ bottom: world
+links:
+ - from: node1
+ to: node2
+ color: '#333333'
+ top:
+ icon: envelope
+ bottom: '"hello"'
+@enduml
+
### Youtube Videos
[Back to top](#top)
diff --git a/sample_data/home/index.ejs b/sample_data/home/index.ejs
index 0517fdc..aeb4bc4 100644
--- a/sample_data/home/index.ejs
+++ b/sample_data/home/index.ejs
@@ -6,16 +6,18 @@
- <%= info.title %>
+ <%= info.title %>
<%= info.description %>
Articles in this blog :
<% articles.forEach((article) => { %>
<% }); %>
<%- include('footer'); %>
diff --git a/sample_data/home/style.css b/sample_data/home/style.css
index e0b0dcc..01bbc72 100644
--- a/sample_data/home/style.css
+++ b/sample_data/home/style.css
@@ -16,7 +16,7 @@ body {
}
main {
- max-width: 42rem;
+ max-width: 45rem;
padding: 2rem;
margin: auto;
background-color: #F0F0F0;
@@ -54,6 +54,13 @@ pre {
padding: 10px 16px;
}
+:not(pre) > code {
+ padding: 0.25em 0.5em;
+ border-radius: 0.25em;
+ background: #DDD;
+ font-size: 90%;
+}
+
blockquote {
border-left: 0.5em solid #ccc;
padding-left: 1em;
@@ -108,10 +115,11 @@ main.article div.header a.link-home {
line-height: 2.4;
}
-main.article div.header h1, main.article div.header h2 {
+main.article div.header h1, main.article div.header h2, .title {
margin-top: 0.85em;
margin-bottom: 0.25em;
font-size: 2em;
+ font-weight: bold;
}
main.article div.header h1 a, main.article div.header h2 a, div.article h3 a {
@@ -129,6 +137,12 @@ div.article {
div.article h3 {
font-size: 1.3em;
margin:0;
+ color: #3C3CA1;
+}
+
+div.article a {
+ text-decoration: none;
+ color: inherit;
}
div.article img{
@@ -138,6 +152,15 @@ div.article img{
margin-top:0.25em;
}
+div.article:hover {
+ opacity: 0.9;
+}
+
+div.article:active {
+ opacity: 0.8;
+}
+
+
#text {
text-align: justify;
hyphens: auto;
@@ -147,7 +170,7 @@ div.article img{
text-align: left;
}
-#text img {
+#text img, #text svg {
max-width: 100%;
height: auto;
}
diff --git a/sample_data/home/template.ejs b/sample_data/home/template.ejs
index e2590c1..f1f4c82 100644
--- a/sample_data/home/template.ejs
+++ b/sample_data/home/template.ejs
@@ -9,7 +9,7 @@
<%- article.content %>
diff --git a/src/config.default.json b/src/config.default.json
index 63e3f92..79fe3f3 100644
--- a/src/config.default.json
+++ b/src/config.default.json
@@ -10,7 +10,8 @@
"webhook": true,
"prism": true,
"mathjax": true,
- "plantuml": true
+ "plantuml": true,
+ "fa-diagrams": true
},
"home": {
"title": "GitBlog.md",
diff --git a/src/renderer.js b/src/renderer.js
index 6094f08..af8c3f5 100644
--- a/src/renderer.js
+++ b/src/renderer.js
@@ -5,6 +5,54 @@ const showdown = require('showdown');
module.exports = (config) => {
const converter = new showdown.Converter(config['showdown']);
+ /**
+ * get parts outside of codes/scripts
+ * @param {string} data
+ * @returns {{index:number, end:number, text:string}[]} parts
+ */
+ const getParts = (data) => {
+ let parts = [];
+ let match;
+ let i = 0;
+ while ((match = /```/m.exec(data.slice(i)))) {
+ parts.push({
+ index: i,
+ text: data.slice(i, i + match.index),
+ });
+ i += match.index + match[0].length;
+ }
+ if (i < data.length)
+ parts.push({
+ index: i,
+ text: data.slice(i, data.length),
+ });
+
+ parts = parts.filter((p, i) => i % 2 === 0); //filter out code parts
+
+ // detect scripts outside of code
+ parts.forEach((p, pi) => {
+ let i = 0;
+ const subParts = [];
+ while ((match = /(\n\n``````kenobi';
+ const parts = renderer.getParts(data);
+ expect(parts).toEqual([
+ {
+ index: 0,
+ end: 12,
+ text: 'Hello\nthere\n'
+ },
+ {
+ index: 22,
+ end: 30,
+ text: '\ngeneral'
+ },
+ {
+ index: 53,
+ end: 54,
+ text: '\n'
+ },
+ {
+ index: 78,
+ end: 79,
+ text: '\n'
+ },
+ {
+ index: 109,
+ end: 115,
+ text: 'kenobi'
+ },
+ ]);
+ });
+});
+
describe('Test Showdown', () => {
test('normal', (done) => {
renderer.renderShowDown('# Hello', (html) => {
@@ -112,6 +155,13 @@ describe('Test PlantUML', () => {
});
});
+ test('plantuml ignored in code', (done) => {
+ renderer.renderPlantUML('code:\n```@startuml\nBob -> Alice : hello\n@enduml```\n ```@startuml``` @enduml', (data) => {
+ expect(data).toBe('code:\n```@startuml\nBob -> Alice : hello\n@enduml```\n ```@startuml``` @enduml');
+ done();
+ });
+ });
+
test('plantuml multiple uml', (done) => {
renderer.renderPlantUML('@startuml\nBob -> Alice : hello\n@enduml\n@startuml\nBob -> Alice : hello\n@enduml', (data) => {
expect(data).toBe('
\n
');
@@ -157,6 +207,12 @@ describe('Test MathJax', () => {
done();
});
});
+ test('no eq in code / script', (done) => {
+ renderer.renderMathJax('this code is ```start $a$ end $$hello$$``` beautiful \n```$no eq$```', (data) => {
+ expect(data).toBe('this code is ```start $a$ end $$hello$$``` beautiful \n```$no eq$```');
+ done();
+ });
+ });
test('multiple eq', (done) => {
renderer.renderMathJax('$$\n\nA\n\n$$\nstart $a$ end\n$$\n\nA\n\n$$', (data) => {
expect(data).toBe('' +
@@ -182,6 +238,34 @@ describe('Test MathJax', () => {
});
});
+describe('Test fa-diagrams', () => {
+ test('no fa-diagrams', (done) => {
+ config['modules']['fa-diagrams'] = false;
+ renderer.renderFaDiagrams('@startfad\noptions:\n\trendering:\t\tcolor:red\n\n@endfad', (data) => {
+ expect(data).toBe('@startfad\noptions:\n\trendering:\t\tcolor:red\n\n@endfad');
+ done();
+ });
+ });
+ test('no fa-diagrams in code', (done) => {
+ renderer.renderFaDiagrams('code:\n```\n@startfad\noptions:\n\trendering:\t\tcolor:red\n\n@endfad\n```', (data) => {
+ expect(data).toBe('code:\n```\n@startfad\noptions:\n\trendering:\t\tcolor:red\n\n@endfad\n```');
+ done();
+ });
+ });
+ test('valid fa-diagrams', (done) => {
+ renderer.renderFaDiagrams('before\n@startfad\noptions:\n rendering:\n color: red\n@endfad\nafter', (data) => {
+ expect(data).toBe('before\n\nafter');
+ done();
+ });
+ });
+ test('invalid yaml', (done) => {
+ renderer.renderFaDiagrams('before\n@startfad\noptions:\n@endfad\nafter', (data) => {
+ expect(data).toBe('before\nTypeError: Cannot convert undefined or null to object\nafter');
+ done();
+ });
+ });
+});
+
describe('Test render', () => {
test('invalid file', (done) => {
renderer.render('invalid file', (err, html) => {