syntax highlight + TOC scroll + other content parsing improvements

pull/1/head
NGPixel 10 years ago
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( $ ) {
$('a').smoothScroll({
speed: 'auto'
speed: 400,
offset: -20
});
var sticky = new Sticky('.stickyscroll');
});

@ -8,4 +8,4 @@ $warning: #f68b39;
@import './layout/_header';
@import './layout/_footer';
@import './layout/_content';

@ -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 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);
if(!pageData.title) {
pageData.title = 'Gollum';

@ -22,7 +22,8 @@ var paths = {
'./node_modules/lodash/lodash.min.js',
'./node_modules/jquery/dist/jquery.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: [
'./client/js/components/*.js',
@ -32,7 +33,8 @@ var paths = {
'./client/js/**/*.js'
],
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: [
'./client/scss/app.scss'

@ -9,7 +9,10 @@ var Promise = require('bluebird'),
mdFootnote = require('markdown-it-footnote'),
mdExternalLinks = require('markdown-it-external-links'),
mdExpandTabs = require('markdown-it-expand-tabs'),
mdAttrs = require('markdown-it-attrs'),
hljs = require('highlight.js'),
slug = require('slug'),
cheerio = require('cheerio'),
_ = require('lodash');
// Load plugins
@ -17,7 +20,15 @@ var Promise = require('bluebird'),
var mkdown = md({
html: 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(mdTaskLists)
@ -33,7 +44,8 @@ var mkdown = md({
})
.use(mdExpandTabs, {
tabWidth: 4
});
})
.use(mdAttrs);
// Rendering rules
@ -41,13 +53,23 @@ mkdown.renderer.rules.emoji = function(token, idx) {
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) => {
let tokens = md().parse(content, {});
let tocArray = [];
//-> Extract headings and their respective levels
for (let i = 0; i < tokens.length; i++) {
if (tokens[i].type !== "heading_close") {
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) => {
let treeLength = tree.length - 1;
if(v.level < 2) {
@ -98,23 +126,42 @@ const parseTree = (content) => {
};
let lastNodePath = GetNodePath();
let lastNode = _.get(tree[treeLength], lastNodePath);
lastNode.push({
content: v.content,
anchor: v.anchor,
nodes: []
});
_.set(tree[treeLength], lastNodePath, lastNode);
if(lastNode) {
lastNode.push({
content: v.content,
anchor: v.anchor,
nodes: []
});
_.set(tree[treeLength], lastNodePath, lastNode);
}
}
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 = {
parse(content) {
return {
html: mkdown.render(content),
html: parseContent(content),
tree: parseTree(content)
};
}

@ -35,6 +35,7 @@
"bluebird": "^3.4.1",
"body-parser": "^1.15.2",
"bulma": "^0.1.2",
"cheerio": "^0.20.0",
"compression": "^1.6.2",
"connect-flash": "^0.1.1",
"connect-redis": "^3.1.0",
@ -44,6 +45,7 @@
"express-brute-redis": "0.0.1",
"express-session": "^1.14.0",
"express-validator": "^2.20.8",
"highlight.js": "^9.6.0",
"i18next": "^3.4.1",
"i18next-express-middleware": "^1.0.1",
"i18next-node-fs-backend": "^0.1.2",
@ -53,6 +55,7 @@
"markdown-it": "^7.0.1",
"markdown-it-abbr": "^1.0.3",
"markdown-it-anchor": "^2.5.0",
"markdown-it-attrs": "^0.6.3",
"markdown-it-emoji": "^1.2.0",
"markdown-it-expand-tabs": "^1.0.11",
"markdown-it-external-links": "0.0.5",
@ -71,6 +74,7 @@
"serve-favicon": "^2.3.0",
"simplemde": "^1.11.2",
"slug": "^0.9.1",
"sticky-js": "^1.0.5",
"twemoji-awesome": "^1.0.4",
"validator": "^5.5.0",
"validator-as-promised": "^1.0.2",

@ -1,5 +1,5 @@
nav.nav.has-shadow
nav.nav.has-shadow.stickyscroll
.nav-left
a.nav-item.is-brand(href='/')
img(src='/favicons/android-icon-96x96.png', alt='Wiki')

@ -25,18 +25,19 @@ block content
a(href='/') Home
li
a(href='/account') Account
.box
.box.stickyscroll(data-margin-top=70)
aside.menu(style= { 'min-width': '200px' })
p.menu-label
| Contents
ul.menu-list
a(href='#root', title='Start') Start
+tocMenu(pageData.tree)
.column
h1.title= pageData.title
h2.subtitle
| Primary bold subtitle
.content
h1.title#title= pageData.title
if pageData.subtitle
h2.subtitle= pageData.subtitle
.content.mkcontent
!= pageData.html

Loading…
Cancel
Save