feat: TOC, scroll to header, page UI improvements
This commit is contained in:
parent
e067fe3abd
commit
3abc254685
@ -21,7 +21,6 @@ import Hammer from 'hammerjs'
|
||||
import moment from 'moment'
|
||||
import VueMoment from 'vue-moment'
|
||||
import VueTour from 'vue-tour'
|
||||
import VueTreeNavigation from 'vue-tree-navigation'
|
||||
import store from './store'
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
@ -149,7 +148,6 @@ Vue.use(VeeValidate, { events: '' })
|
||||
Vue.use(Vuetify)
|
||||
Vue.use(VueMoment, { moment })
|
||||
Vue.use(VueTour)
|
||||
Vue.use(VueTreeNavigation)
|
||||
|
||||
Vue.prototype.Velocity = Velocity
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template lang="pug">
|
||||
v-dialog(v-model='isShown', lazy, max-width='850px')
|
||||
v-card.page-selector
|
||||
.dialog-header
|
||||
.dialog-header.is-dark
|
||||
v-icon.mr-2(color='white') find_in_page
|
||||
span Select Page Location
|
||||
v-spacer
|
||||
v-progress-circular(
|
||||
@ -59,7 +60,7 @@
|
||||
v-list-tile
|
||||
v-list-tile-avatar: v-icon insert_drive_file
|
||||
v-list-tile-title File D
|
||||
v-card-text.grey.lighten-2.pa-2
|
||||
v-card-text.grey.lighten-1.pa-2
|
||||
v-text-field(
|
||||
solo
|
||||
hide-details
|
||||
|
@ -224,8 +224,8 @@ export default {
|
||||
isPrivate: false,
|
||||
isPublished: this.$store.get('page/isPublished'),
|
||||
path: this.$store.get('page/path'),
|
||||
publishEndDate: this.$store.get('page/publishEndDate'),
|
||||
publishStartDate: this.$store.get('page/publishStartDate'),
|
||||
publishEndDate: this.$store.get('page/publishEndDate') || '',
|
||||
publishStartDate: this.$store.get('page/publishStartDate') || '',
|
||||
tags: this.$store.get('page/tags'),
|
||||
title: this.$store.get('page/title')
|
||||
}
|
||||
@ -258,8 +258,8 @@ export default {
|
||||
isPrivate: false,
|
||||
isPublished: this.$store.get('page/isPublished'),
|
||||
path: this.$store.get('page/path'),
|
||||
publishEndDate: this.$store.get('page/publishEndDate'),
|
||||
publishStartDate: this.$store.get('page/publishStartDate'),
|
||||
publishEndDate: this.$store.get('page/publishEndDate') || '',
|
||||
publishStartDate: this.$store.get('page/publishStartDate') || '',
|
||||
tags: this.$store.get('page/tags'),
|
||||
title: this.$store.get('page/title')
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
}
|
||||
|
||||
> * + h1, > * + h2, > * + h3, > * + h4 {
|
||||
margin-top: 1rem;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
|
@ -14,4 +14,10 @@
|
||||
background: radial-gradient(ellipse at top, mc('red', '500'), mc('red', '700')),
|
||||
radial-gradient(ellipse at bottom, mc('red', '800'), mc('red', '700'));
|
||||
}
|
||||
|
||||
&.is-dark {
|
||||
background-color: mc('grey', '900');
|
||||
background: radial-gradient(ellipse at top, mc('grey', '800'), mc('grey', '900')),
|
||||
radial-gradient(ellipse at bottom, mc('grey', '800'), mc('grey', '900'));
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ const state = {
|
||||
isPublished: true,
|
||||
locale: 'en',
|
||||
path: '',
|
||||
publishEndDate: '',
|
||||
publishStartDate: '',
|
||||
tags: [],
|
||||
title: '',
|
||||
updatedAt: ''
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template lang="pug">
|
||||
v-app
|
||||
v-app(v-scroll='upBtnScroll')
|
||||
nav-header
|
||||
v-navigation-drawer.primary(
|
||||
dark
|
||||
@ -15,23 +15,24 @@
|
||||
slot(name='sidebar')
|
||||
|
||||
v-content
|
||||
v-toolbar(color='grey lighten-3', flat, dense)
|
||||
v-btn.pl-0(v-if='$vuetify.breakpoint.xsOnly', flat, @click='toggleNavigation')
|
||||
v-icon(color='grey darken-2', left) menu
|
||||
span Navigation
|
||||
v-breadcrumbs.breadcrumbs-nav.pl-0(
|
||||
v-else
|
||||
:items='breadcrumbs'
|
||||
divider='/'
|
||||
)
|
||||
template(slot='item', slot-scope='props')
|
||||
v-icon(v-if='props.item.path === "/"', small) home
|
||||
v-btn.ma-0(v-else, :href='props.item.path', small, flat) {{props.item.name}}
|
||||
template(v-if='!isPublished')
|
||||
v-spacer
|
||||
.caption.red--text Unpublished
|
||||
status-indicator.ml-3(negative, pulse)
|
||||
v-divider
|
||||
template(v-if='path !== `home`')
|
||||
v-toolbar(color='grey lighten-3', flat, dense)
|
||||
v-btn.pl-0(v-if='$vuetify.breakpoint.xsOnly', flat, @click='toggleNavigation')
|
||||
v-icon(color='grey darken-2', left) menu
|
||||
span Navigation
|
||||
v-breadcrumbs.breadcrumbs-nav.pl-0(
|
||||
v-else
|
||||
:items='breadcrumbs'
|
||||
divider='/'
|
||||
)
|
||||
template(slot='item', slot-scope='props')
|
||||
v-icon(v-if='props.item.path === "/"', small) home
|
||||
v-btn.ma-0(v-else, :href='props.item.path', small, flat) {{props.item.name}}
|
||||
template(v-if='!isPublished')
|
||||
v-spacer
|
||||
.caption.red--text Unpublished
|
||||
status-indicator.ml-3(negative, pulse)
|
||||
v-divider
|
||||
v-layout(row)
|
||||
v-flex(xs12, lg9, xl10)
|
||||
v-toolbar(color='grey lighten-4', flat, :height='90')
|
||||
@ -54,10 +55,20 @@
|
||||
v-icon(color='grey') edit
|
||||
span Edit Page
|
||||
v-divider
|
||||
v-list.grey.lighten-3.pb-3(dense)
|
||||
v-subheader.pl-4.primary--text Table of contents
|
||||
vue-tree-navigation.treenav(:items='toc', :defaultOpenLevel='1')
|
||||
v-divider
|
||||
template(v-if='toc.length')
|
||||
v-list.grey.lighten-3.pb-3(dense)
|
||||
v-subheader.pl-4.primary--text Table of contents
|
||||
template(v-for='(tocItem, tocIdx) in toc')
|
||||
v-list-tile(@click='$vuetify.goTo(tocItem.anchor, scrollOpts)')
|
||||
v-icon(color='grey') arrow_right
|
||||
v-list-tile-title.pl-3 {{tocItem.title}}
|
||||
v-divider.ml-4(v-if='tocIdx < toc.length - 1 || tocItem.children.length')
|
||||
template(v-for='tocSubItem in tocItem.children')
|
||||
v-list-tile(@click='$vuetify.goTo(tocSubItem.anchor, scrollOpts)')
|
||||
v-icon.pl-3(color='grey lighten-1') arrow_right
|
||||
v-list-tile-title.pl-3.caption {{tocSubItem.title}}
|
||||
v-divider(inset, v-if='tocIdx < toc.length - 1')
|
||||
v-divider
|
||||
v-list.grey.lighten-4(dense)
|
||||
v-subheader.pl-4.yellow--text.text--darken-4 Rating
|
||||
.text-xs-center
|
||||
@ -97,6 +108,9 @@
|
||||
span Print Format
|
||||
v-spacer
|
||||
nav-footer
|
||||
v-fab-transition
|
||||
v-btn(v-if='upBtnShown', fab, fixed, bottom, right, small, @click='$vuetify.goTo(0, scrollOpts)', color='primary')
|
||||
v-icon arrow_upward
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -147,46 +161,27 @@ export default {
|
||||
isPublished: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
toc: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
navOpen: false,
|
||||
upBtnShown: false,
|
||||
scrollOpts: {
|
||||
duration: 1500,
|
||||
offset: -75,
|
||||
easing: 'easeInOutCubic'
|
||||
},
|
||||
breadcrumbs: [
|
||||
{ path: '/', name: 'Home' },
|
||||
{ path: '/universe', name: 'Universe' },
|
||||
{ path: '/universe/galaxy', name: 'Galaxy' },
|
||||
{ path: '/universe/galaxy/solar-system', name: 'Solar System' },
|
||||
{ path: '/universe/galaxy/solar-system/planet-earth', name: 'Planet Earth' }
|
||||
],
|
||||
toc: [
|
||||
{
|
||||
name: 'Introduction',
|
||||
element: 'introduction'
|
||||
},
|
||||
{
|
||||
name: 'Cities',
|
||||
element: 'cities',
|
||||
children: [
|
||||
{
|
||||
name: 'New York',
|
||||
element: 'contact',
|
||||
children: [
|
||||
{ name: 'E-mail', element: 'email' },
|
||||
{ name: 'Phone', element: 'phone' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Chicago',
|
||||
element: 'contact',
|
||||
children: [
|
||||
{ name: 'E-mail', element: 'email' },
|
||||
{ name: 'Phone', element: 'phone' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{ name: 'Population', external: 'https://github.com' }
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -222,6 +217,10 @@ export default {
|
||||
methods: {
|
||||
toggleNavigation () {
|
||||
this.navOpen = !this.navOpen
|
||||
},
|
||||
upBtnScroll () {
|
||||
const scrollOffset = window.pageYOffset || document.documentElement.scrollTop
|
||||
this.upBtnShown = scrollOffset > window.innerHeight * 0.33
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
.contents {
|
||||
color: mc('grey', '800');
|
||||
padding-bottom: 50px;
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
position: relative;
|
||||
@ -26,7 +27,7 @@
|
||||
h1 {
|
||||
padding-left: 24px;
|
||||
color: mc('blue', '800');
|
||||
margin-top: 1rem;
|
||||
margin-top: 2rem;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
|
100
package.json
100
package.json
@ -42,15 +42,15 @@
|
||||
"node": ">=10.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"apollo-server": "2.1.0",
|
||||
"apollo-server-express": "2.1.0",
|
||||
"auto-load": "3.0.1",
|
||||
"apollo-server": "2.2.2",
|
||||
"apollo-server-express": "2.2.2",
|
||||
"auto-load": "3.0.4",
|
||||
"axios": "0.18.0",
|
||||
"bcryptjs-then": "1.0.1",
|
||||
"bluebird": "3.5.2",
|
||||
"bluebird": "3.5.3",
|
||||
"body-parser": "1.18.3",
|
||||
"bugsnag": "2.4.3",
|
||||
"bull": "3.4.8",
|
||||
"bull": "3.5.2",
|
||||
"chalk": "2.4.1",
|
||||
"cheerio": "1.0.0-rc.2",
|
||||
"child-process-promise": "2.2.1",
|
||||
@ -58,34 +58,34 @@
|
||||
"compression": "1.7.3",
|
||||
"connect-redis": "3.4.0",
|
||||
"cookie-parser": "1.4.3",
|
||||
"cors": "2.8.4",
|
||||
"cors": "2.8.5",
|
||||
"dependency-graph": "0.7.2",
|
||||
"diff2html": "2.4.0",
|
||||
"diff2html": "2.5.0",
|
||||
"dotize": "^0.2.0",
|
||||
"execa": "1.0.0",
|
||||
"express": "4.16.4",
|
||||
"express-brute": "1.0.1",
|
||||
"express-brute-redis": "0.0.1",
|
||||
"express-session": "1.15.6",
|
||||
"file-type": "10.2.0",
|
||||
"file-type": "10.4.0",
|
||||
"filesize": "3.6.1",
|
||||
"follow-redirects": "1.5.9",
|
||||
"fs-extra": "7.0.0",
|
||||
"fs-extra": "7.0.1",
|
||||
"getos": "3.1.0",
|
||||
"graphql": "14.0.2",
|
||||
"graphql-list-fields": "2.0.2",
|
||||
"graphql-subscriptions": "1.0.0",
|
||||
"graphql-tools": "4.0.2",
|
||||
"graphql-tools": "4.0.3",
|
||||
"highlight.js": "9.13.1",
|
||||
"i18next": "12.0.0",
|
||||
"i18next-express-middleware": "1.4.1",
|
||||
"i18next-express-middleware": "1.5.0",
|
||||
"i18next-localstorage-cache": "1.1.1",
|
||||
"i18next-node-fs-backend": "2.1.0",
|
||||
"image-size": "0.6.3",
|
||||
"ioredis": "4.2.0",
|
||||
"js-binary": "1.2.0",
|
||||
"js-yaml": "3.12.0",
|
||||
"jsonwebtoken": "8.3.0",
|
||||
"jsonwebtoken": "8.4.0",
|
||||
"klaw": "3.0.0",
|
||||
"knex": "0.15.2",
|
||||
"lodash": "4.17.11",
|
||||
@ -106,11 +106,11 @@
|
||||
"mathjax-node": "2.1.1",
|
||||
"mime-types": "2.1.21",
|
||||
"moment": "2.22.2",
|
||||
"moment-timezone": "0.5.21",
|
||||
"mongodb": "3.1.8",
|
||||
"mssql": "4.2.2",
|
||||
"moment-timezone": "0.5.23",
|
||||
"mongodb": "3.1.10",
|
||||
"mssql": "4.2.3",
|
||||
"multer": "1.4.1",
|
||||
"mysql2": "1.6.1",
|
||||
"mysql2": "1.6.4",
|
||||
"node-2fa": "1.1.2",
|
||||
"node-cache": "4.2.0",
|
||||
"oauth2orize": "1.11.0",
|
||||
@ -135,7 +135,7 @@
|
||||
"passport-slack": "0.0.7",
|
||||
"passport-twitch": "1.0.3",
|
||||
"passport-windowslive": "1.0.2",
|
||||
"pg": "7.6.0",
|
||||
"pg": "7.6.1",
|
||||
"pg-hstore": "2.3.2",
|
||||
"pm2": "3.2.2",
|
||||
"pug": "2.0.3",
|
||||
@ -148,20 +148,20 @@
|
||||
"scim-query-filter-parser": "1.1.0",
|
||||
"semver": "5.6.0",
|
||||
"serve-favicon": "2.5.0",
|
||||
"sqlite3": "4.0.3",
|
||||
"sqlite3": "4.0.4",
|
||||
"subscriptions-transport-ws": "0.9.15",
|
||||
"uslug": "1.0.4",
|
||||
"uuid": "3.3.2",
|
||||
"validator": "10.8.0",
|
||||
"validator": "10.9.0",
|
||||
"validator-as-promised": "1.0.2",
|
||||
"winston": "3.1.0",
|
||||
"yargs": "12.0.2"
|
||||
"yargs": "12.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.1.2",
|
||||
"@babel/core": "^7.1.2",
|
||||
"@babel/cli": "^7.1.5",
|
||||
"@babel/core": "^7.1.6",
|
||||
"@babel/plugin-proposal-class-properties": "^7.1.0",
|
||||
"@babel/plugin-proposal-decorators": "^7.1.2",
|
||||
"@babel/plugin-proposal-decorators": "^7.1.6",
|
||||
"@babel/plugin-proposal-export-namespace-from": "^7.0.0",
|
||||
"@babel/plugin-proposal-function-sent": "^7.1.0",
|
||||
"@babel/plugin-proposal-json-strings": "^7.0.0",
|
||||
@ -170,20 +170,20 @@
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
||||
"@babel/plugin-syntax-import-meta": "^7.0.0",
|
||||
"@babel/polyfill": "^7.0.0",
|
||||
"@babel/preset-env": "^7.1.0",
|
||||
"@babel/preset-env": "^7.1.6",
|
||||
"@panter/vue-i18next": "0.13.0",
|
||||
"@vue/cli": "3.0.5",
|
||||
"@vue/cli": "3.1.3",
|
||||
"animated-number-vue": "0.1.3",
|
||||
"apollo-cache-inmemory": "1.3.7",
|
||||
"apollo-client": "2.4.4",
|
||||
"apollo-cache-inmemory": "1.3.10",
|
||||
"apollo-client": "2.4.6",
|
||||
"apollo-fetch": "0.7.0",
|
||||
"apollo-link": "1.2.3",
|
||||
"apollo-link-batch-http": "1.2.3",
|
||||
"apollo-link-error": "1.1.1",
|
||||
"apollo-link-http": "1.5.5",
|
||||
"apollo-link-persisted-queries": "0.2.1",
|
||||
"apollo-link-persisted-queries": "0.2.2",
|
||||
"apollo-link-ws": "1.0.9",
|
||||
"apollo-utilities": "1.0.24",
|
||||
"apollo-utilities": "1.0.25",
|
||||
"autoprefixer": "9.3.1",
|
||||
"babel-eslint": "10.0.1",
|
||||
"babel-jest": "23.6.0",
|
||||
@ -192,15 +192,16 @@
|
||||
"babel-plugin-lodash": "3.3.4",
|
||||
"babel-plugin-transform-imports": "1.5.1",
|
||||
"brace": "0.11.1",
|
||||
"cache-loader": "1.2.2",
|
||||
"cache-loader": "1.2.5",
|
||||
"chart.js": "2.7.3",
|
||||
"clean-webpack-plugin": "0.1.19",
|
||||
"copy-webpack-plugin": "4.5.4",
|
||||
"css-loader": "1.0.0",
|
||||
"clean-webpack-plugin": "1.0.0",
|
||||
"copy-webpack-plugin": "4.6.0",
|
||||
"core-js": "2.5.7",
|
||||
"css-loader": "1.0.1",
|
||||
"cssnano": "4.1.7",
|
||||
"duplicate-package-checker-webpack-plugin": "3.0.0",
|
||||
"epic-spinners": "1.0.4",
|
||||
"eslint": "5.8.0",
|
||||
"eslint": "5.9.0",
|
||||
"eslint-config-requarks": "1.0.7",
|
||||
"eslint-config-standard": "12.0.0",
|
||||
"eslint-plugin-import": "2.14.0",
|
||||
@ -210,7 +211,7 @@
|
||||
"eslint-plugin-vue": "4.7.1",
|
||||
"file-loader": "2.0.0",
|
||||
"filesize.js": "1.0.2",
|
||||
"grapesjs": "0.14.33",
|
||||
"grapesjs": "0.14.40",
|
||||
"graphiql": "0.12.0",
|
||||
"graphql-persisted-document-loader": "1.0.1",
|
||||
"graphql-tag": "^2.10.0",
|
||||
@ -223,62 +224,61 @@
|
||||
"js-cookie": "2.2.0",
|
||||
"mini-css-extract-plugin": "0.4.4",
|
||||
"node-sass": "4.9.4",
|
||||
"offline-plugin": "5.0.5",
|
||||
"offline-plugin": "5.0.6",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.1",
|
||||
"postcss-cssnext": "3.1.0",
|
||||
"postcss-flexbugs-fixes": "4.1.0",
|
||||
"postcss-flexibility": "2.0.0",
|
||||
"postcss-import": "12.0.1",
|
||||
"postcss-loader": "3.0.0",
|
||||
"postcss-preset-env": "6.3.0",
|
||||
"postcss-preset-env": "6.4.0",
|
||||
"postcss-selector-parser": "5.0.0-rc.4",
|
||||
"pug-lint": "2.5.0",
|
||||
"pug-loader": "2.4.0",
|
||||
"pug-plain-loader": "1.0.0",
|
||||
"raw-loader": "0.5.1",
|
||||
"react": "16.6.0",
|
||||
"react-dom": "16.6.0",
|
||||
"react": "16.6.3",
|
||||
"react-dom": "16.6.3",
|
||||
"resolve-url-loader": "3.0.0",
|
||||
"sass-loader": "7.1.0",
|
||||
"sass-resources-loader": "1.3.4",
|
||||
"script-ext-html-webpack-plugin": "2.0.1",
|
||||
"sass-resources-loader": "2.0.0",
|
||||
"script-ext-html-webpack-plugin": "2.1.3",
|
||||
"simple-progress-webpack-plugin": "1.1.2",
|
||||
"style-loader": "0.23.1",
|
||||
"stylus": "0.54.5",
|
||||
"stylus-loader": "3.0.2",
|
||||
"twemoji-awesome": "1.0.6",
|
||||
"url-loader": "1.1.2",
|
||||
"vee-validate": "2.1.1",
|
||||
"vee-validate": "2.1.3",
|
||||
"velocity-animate": "1.5.2",
|
||||
"viz.js": "2.0.0",
|
||||
"viz.js": "2.1.1",
|
||||
"vue": "2.5.17",
|
||||
"vue-apollo": "3.0.0-beta.25",
|
||||
"vue-apollo": "3.0.0-beta.26",
|
||||
"vue-chartjs": "3.4.0",
|
||||
"vue-clipboards": "1.2.4",
|
||||
"vue-codemirror": "4.0.5",
|
||||
"vue-codemirror": "4.0.6",
|
||||
"vue-hot-reload-api": "2.3.1",
|
||||
"vue-loader": "15.4.2",
|
||||
"vue-material-design-icons": "2.3.0",
|
||||
"vue-material-design-icons": "2.4.0",
|
||||
"vue-moment": "4.0.0",
|
||||
"vue-router": "3.0.1",
|
||||
"vue-simple-breakpoints": "1.0.3",
|
||||
"vue-status-indicator": "1.1.1",
|
||||
"vue-template-compiler": "2.5.17",
|
||||
"vue-tour": "1.1.0",
|
||||
"vue-tree-navigation": "3.0.1",
|
||||
"vue2-animate": "2.1.0",
|
||||
"vuedraggable": "2.16.0",
|
||||
"vuetify": "1.3.3",
|
||||
"vuetify": "1.3.8",
|
||||
"vuex": "3.0.1",
|
||||
"vuex-pathify": "1.1.3",
|
||||
"vuex-persistedstate": "2.5.4",
|
||||
"webpack": "4.23.1",
|
||||
"webpack": "4.25.1",
|
||||
"webpack-bundle-analyzer": "3.0.3",
|
||||
"webpack-cli": "3.1.2",
|
||||
"webpack-dev-middleware": "3.4.0",
|
||||
"webpack-hot-middleware": "2.24.3",
|
||||
"webpack-merge": "4.1.4",
|
||||
"webpack-subresource-integrity": "1.2.0",
|
||||
"webpack-subresource-integrity": "1.3.0",
|
||||
"whatwg-fetch": "3.0.0",
|
||||
"write-file-webpack-plugin": "4.4.1",
|
||||
"xterm": "3.8.0"
|
||||
|
@ -116,6 +116,7 @@ exports.up = knex => {
|
||||
table.string('publishEndDate')
|
||||
table.text('content')
|
||||
table.text('render')
|
||||
table.json('toc')
|
||||
table.string('contentType').notNullable()
|
||||
table.string('createdAt').notNullable()
|
||||
table.string('updatedAt').notNullable()
|
||||
|
@ -1,6 +1,7 @@
|
||||
require('../core/worker')
|
||||
|
||||
const _ = require('lodash')
|
||||
const cheerio = require('cheerio')
|
||||
|
||||
/* global WIKI */
|
||||
|
||||
@ -21,15 +22,43 @@ module.exports = async (job) => {
|
||||
})
|
||||
}
|
||||
|
||||
// Parse TOC
|
||||
const $ = cheerio.load(output)
|
||||
let isStrict = $('h1').length > 0 // <- Allows for documents using H2 as top level
|
||||
let toc = { root: [] }
|
||||
|
||||
$('h1,h2,h3,h4,h5,h6').each((idx, el) => {
|
||||
const depth = _.toSafeInteger(el.name.substring(1)) - (isStrict ? 1 : 2)
|
||||
const leafPath = _.reduce(_.times(depth), (curPath, curIdx) => {
|
||||
if (_.has(toc, curPath)) {
|
||||
const lastLeafIdx = _.get(toc, curPath).length - 1
|
||||
curPath = `${curPath}[${lastLeafIdx}].children`
|
||||
}
|
||||
return curPath
|
||||
}, 'root')
|
||||
|
||||
const leafSlug = $('.toc-anchor', el).first().attr('href')
|
||||
$('.toc-anchor', el).remove()
|
||||
_.get(toc, leafPath).push({
|
||||
title: _.trim($(el).text()),
|
||||
anchor: leafSlug,
|
||||
children: []
|
||||
})
|
||||
})
|
||||
|
||||
// Save to DB
|
||||
await WIKI.models.pages.query()
|
||||
.patch({ render: output })
|
||||
.patch({
|
||||
render: output,
|
||||
toc: JSON.stringify(toc.root)
|
||||
})
|
||||
.where('id', job.data.page.id)
|
||||
|
||||
// Save to cache
|
||||
await WIKI.models.pages.savePageToCache({
|
||||
...job.data.page,
|
||||
render: output
|
||||
render: output,
|
||||
toc: JSON.stringify(toc.root)
|
||||
})
|
||||
|
||||
WIKI.logger.info(`Rendering page ${job.data.page.path}: [ COMPLETED ]`)
|
||||
|
@ -96,8 +96,8 @@ module.exports = class PageHistory extends Model {
|
||||
isPublished: opts.isPublished,
|
||||
localeCode: opts.localeCode,
|
||||
path: opts.path,
|
||||
publishEndDate: opts.publishEndDate,
|
||||
publishStartDate: opts.publishStartDate,
|
||||
publishEndDate: opts.publishEndDate || '',
|
||||
publishStartDate: opts.publishStartDate || '',
|
||||
title: opts.title
|
||||
})
|
||||
}
|
||||
|
@ -108,6 +108,7 @@ module.exports = class Page extends Model {
|
||||
publishStartDate: 'string',
|
||||
render: 'string',
|
||||
title: 'string',
|
||||
toc: 'string',
|
||||
updatedAt: 'string'
|
||||
})
|
||||
}
|
||||
@ -125,9 +126,10 @@ module.exports = class Page extends Model {
|
||||
isPublished: opts.isPublished,
|
||||
localeCode: opts.locale,
|
||||
path: opts.path,
|
||||
publishEndDate: opts.publishEndDate,
|
||||
publishStartDate: opts.publishStartDate,
|
||||
title: opts.title
|
||||
publishEndDate: opts.publishEndDate || '',
|
||||
publishStartDate: opts.publishStartDate || '',
|
||||
title: opts.title,
|
||||
toc: '[]'
|
||||
})
|
||||
const page = await WIKI.models.pages.getPageFromDb({
|
||||
path: opts.path,
|
||||
@ -154,8 +156,8 @@ module.exports = class Page extends Model {
|
||||
content: opts.content,
|
||||
description: opts.description,
|
||||
isPublished: opts.isPublished,
|
||||
publishEndDate: opts.publishEndDate,
|
||||
publishStartDate: opts.publishStartDate,
|
||||
publishEndDate: opts.publishEndDate || '',
|
||||
publishStartDate: opts.publishStartDate || '',
|
||||
title: opts.title
|
||||
}).where('id', ogPage.id)
|
||||
const page = await WIKI.models.pages.getPageFromDb({
|
||||
@ -243,6 +245,7 @@ module.exports = class Page extends Model {
|
||||
publishStartDate: page.publishStartDate,
|
||||
render: page.render,
|
||||
title: page.title,
|
||||
toc: page.toc,
|
||||
updatedAt: page.updatedAt
|
||||
}))
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ block body
|
||||
author-name=page.authorName
|
||||
:author-id=page.authorId
|
||||
:is-published=page.isPublished
|
||||
:toc=page.toc
|
||||
)
|
||||
template(slot='sidebar')
|
||||
each navItem in sidebar
|
||||
|
Loading…
Reference in New Issue
Block a user