syntax highlight + TOC scroll + other content parsing improvements
This commit is contained in:
parent
1ad03a3d1f
commit
e94abf9466
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
|||||||
"use strict";jQuery(document).ready(function(e){e("a").smoothScroll({speed:"auto"})});
|
"use strict";jQuery(document).ready(function(e){e("a").smoothScroll({speed:400,offset:-20});new Sticky(".stickyscroll")});
|
File diff suppressed because one or more lines are too long
@ -3,7 +3,10 @@
|
|||||||
jQuery( document ).ready(function( $ ) {
|
jQuery( document ).ready(function( $ ) {
|
||||||
|
|
||||||
$('a').smoothScroll({
|
$('a').smoothScroll({
|
||||||
speed: 'auto'
|
speed: 400,
|
||||||
|
offset: -20
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var sticky = new Sticky('.stickyscroll');
|
||||||
|
|
||||||
});
|
});
|
@ -8,4 +8,4 @@ $warning: #f68b39;
|
|||||||
|
|
||||||
@import './layout/_header';
|
@import './layout/_header';
|
||||||
@import './layout/_footer';
|
@import './layout/_footer';
|
||||||
|
@import './layout/_content';
|
32
client/scss/layout/_content.scss
Normal file
32
client/scss/layout/_content.scss
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
.mkcontent {
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
border-bottom: 1px dotted $grey-light;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: $grey-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.toc-anchor {
|
||||||
|
font-size: 80%;
|
||||||
|
color: $purple;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
padding: 0;
|
||||||
|
border-bottom: 1px solid $grey-light;
|
||||||
|
border-right: 1px solid $grey-light;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre + p {
|
||||||
|
padding-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.right {
|
||||||
|
float:right;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -11,7 +11,7 @@ router.get('/', (req, res) => {
|
|||||||
var Promise = require('bluebird');
|
var Promise = require('bluebird');
|
||||||
var fs = Promise.promisifyAll(require("fs"));
|
var fs = Promise.promisifyAll(require("fs"));
|
||||||
|
|
||||||
fs.readFileAsync("repo/Gollum.md", "utf8").then(function(contents) {
|
fs.readFileAsync("repo/Home.md", "utf8").then(function(contents) {
|
||||||
let pageData = mark.parse(contents);
|
let pageData = mark.parse(contents);
|
||||||
if(!pageData.title) {
|
if(!pageData.title) {
|
||||||
pageData.title = 'Gollum';
|
pageData.title = 'Gollum';
|
||||||
|
@ -22,7 +22,8 @@ var paths = {
|
|||||||
'./node_modules/lodash/lodash.min.js',
|
'./node_modules/lodash/lodash.min.js',
|
||||||
'./node_modules/jquery/dist/jquery.min.js',
|
'./node_modules/jquery/dist/jquery.min.js',
|
||||||
'./node_modules/vue/dist/vue.min.js',
|
'./node_modules/vue/dist/vue.min.js',
|
||||||
'./node_modules/jquery-smooth-scroll/jquery.smooth-scroll.min.js'
|
'./node_modules/jquery-smooth-scroll/jquery.smooth-scroll.min.js',
|
||||||
|
'./node_modules/sticky-js/dist/sticky.min.js'
|
||||||
],
|
],
|
||||||
scriptapps: [
|
scriptapps: [
|
||||||
'./client/js/components/*.js',
|
'./client/js/components/*.js',
|
||||||
@ -32,7 +33,8 @@ var paths = {
|
|||||||
'./client/js/**/*.js'
|
'./client/js/**/*.js'
|
||||||
],
|
],
|
||||||
csslibs: [
|
csslibs: [
|
||||||
'./node_modules/font-awesome/css/font-awesome.min.css'
|
'./node_modules/font-awesome/css/font-awesome.min.css',
|
||||||
|
'./node_modules/highlight.js/styles/default.css'
|
||||||
],
|
],
|
||||||
cssapps: [
|
cssapps: [
|
||||||
'./client/scss/app.scss'
|
'./client/scss/app.scss'
|
||||||
|
@ -9,7 +9,10 @@ var Promise = require('bluebird'),
|
|||||||
mdFootnote = require('markdown-it-footnote'),
|
mdFootnote = require('markdown-it-footnote'),
|
||||||
mdExternalLinks = require('markdown-it-external-links'),
|
mdExternalLinks = require('markdown-it-external-links'),
|
||||||
mdExpandTabs = require('markdown-it-expand-tabs'),
|
mdExpandTabs = require('markdown-it-expand-tabs'),
|
||||||
|
mdAttrs = require('markdown-it-attrs'),
|
||||||
|
hljs = require('highlight.js'),
|
||||||
slug = require('slug'),
|
slug = require('slug'),
|
||||||
|
cheerio = require('cheerio'),
|
||||||
_ = require('lodash');
|
_ = require('lodash');
|
||||||
|
|
||||||
// Load plugins
|
// Load plugins
|
||||||
@ -17,7 +20,15 @@ var Promise = require('bluebird'),
|
|||||||
var mkdown = md({
|
var mkdown = md({
|
||||||
html: true,
|
html: true,
|
||||||
linkify: true,
|
linkify: true,
|
||||||
typography: true
|
typography: true,
|
||||||
|
highlight: function (str, lang) {
|
||||||
|
if (lang && hljs.getLanguage(lang)) {
|
||||||
|
try {
|
||||||
|
return '<pre class="hljs"><code>' + hljs.highlight(lang, str, true).value + '</code></pre>';
|
||||||
|
} catch (__) {}
|
||||||
|
}
|
||||||
|
return '<pre class="hljs"><code>' + hljs.highlightAuto(str).value + '</code></pre>';
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.use(mdEmoji)
|
.use(mdEmoji)
|
||||||
.use(mdTaskLists)
|
.use(mdTaskLists)
|
||||||
@ -33,7 +44,8 @@ var mkdown = md({
|
|||||||
})
|
})
|
||||||
.use(mdExpandTabs, {
|
.use(mdExpandTabs, {
|
||||||
tabWidth: 4
|
tabWidth: 4
|
||||||
});
|
})
|
||||||
|
.use(mdAttrs);
|
||||||
|
|
||||||
// Rendering rules
|
// Rendering rules
|
||||||
|
|
||||||
@ -41,13 +53,23 @@ mkdown.renderer.rules.emoji = function(token, idx) {
|
|||||||
return '<i class="twa twa-' + token[idx].markup + '"></i>';
|
return '<i class="twa twa-' + token[idx].markup + '"></i>';
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse markdown headings tree
|
mkdown.inline.ruler.push('internal_link', (state) => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse markdown content and build TOC tree
|
||||||
|
*
|
||||||
|
* @param {(Function|string)} content Markdown content
|
||||||
|
* @return {Array} TOC tree
|
||||||
|
*/
|
||||||
const parseTree = (content) => {
|
const parseTree = (content) => {
|
||||||
|
|
||||||
let tokens = md().parse(content, {});
|
let tokens = md().parse(content, {});
|
||||||
let tocArray = [];
|
let tocArray = [];
|
||||||
|
|
||||||
|
//-> Extract headings and their respective levels
|
||||||
|
|
||||||
for (let i = 0; i < tokens.length; i++) {
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
if (tokens[i].type !== "heading_close") {
|
if (tokens[i].type !== "heading_close") {
|
||||||
continue
|
continue
|
||||||
@ -75,6 +97,12 @@ const parseTree = (content) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-> Exclude levels deeper than 2
|
||||||
|
|
||||||
|
_.remove(tocArray, (n) => { return n.level > 2; });
|
||||||
|
|
||||||
|
//-> Build tree from flat array
|
||||||
|
|
||||||
return _.reduce(tocArray, (tree, v) => {
|
return _.reduce(tocArray, (tree, v) => {
|
||||||
let treeLength = tree.length - 1;
|
let treeLength = tree.length - 1;
|
||||||
if(v.level < 2) {
|
if(v.level < 2) {
|
||||||
@ -98,23 +126,42 @@ const parseTree = (content) => {
|
|||||||
};
|
};
|
||||||
let lastNodePath = GetNodePath();
|
let lastNodePath = GetNodePath();
|
||||||
let lastNode = _.get(tree[treeLength], lastNodePath);
|
let lastNode = _.get(tree[treeLength], lastNodePath);
|
||||||
lastNode.push({
|
if(lastNode) {
|
||||||
content: v.content,
|
lastNode.push({
|
||||||
anchor: v.anchor,
|
content: v.content,
|
||||||
nodes: []
|
anchor: v.anchor,
|
||||||
});
|
nodes: []
|
||||||
_.set(tree[treeLength], lastNodePath, lastNode);
|
});
|
||||||
|
_.set(tree[treeLength], lastNodePath, lastNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return tree;
|
return tree;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse markdown content to HTML
|
||||||
|
*
|
||||||
|
* @param {String} content Markdown content
|
||||||
|
* @return {String} HTML formatted content
|
||||||
|
*/
|
||||||
|
const parseContent = (content) => {
|
||||||
|
|
||||||
|
let output = mkdown.render(content);
|
||||||
|
let cr = cheerio.load(output);
|
||||||
|
cr('table').addClass('table is-bordered is-striped is-narrow');
|
||||||
|
output = cr.html();
|
||||||
|
|
||||||
|
return output;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
parse(content) {
|
parse(content) {
|
||||||
return {
|
return {
|
||||||
html: mkdown.render(content),
|
html: parseContent(content),
|
||||||
tree: parseTree(content)
|
tree: parseTree(content)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
"bluebird": "^3.4.1",
|
"bluebird": "^3.4.1",
|
||||||
"body-parser": "^1.15.2",
|
"body-parser": "^1.15.2",
|
||||||
"bulma": "^0.1.2",
|
"bulma": "^0.1.2",
|
||||||
|
"cheerio": "^0.20.0",
|
||||||
"compression": "^1.6.2",
|
"compression": "^1.6.2",
|
||||||
"connect-flash": "^0.1.1",
|
"connect-flash": "^0.1.1",
|
||||||
"connect-redis": "^3.1.0",
|
"connect-redis": "^3.1.0",
|
||||||
@ -44,6 +45,7 @@
|
|||||||
"express-brute-redis": "0.0.1",
|
"express-brute-redis": "0.0.1",
|
||||||
"express-session": "^1.14.0",
|
"express-session": "^1.14.0",
|
||||||
"express-validator": "^2.20.8",
|
"express-validator": "^2.20.8",
|
||||||
|
"highlight.js": "^9.6.0",
|
||||||
"i18next": "^3.4.1",
|
"i18next": "^3.4.1",
|
||||||
"i18next-express-middleware": "^1.0.1",
|
"i18next-express-middleware": "^1.0.1",
|
||||||
"i18next-node-fs-backend": "^0.1.2",
|
"i18next-node-fs-backend": "^0.1.2",
|
||||||
@ -53,6 +55,7 @@
|
|||||||
"markdown-it": "^7.0.1",
|
"markdown-it": "^7.0.1",
|
||||||
"markdown-it-abbr": "^1.0.3",
|
"markdown-it-abbr": "^1.0.3",
|
||||||
"markdown-it-anchor": "^2.5.0",
|
"markdown-it-anchor": "^2.5.0",
|
||||||
|
"markdown-it-attrs": "^0.6.3",
|
||||||
"markdown-it-emoji": "^1.2.0",
|
"markdown-it-emoji": "^1.2.0",
|
||||||
"markdown-it-expand-tabs": "^1.0.11",
|
"markdown-it-expand-tabs": "^1.0.11",
|
||||||
"markdown-it-external-links": "0.0.5",
|
"markdown-it-external-links": "0.0.5",
|
||||||
@ -71,6 +74,7 @@
|
|||||||
"serve-favicon": "^2.3.0",
|
"serve-favicon": "^2.3.0",
|
||||||
"simplemde": "^1.11.2",
|
"simplemde": "^1.11.2",
|
||||||
"slug": "^0.9.1",
|
"slug": "^0.9.1",
|
||||||
|
"sticky-js": "^1.0.5",
|
||||||
"twemoji-awesome": "^1.0.4",
|
"twemoji-awesome": "^1.0.4",
|
||||||
"validator": "^5.5.0",
|
"validator": "^5.5.0",
|
||||||
"validator-as-promised": "^1.0.2",
|
"validator-as-promised": "^1.0.2",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
nav.nav.has-shadow
|
nav.nav.has-shadow.stickyscroll
|
||||||
.nav-left
|
.nav-left
|
||||||
a.nav-item.is-brand(href='/')
|
a.nav-item.is-brand(href='/')
|
||||||
img(src='/favicons/android-icon-96x96.png', alt='Wiki')
|
img(src='/favicons/android-icon-96x96.png', alt='Wiki')
|
||||||
|
@ -25,18 +25,19 @@ block content
|
|||||||
a(href='/') Home
|
a(href='/') Home
|
||||||
li
|
li
|
||||||
a(href='/account') Account
|
a(href='/account') Account
|
||||||
.box
|
.box.stickyscroll(data-margin-top=70)
|
||||||
aside.menu(style= { 'min-width': '200px' })
|
aside.menu(style= { 'min-width': '200px' })
|
||||||
p.menu-label
|
p.menu-label
|
||||||
| Contents
|
| Contents
|
||||||
ul.menu-list
|
ul.menu-list
|
||||||
|
a(href='#root', title='Start') Start
|
||||||
+tocMenu(pageData.tree)
|
+tocMenu(pageData.tree)
|
||||||
|
|
||||||
.column
|
.column
|
||||||
|
|
||||||
h1.title= pageData.title
|
h1.title#title= pageData.title
|
||||||
h2.subtitle
|
if pageData.subtitle
|
||||||
| Primary bold subtitle
|
h2.subtitle= pageData.subtitle
|
||||||
.content
|
.content.mkcontent
|
||||||
!= pageData.html
|
!= pageData.html
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user