feat: legacy login
This commit is contained in:
parent
bd24ff225b
commit
03e80bdff3
@ -28,6 +28,120 @@ body {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LOGIN
|
||||||
|
|
||||||
|
.login {
|
||||||
|
background-color: mc('grey', '900');
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&-deprecated {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: mc('red', '700');
|
||||||
|
text-align: center;
|
||||||
|
color: mc('red', '50');
|
||||||
|
height: 64px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #FFF;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-dialog {
|
||||||
|
width: 650px;
|
||||||
|
background-color: mc('grey', '100');
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem;
|
||||||
|
color: mc('grey', '800');
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, select {
|
||||||
|
display: block;
|
||||||
|
background-color: #FFF;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 1rem;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 40px;
|
||||||
|
display: block;
|
||||||
|
width: 200px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: mc('blue', '700');
|
||||||
|
color: #FFF;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: mc('blue', '800');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-social {
|
||||||
|
margin-top: 2rem;
|
||||||
|
padding-top: 1rem;
|
||||||
|
border-top: 1px solid mc('grey', '400');
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 54px;
|
||||||
|
height: 54px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity .2s ease;
|
||||||
|
margin: .5rem .25rem;
|
||||||
|
&:hover {
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
bottom: 0;
|
||||||
|
path {
|
||||||
|
fill: #FFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $colorName, $color in $material-colors {
|
||||||
|
&.#{$colorName} {
|
||||||
|
background-color: map-get($color, '500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PAGE
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
@ -145,7 +259,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-right {
|
&-right {
|
||||||
flex: 0 0 324px;
|
flex: 0 0 308px;
|
||||||
padding-left: 16px;
|
padding-left: 16px;
|
||||||
|
|
||||||
&-title {
|
&-title {
|
||||||
|
@ -90,58 +90,9 @@ html
|
|||||||
|
|
||||||
!= analyticsCode.head
|
!= analyticsCode.head
|
||||||
|
|
||||||
if injectCode.css
|
block head
|
||||||
style(type='text/css')!= injectCode.css
|
|
||||||
if injectCode.head
|
|
||||||
!= injectCode.head
|
|
||||||
|
|
||||||
body
|
body
|
||||||
!= analyticsCode.bodyStart
|
!= analyticsCode.bodyStart
|
||||||
#root
|
block body
|
||||||
.header
|
|
||||||
span.header-title= siteConfig.title
|
|
||||||
span.header-deprecated Your browser is outdated. Upgrade to a #[a(href='https://bestvpn.org/outdatedbrowser/en', rel='nofollow') modern browser].
|
|
||||||
span.header-login
|
|
||||||
a(href='/login')
|
|
||||||
i.material-icons account_circle
|
|
||||||
.main
|
|
||||||
.sidebar
|
|
||||||
each navItem in sidebar
|
|
||||||
if navItem.kind === 'link'
|
|
||||||
a.sidebar-link(href=navItem.target)
|
|
||||||
i.material-icons= navItem.icon
|
|
||||||
span= navItem.label
|
|
||||||
else if navItem.kind === 'divider'
|
|
||||||
.sidebar-divider
|
|
||||||
else if navItem.kind === 'header'
|
|
||||||
.sidebar-title= navItem.label
|
|
||||||
.main-container
|
|
||||||
.page-header
|
|
||||||
.page-header-left
|
|
||||||
h1= page.title
|
|
||||||
h2= page.description
|
|
||||||
.page-header-right
|
|
||||||
.page-header-right-title Last edited by
|
|
||||||
.page-header-right-author= page.authorName
|
|
||||||
.page-header-right-updated= page.updatedAt
|
|
||||||
.page-contents
|
|
||||||
.contents
|
|
||||||
div!= page.render
|
|
||||||
if page.toc.length
|
|
||||||
.toc
|
|
||||||
.toc-title Table of Contents
|
|
||||||
each tocItem, tocIdx in page.toc
|
|
||||||
a.toc-tile(href='#' + tocItem.anchor)
|
|
||||||
i.material-icons arrow_right
|
|
||||||
span= tocItem.title
|
|
||||||
if tocIdx < page.toc.length - 1 || tocItem.children.length
|
|
||||||
.toc-divider
|
|
||||||
each tocSubItem in tocItem.children
|
|
||||||
a.toc-tile.inset(href='#' + tocSubItem.anchor)
|
|
||||||
i.material-icons arrow_right
|
|
||||||
span= tocSubItem.title
|
|
||||||
if tocIdx < page.toc.length - 1
|
|
||||||
.toc-divider.inset
|
|
||||||
if injectCode.body
|
|
||||||
!= injectCode.body
|
|
||||||
!= analyticsCode.bodyEnd
|
!= analyticsCode.bodyEnd
|
||||||
|
@ -199,7 +199,7 @@ module.exports = {
|
|||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: 'dev/templates/legacy.pug',
|
template: 'dev/templates/legacy.pug',
|
||||||
filename: '../server/views/legacy.pug',
|
filename: '../server/views/legacy/master.pug',
|
||||||
hash: false,
|
hash: false,
|
||||||
inject: false,
|
inject: false,
|
||||||
excludeChunks: ['setup', 'app']
|
excludeChunks: ['setup', 'app']
|
||||||
|
@ -209,7 +209,7 @@ module.exports = {
|
|||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: 'dev/templates/legacy.pug',
|
template: 'dev/templates/legacy.pug',
|
||||||
filename: '../server/views/legacy.pug',
|
filename: '../server/views/legacy/master.pug',
|
||||||
hash: false,
|
hash: false,
|
||||||
inject: false,
|
inject: false,
|
||||||
excludeChunks: ['setup', 'app']
|
excludeChunks: ['setup', 'app']
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
"bcryptjs-then": "1.0.1",
|
"bcryptjs-then": "1.0.1",
|
||||||
"bluebird": "3.5.5",
|
"bluebird": "3.5.5",
|
||||||
"body-parser": "1.19.0",
|
"body-parser": "1.19.0",
|
||||||
|
"brute-knex": "4.0.0",
|
||||||
"chalk": "2.4.2",
|
"chalk": "2.4.2",
|
||||||
"cheerio": "1.0.0-rc.3",
|
"cheerio": "1.0.0-rc.3",
|
||||||
"chokidar": "3.0.1",
|
"chokidar": "3.0.1",
|
||||||
|
@ -1,17 +1,70 @@
|
|||||||
/* global WIKI */
|
/* global WIKI */
|
||||||
|
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
|
const ExpressBrute = require('express-brute')
|
||||||
|
const BruteKnex = require('brute-knex')
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
const moment = require('moment')
|
const moment = require('moment')
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
|
const fs = require('fs-extra')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
const bruteforce = new ExpressBrute(new BruteKnex({
|
||||||
|
createTable: true,
|
||||||
|
knex: WIKI.models.knex
|
||||||
|
}), {
|
||||||
|
freeRetries: 5,
|
||||||
|
minWait: 5*60*1000, // 5 minutes
|
||||||
|
maxWait: 60*60*1000, // 1 hour
|
||||||
|
failCallback: (req, res, next) => {
|
||||||
|
res.status(401).send('Too many failed attempts. Try again later.')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login form
|
* Login form
|
||||||
*/
|
*/
|
||||||
router.get('/login', (req, res, next) => {
|
router.get('/login', async (req, res, next) => {
|
||||||
_.set(res.locals, 'pageMeta.title', 'Login')
|
_.set(res.locals, 'pageMeta.title', 'Login')
|
||||||
res.render('login')
|
|
||||||
|
if (req.query.legacy || req.get('user-agent').indexOf('Trident') >= 0) {
|
||||||
|
const strategies = await WIKI.models.authentication.query().select('key', 'selfRegistration').where({ isEnabled: true })
|
||||||
|
let formStrategies = []
|
||||||
|
let socialStrategies = []
|
||||||
|
|
||||||
|
// TODO: Let's refactor that at some point...
|
||||||
|
for (let stg of strategies) {
|
||||||
|
const stgInfo = _.find(WIKI.data.authentication, ['key', stg.key]) || {}
|
||||||
|
if (stgInfo.useForm) {
|
||||||
|
formStrategies.push({
|
||||||
|
key: stg.key,
|
||||||
|
title: stgInfo.title
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
socialStrategies.push({
|
||||||
|
...stgInfo,
|
||||||
|
...stg,
|
||||||
|
icon: await fs.readFile(path.join(WIKI.ROOTPATH, `assets/svg/auth-icon-${stg.key}.svg`), 'utf8').catch(err => {
|
||||||
|
if (err.code === 'ENOENT') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
throw err
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.render('legacy/login', {
|
||||||
|
formStrategies,
|
||||||
|
socialStrategies
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
res.render('login')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Social Strategies Login
|
||||||
|
*/
|
||||||
router.get('/login/:strategy', async (req, res, next) => {
|
router.get('/login/:strategy', async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
await WIKI.models.users.login({
|
await WIKI.models.users.login({
|
||||||
@ -21,6 +74,10 @@ router.get('/login/:strategy', async (req, res, next) => {
|
|||||||
next(err)
|
next(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Social Strategies Callback
|
||||||
|
*/
|
||||||
router.all('/login/:strategy/callback', async (req, res, next) => {
|
router.all('/login/:strategy/callback', async (req, res, next) => {
|
||||||
if (req.method !== 'GET' && req.method !== 'POST') { return next() }
|
if (req.method !== 'GET' && req.method !== 'POST') { return next() }
|
||||||
|
|
||||||
@ -35,6 +92,30 @@ router.all('/login/:strategy/callback', async (req, res, next) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LEGACY - Login form handling
|
||||||
|
*/
|
||||||
|
router.post('/login', bruteforce.prevent, async (req, res, next) => {
|
||||||
|
_.set(res.locals, 'pageMeta.title', 'Login')
|
||||||
|
|
||||||
|
if (req.query.legacy || req.get('user-agent').indexOf('Trident') >= 0) {
|
||||||
|
try {
|
||||||
|
const authResult = await WIKI.models.users.login({
|
||||||
|
strategy: req.body.strategy,
|
||||||
|
username: req.body.user,
|
||||||
|
password: req.body.pass
|
||||||
|
}, { req, res })
|
||||||
|
req.brute.reset()
|
||||||
|
res.cookie('jwt', authResult.jwt, { expires: moment().add(1, 'y').toDate() })
|
||||||
|
res.redirect('/')
|
||||||
|
} catch (err) {
|
||||||
|
res.render('legacy/login')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.redirect('/login')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logout
|
* Logout
|
||||||
*/
|
*/
|
||||||
@ -59,10 +140,11 @@ router.get('/register', async (req, res, next) => {
|
|||||||
/**
|
/**
|
||||||
* Verify
|
* Verify
|
||||||
*/
|
*/
|
||||||
router.get('/verify/:token', async (req, res, next) => {
|
router.get('/verify/:token', bruteforce.prevent, async (req, res, next) => {
|
||||||
const usr = await WIKI.models.userKeys.validateToken({ kind: 'verify', token: req.params.token })
|
const usr = await WIKI.models.userKeys.validateToken({ kind: 'verify', token: req.params.token })
|
||||||
await WIKI.models.users.query().patch({ isVerified: true }).where('id', usr.id)
|
await WIKI.models.users.query().patch({ isVerified: true }).where('id', usr.id)
|
||||||
const result = await WIKI.models.users.refreshToken(usr)
|
const result = await WIKI.models.users.refreshToken(usr)
|
||||||
|
req.brute.reset()
|
||||||
res.cookie('jwt', result.token, { expires: moment().add(1, 'years').toDate() })
|
res.cookie('jwt', result.token, { expires: moment().add(1, 'years').toDate() })
|
||||||
res.redirect('/')
|
res.redirect('/')
|
||||||
})
|
})
|
||||||
|
@ -200,7 +200,7 @@ router.get('/*', async (req, res, next) => {
|
|||||||
if (_.isString(page.toc)) {
|
if (_.isString(page.toc)) {
|
||||||
page.toc = JSON.parse(page.toc)
|
page.toc = JSON.parse(page.toc)
|
||||||
}
|
}
|
||||||
res.render('legacy', { page, sidebar, injectCode })
|
res.render('legacy/page', { page, sidebar, injectCode })
|
||||||
} else {
|
} else {
|
||||||
res.render('page', { page, sidebar, injectCode })
|
res.render('page', { page, sidebar, injectCode })
|
||||||
}
|
}
|
||||||
|
21
server/views/legacy/login.pug
Normal file
21
server/views/legacy/login.pug
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
extends master.pug
|
||||||
|
|
||||||
|
block body
|
||||||
|
#root
|
||||||
|
.login-deprecated Your browser is outdated. Upgrade to a #[a(href='https://bestvpn.org/outdatedbrowser/en', rel='nofollow') modern browser].
|
||||||
|
.login
|
||||||
|
.login-dialog
|
||||||
|
form(method='post', action='/login')
|
||||||
|
h1= config.title
|
||||||
|
select(name='strategy')
|
||||||
|
each str in formStrategies
|
||||||
|
option(value=str.key, selected)= str.title
|
||||||
|
input(type='text', name='user', placeholder='Username / Email')
|
||||||
|
input(type='password', name='pass', placeholder='Password')
|
||||||
|
button(type='submit') Login
|
||||||
|
if socialStrategies.length
|
||||||
|
.login-social
|
||||||
|
h2 or login using...
|
||||||
|
each str in socialStrategies
|
||||||
|
a.login-social-icon(href='/login/' + str.key, class=str.color)
|
||||||
|
!= str.icon
|
82
server/views/legacy/master.pug
Normal file
82
server/views/legacy/master.pug
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
doctype html
|
||||||
|
html
|
||||||
|
head
|
||||||
|
meta(http-equiv='X-UA-Compatible', content='IE=edge')
|
||||||
|
meta(charset='UTF-8')
|
||||||
|
meta(name='viewport', content='user-scalable=yes, width=device-width, initial-scale=1, maximum-scale=5')
|
||||||
|
meta(name='theme-color', content='#333333')
|
||||||
|
meta(name='msapplication-TileColor', content='#333333')
|
||||||
|
meta(name='msapplication-TileImage', content='/favicons/ms-icon-144x144.png')
|
||||||
|
|
||||||
|
title= pageMeta.title + ' | ' + config.title
|
||||||
|
|
||||||
|
//- SEO / OpenGraph
|
||||||
|
meta(name='description', content=pageMeta.description)
|
||||||
|
meta(property='og:title', content=pageMeta.title)
|
||||||
|
meta(property='og:type', content='website')
|
||||||
|
meta(property='og:description', content=pageMeta.description)
|
||||||
|
meta(property='og:image', content=pageMeta.image)
|
||||||
|
meta(property='og:url', content=pageMeta.url)
|
||||||
|
meta(property='og:site_name', content=config.title)
|
||||||
|
|
||||||
|
//- Favicon
|
||||||
|
each favsize in [57, 60, 72, 76, 114, 120, 144, 152, 180]
|
||||||
|
link(rel='apple-touch-icon', sizes=favsize + 'x' + favsize, href='/favicons/apple-icon-' + favsize + 'x' + favsize + '.png')
|
||||||
|
link(rel='icon', type='image/png', sizes='192x192', href='/favicons/android-icon-192x192.png')
|
||||||
|
each favsize in [32, 96, 16]
|
||||||
|
link(rel='icon', type='image/png', sizes=favsize + 'x' + favsize, href='/favicons/favicon-' + favsize + 'x' + favsize + '.png')
|
||||||
|
link(rel='manifest', href='/manifest.json')
|
||||||
|
|
||||||
|
//- Icon Set
|
||||||
|
if config.theming.iconset === 'mdi'
|
||||||
|
link(
|
||||||
|
type='text/css'
|
||||||
|
rel='stylesheet'
|
||||||
|
href='https://cdn.materialdesignicons.com/3.7.95/css/materialdesignicons.min.css'
|
||||||
|
)
|
||||||
|
else if config.theming.iconset === 'fa'
|
||||||
|
link(
|
||||||
|
type='text/css'
|
||||||
|
rel='stylesheet'
|
||||||
|
href='https://use.fontawesome.com/releases/v5.0.13/css/all.css'
|
||||||
|
)
|
||||||
|
else if config.theming.iconset === 'fa4'
|
||||||
|
link(
|
||||||
|
type='text/css'
|
||||||
|
rel='stylesheet'
|
||||||
|
href='https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css'
|
||||||
|
)
|
||||||
|
|
||||||
|
//- CSS
|
||||||
|
|
||||||
|
|
||||||
|
script(
|
||||||
|
crossorigin='anonymous'
|
||||||
|
src='https://polyfill.io/v3/polyfill.min.js?features=EventSource'
|
||||||
|
)
|
||||||
|
|
||||||
|
//- JS
|
||||||
|
|
||||||
|
|
||||||
|
script(
|
||||||
|
type='text/javascript'
|
||||||
|
src='/js/runtime.js'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
script(
|
||||||
|
type='text/javascript'
|
||||||
|
src='/js/legacy.js'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
!= analyticsCode.head
|
||||||
|
|
||||||
|
block head
|
||||||
|
|
||||||
|
body
|
||||||
|
!= analyticsCode.bodyStart
|
||||||
|
block body
|
||||||
|
!= analyticsCode.bodyEnd
|
56
server/views/legacy/page.pug
Normal file
56
server/views/legacy/page.pug
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
extends master.pug
|
||||||
|
|
||||||
|
block head
|
||||||
|
if injectCode.css
|
||||||
|
style(type='text/css')!= injectCode.css
|
||||||
|
if injectCode.head
|
||||||
|
!= injectCode.head
|
||||||
|
|
||||||
|
block body
|
||||||
|
#root
|
||||||
|
.header
|
||||||
|
span.header-title= siteConfig.title
|
||||||
|
span.header-deprecated Your browser is outdated. Upgrade to a #[a(href='https://bestvpn.org/outdatedbrowser/en', rel='nofollow') modern browser].
|
||||||
|
span.header-login
|
||||||
|
a(href='/login')
|
||||||
|
i.material-icons account_circle
|
||||||
|
.main
|
||||||
|
.sidebar
|
||||||
|
each navItem in sidebar
|
||||||
|
if navItem.kind === 'link'
|
||||||
|
a.sidebar-link(href=navItem.target)
|
||||||
|
i.material-icons= navItem.icon
|
||||||
|
span= navItem.label
|
||||||
|
else if navItem.kind === 'divider'
|
||||||
|
.sidebar-divider
|
||||||
|
else if navItem.kind === 'header'
|
||||||
|
.sidebar-title= navItem.label
|
||||||
|
.main-container
|
||||||
|
.page-header
|
||||||
|
.page-header-left
|
||||||
|
h1= page.title
|
||||||
|
h2= page.description
|
||||||
|
.page-header-right
|
||||||
|
.page-header-right-title Last edited by
|
||||||
|
.page-header-right-author= page.authorName
|
||||||
|
.page-header-right-updated= page.updatedAt
|
||||||
|
.page-contents
|
||||||
|
.contents
|
||||||
|
div!= page.render
|
||||||
|
if page.toc.length
|
||||||
|
.toc
|
||||||
|
.toc-title Table of Contents
|
||||||
|
each tocItem, tocIdx in page.toc
|
||||||
|
a.toc-tile(href='#' + tocItem.anchor)
|
||||||
|
i.material-icons arrow_right
|
||||||
|
span= tocItem.title
|
||||||
|
if tocIdx < page.toc.length - 1 || tocItem.children.length
|
||||||
|
.toc-divider
|
||||||
|
each tocSubItem in tocItem.children
|
||||||
|
a.toc-tile.inset(href='#' + tocSubItem.anchor)
|
||||||
|
i.material-icons arrow_right
|
||||||
|
span= tocSubItem.title
|
||||||
|
if tocIdx < page.toc.length - 1
|
||||||
|
.toc-divider.inset
|
||||||
|
if injectCode.body
|
||||||
|
!= injectCode.body
|
@ -31,6 +31,26 @@ html
|
|||||||
script.
|
script.
|
||||||
var siteConfig = !{JSON.stringify(siteConfig)}; var siteLangs = !{JSON.stringify(langs)}
|
var siteConfig = !{JSON.stringify(siteConfig)}; var siteLangs = !{JSON.stringify(langs)}
|
||||||
|
|
||||||
|
//- Icon Set
|
||||||
|
if config.theming.iconset === 'mdi'
|
||||||
|
link(
|
||||||
|
type='text/css'
|
||||||
|
rel='stylesheet'
|
||||||
|
href='https://cdn.materialdesignicons.com/3.7.95/css/materialdesignicons.min.css'
|
||||||
|
)
|
||||||
|
else if config.theming.iconset === 'fa'
|
||||||
|
link(
|
||||||
|
type='text/css'
|
||||||
|
rel='stylesheet'
|
||||||
|
href='https://use.fontawesome.com/releases/v5.0.13/css/all.css'
|
||||||
|
)
|
||||||
|
else if config.theming.iconset === 'fa4'
|
||||||
|
link(
|
||||||
|
type='text/css'
|
||||||
|
rel='stylesheet'
|
||||||
|
href='https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css'
|
||||||
|
)
|
||||||
|
|
||||||
//- CSS
|
//- CSS
|
||||||
|
|
||||||
|
|
||||||
|
12
yarn.lock
12
yarn.lock
@ -3340,6 +3340,14 @@ browserslist@^4.6.1:
|
|||||||
electron-to-chromium "^1.3.164"
|
electron-to-chromium "^1.3.164"
|
||||||
node-releases "^1.1.23"
|
node-releases "^1.1.23"
|
||||||
|
|
||||||
|
brute-knex@4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/brute-knex/-/brute-knex-4.0.0.tgz#bb23549017565983e5ed7858214d8d15b690c3bb"
|
||||||
|
integrity sha512-mMpMvCJjWasupvbcYVPIb6QSWT67U8zKzp+nG6NRsQUeXJHE2fS76EG5r+NSzoQO7xKZ7kONnNkylnivZ9ASmA==
|
||||||
|
dependencies:
|
||||||
|
express-brute "^1.0.1"
|
||||||
|
knex "^0.17"
|
||||||
|
|
||||||
bser@^2.0.0:
|
bser@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
|
resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
|
||||||
@ -5720,7 +5728,7 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
homedir-polyfill "^1.0.1"
|
homedir-polyfill "^1.0.1"
|
||||||
|
|
||||||
express-brute@1.0.1:
|
express-brute@1.0.1, express-brute@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/express-brute/-/express-brute-1.0.1.tgz#9f36d107fe34e40a682593e39bffcc53102b5335"
|
resolved "https://registry.yarnpkg.com/express-brute/-/express-brute-1.0.1.tgz#9f36d107fe34e40a682593e39bffcc53102b5335"
|
||||||
integrity sha1-nzbRB/405ApoJZPjm//MUxArUzU=
|
integrity sha1-nzbRB/405ApoJZPjm//MUxArUzU=
|
||||||
@ -8141,7 +8149,7 @@ klaw@3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs "^4.1.9"
|
graceful-fs "^4.1.9"
|
||||||
|
|
||||||
knex@0.17.6:
|
knex@0.17.6, knex@^0.17:
|
||||||
version "0.17.6"
|
version "0.17.6"
|
||||||
resolved "https://registry.yarnpkg.com/knex/-/knex-0.17.6.tgz#80220cf159cd52768d5b29118c70b18aaf5138fe"
|
resolved "https://registry.yarnpkg.com/knex/-/knex-0.17.6.tgz#80220cf159cd52768d5b29118c70b18aaf5138fe"
|
||||||
integrity sha512-4SKp8jaBxqlEoaveenmpfnHEv5Kzo6/vhIj8UhW1srGw/FKqARTr+7Fv8C1C1qeVHDjv0coQWuUzN5eermHUsw==
|
integrity sha512-4SKp8jaBxqlEoaveenmpfnHEv5Kzo6/vhIj8UhW1srGw/FKqARTr+7Fv8C1C1qeVHDjv0coQWuUzN5eermHUsw==
|
||||||
|
Loading…
Reference in New Issue
Block a user