feat: add search, close #43
This commit is contained in:
parent
12e2479014
commit
eb5ff3e987
10 changed files with 395 additions and 16 deletions
|
|
@ -1,7 +1,9 @@
|
||||||
{
|
{
|
||||||
"extends": ["vue"],
|
"extends": ["vue"],
|
||||||
|
"env": {
|
||||||
|
"browser": true
|
||||||
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"XMLHttpRequest": true,
|
"$docsify": true
|
||||||
"__docsify__": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ var fs = require('fs')
|
||||||
var cssnano = require('cssnano').process
|
var cssnano = require('cssnano').process
|
||||||
var resolve = require('path').resolve
|
var resolve = require('path').resolve
|
||||||
var postcss = require('postcss')
|
var postcss = require('postcss')
|
||||||
|
var isProd = process.argv[process.argv.length - 1] !== '--dev'
|
||||||
|
|
||||||
var processor = postcss([require('postcss-salad')({
|
var processor = postcss([require('postcss-salad')({
|
||||||
features: {
|
features: {
|
||||||
|
|
@ -34,7 +35,7 @@ list.forEach(function (file) {
|
||||||
.then(function (result) {
|
.then(function (result) {
|
||||||
save(file, result.css)
|
save(file, result.css)
|
||||||
console.log('salad - ' + file)
|
console.log('salad - ' + file)
|
||||||
cssnano(loadLib(file))
|
isProd && cssnano(loadLib(file))
|
||||||
.then(function (result) {
|
.then(function (result) {
|
||||||
saveMin(file, result.css)
|
saveMin(file, result.css)
|
||||||
console.log('cssnao - ' + file)
|
console.log('cssnao - ' + file)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ var buble = require('rollup-plugin-buble')
|
||||||
var commonjs = require('rollup-plugin-commonjs')
|
var commonjs = require('rollup-plugin-commonjs')
|
||||||
var nodeResolve = require('rollup-plugin-node-resolve')
|
var nodeResolve = require('rollup-plugin-node-resolve')
|
||||||
var uglify = require('rollup-plugin-uglify')
|
var uglify = require('rollup-plugin-uglify')
|
||||||
|
var isProd = process.argv[process.argv.length - 1] !== '--dev'
|
||||||
|
|
||||||
var build = function (opts) {
|
var build = function (opts) {
|
||||||
rollup
|
rollup
|
||||||
|
|
@ -16,7 +17,7 @@ var build = function (opts) {
|
||||||
console.log(dest)
|
console.log(dest)
|
||||||
bundle.write({
|
bundle.write({
|
||||||
format: 'iife',
|
format: 'iife',
|
||||||
moduleName: opts.moduleName || 'Docsify',
|
moduleName: opts.moduleName || 'D',
|
||||||
dest: dest
|
dest: dest
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -30,8 +31,19 @@ build({
|
||||||
output: 'docsify.js',
|
output: 'docsify.js',
|
||||||
plugins: [commonjs(), nodeResolve()]
|
plugins: [commonjs(), nodeResolve()]
|
||||||
})
|
})
|
||||||
build({
|
isProd && build({
|
||||||
entry: 'index.js',
|
entry: 'index.js',
|
||||||
output: 'docsify.min.js',
|
output: 'docsify.min.js',
|
||||||
plugins: [commonjs(), nodeResolve(), uglify()]
|
plugins: [commonjs(), nodeResolve(), uglify()]
|
||||||
})
|
})
|
||||||
|
build({
|
||||||
|
entry: 'plugins/search.js',
|
||||||
|
output: 'plugins/search.js',
|
||||||
|
moduleName: 'D.Search'
|
||||||
|
})
|
||||||
|
isProd && build({
|
||||||
|
entry: 'plugins/search.js',
|
||||||
|
output: 'plugins/search.min.js',
|
||||||
|
moduleName: 'D.Search',
|
||||||
|
plugins: [uglify()]
|
||||||
|
})
|
||||||
|
|
|
||||||
19
dev.html
19
dev.html
|
|
@ -6,7 +6,24 @@
|
||||||
<link rel="stylesheet" href="/themes/vue.css">
|
<link rel="stylesheet" href="/themes/vue.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<nav>
|
||||||
|
<a href="#/">En</a>
|
||||||
|
<a href="#/zh-cn">中文</a>
|
||||||
|
</nav>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
</body>
|
</body>
|
||||||
<script src="/lib/docsify.js" data-repo="qingwei-li/docsify" data-name="docsify" data-auto2top></script>
|
<script>
|
||||||
|
window.$docsify = {
|
||||||
|
search: {
|
||||||
|
maxAge: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script
|
||||||
|
src="/lib/docsify.js"
|
||||||
|
data-repo="qingwei-li/docsify"
|
||||||
|
data-name="docsify"
|
||||||
|
data-base-path="docs/"
|
||||||
|
data-auto2top></script>
|
||||||
|
<script src="/lib/plugins/search.js"></script>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rm -rf lib themes && node build/build.js && mkdir lib/themes && mkdir themes && node build/build-css.js",
|
"build": "rm -rf lib themes && node build/build.js && mkdir lib/themes && mkdir themes && node build/build-css.js",
|
||||||
"dev": "node app.js & nodemon -w src -e js,css --exec 'npm run build'",
|
"dev:build": "rm -rf lib themes && mkdir themes && node build/build.js --dev && node build/build-css.js --dev",
|
||||||
|
"dev": "node app.js & nodemon -w src -e js,css --exec 'npm run dev:build'",
|
||||||
"test": "eslint src test"
|
"test": "eslint src test"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export function scrollActiveSidebar () {
|
||||||
|
|
||||||
let hoveredOverSidebar = false
|
let hoveredOverSidebar = false
|
||||||
const anchors = document.querySelectorAll('.anchor')
|
const anchors = document.querySelectorAll('.anchor')
|
||||||
const sidebar = document.querySelector('.sidebar>div')
|
const sidebar = document.querySelector('.sidebar')
|
||||||
const sidebarHeight = sidebar.clientHeight
|
const sidebarHeight = sidebar.clientHeight
|
||||||
|
|
||||||
const nav = {}
|
const nav = {}
|
||||||
|
|
|
||||||
332
src/plugins/search.js
Normal file
332
src/plugins/search.js
Normal file
|
|
@ -0,0 +1,332 @@
|
||||||
|
let INDEXS = {}
|
||||||
|
const CONFIG = {
|
||||||
|
placeholder: 'Type to search',
|
||||||
|
paths: 'auto',
|
||||||
|
maxAge: 86400000 // 1 day
|
||||||
|
}
|
||||||
|
|
||||||
|
const isObj = function (obj) {
|
||||||
|
return Object.prototype.toString.call(obj) === '[object Object]'
|
||||||
|
}
|
||||||
|
|
||||||
|
const escapeHtml = function (string) {
|
||||||
|
const entityMap = {
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'"': '"',
|
||||||
|
"'": ''',
|
||||||
|
'/': '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
return String(string).replace(/[&<>"'\/]/g, s => entityMap[s])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find all filepath from A tag
|
||||||
|
*/
|
||||||
|
const getAllPaths = function () {
|
||||||
|
const paths = []
|
||||||
|
|
||||||
|
;[].slice.call(document.querySelectorAll('a'))
|
||||||
|
.map(node => {
|
||||||
|
const href = node.href
|
||||||
|
if (/#\/[^#]*?$/.test(href)) {
|
||||||
|
const path = href.replace(/^[^#]+#/, '')
|
||||||
|
|
||||||
|
if (paths.indexOf(path) <= 0) paths.push(path)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return file path
|
||||||
|
*/
|
||||||
|
const genFilePath = function (path) {
|
||||||
|
const basePath = window.$docsify.basePath
|
||||||
|
let filePath = /\/$/.test(path) ? `${path}README.md` : `${path}.md`
|
||||||
|
|
||||||
|
filePath = basePath + filePath
|
||||||
|
|
||||||
|
return filePath.replace(/\/\//g, '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate index
|
||||||
|
*/
|
||||||
|
const genIndex = function (path, content = '') {
|
||||||
|
// INDEXS[path] = {}
|
||||||
|
let slug
|
||||||
|
|
||||||
|
content
|
||||||
|
// remove PRE and TEMPLATE tag
|
||||||
|
.replace(/<template[^>]*?>[\s\S]+?<\/template>/g, '')
|
||||||
|
// find all html tag
|
||||||
|
.replace(/<(\w+)([^>]*?)>([\s\S]+?)<\//g, (match, tag, attr, html) => {
|
||||||
|
// remove all html tag
|
||||||
|
const text = html.replace(/<[^>]+>/g, '')
|
||||||
|
|
||||||
|
// tag is headline
|
||||||
|
if (/^h\d$/.test(tag)) {
|
||||||
|
// <h1 id="xxx"></h1>
|
||||||
|
const id = attr.match(/id="(\S+)"/)[1]
|
||||||
|
|
||||||
|
slug = `#/${path}#${id}`.replace(/\/\//, '/')
|
||||||
|
INDEXS[slug] = { slug, title: text, body: '' }
|
||||||
|
} else {
|
||||||
|
// other html tag
|
||||||
|
if (!INDEXS[slug]) {
|
||||||
|
INDEXS[slug] = {}
|
||||||
|
} else {
|
||||||
|
if (INDEXS[slug].body && INDEXS[slug].body.length) {
|
||||||
|
INDEXS[slug].body += '\n' + text
|
||||||
|
} else {
|
||||||
|
INDEXS[slug].body = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* component
|
||||||
|
*/
|
||||||
|
class SearchComponent {
|
||||||
|
constructor () {
|
||||||
|
if (this.rendered) return
|
||||||
|
|
||||||
|
this.style()
|
||||||
|
|
||||||
|
const el = document.createElement('div')
|
||||||
|
const aside = document.querySelector('aside')
|
||||||
|
|
||||||
|
el.classList.add('search')
|
||||||
|
aside.insertBefore(el, aside.children[0])
|
||||||
|
this.render(el)
|
||||||
|
this.rendered = true
|
||||||
|
this.bindEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
style () {
|
||||||
|
const code = `
|
||||||
|
.sidebar {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 6px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search .results-panel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search .results-panel.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search input {
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
padding: 7px;
|
||||||
|
line-height: 22px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search h2 {
|
||||||
|
font-size: 17px;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search .matching-post {
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search .matching-post:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search p {
|
||||||
|
font-size: 14px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search p.empty {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
const style = document.createElement('style')
|
||||||
|
|
||||||
|
style.innerHTML = code
|
||||||
|
document.head.appendChild(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
render (dom) {
|
||||||
|
dom.innerHTML = `<input type="search" placeholder="${CONFIG.placeholder}" /><div class="results-panel"></div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
bindEvent () {
|
||||||
|
const input = document.querySelector('.search input')
|
||||||
|
const panel = document.querySelector('.results-panel')
|
||||||
|
|
||||||
|
input.addEventListener('input', e => {
|
||||||
|
const target = e.target
|
||||||
|
|
||||||
|
if (target.value.trim() !== '') {
|
||||||
|
const matchingPosts = this.search(target.value)
|
||||||
|
let html = ''
|
||||||
|
|
||||||
|
matchingPosts.forEach(function (post, index) {
|
||||||
|
html += `
|
||||||
|
<div class="matching-post">
|
||||||
|
<h2><a href="${post.url}">${post.title}</a></h2>
|
||||||
|
<p>${post.content}</p>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
if (panel.classList.contains('results-panel')) {
|
||||||
|
panel.classList.add('show')
|
||||||
|
panel.innerHTML = html || '<p class="empty">No Results!</p>'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (panel.classList.contains('results-panel')) {
|
||||||
|
panel.classList.remove('show')
|
||||||
|
panel.innerHTML = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// From [weex website] https://weex-project.io/js/common.js
|
||||||
|
search (keywords) {
|
||||||
|
const matchingResults = []
|
||||||
|
const data = Object.keys(INDEXS).map(key => INDEXS[key])
|
||||||
|
|
||||||
|
keywords = keywords.trim().split(/[\s\-\,\\/]+/)
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const post = data[i]
|
||||||
|
let isMatch = false
|
||||||
|
let matchingNum = 0
|
||||||
|
let resultStr = ''
|
||||||
|
const postTitle = post.title && post.title.trim()
|
||||||
|
const postContent = post.body && post.body.trim()
|
||||||
|
const postUrl = post.slug || ''
|
||||||
|
const postType = post.pagetitle
|
||||||
|
|
||||||
|
if (postTitle !== '' && postContent !== '') {
|
||||||
|
keywords.forEach((keyword, i) => {
|
||||||
|
const regEx = new RegExp(keyword, 'gi')
|
||||||
|
let indexTitle = -1
|
||||||
|
let indexContent = -1
|
||||||
|
|
||||||
|
indexTitle = postTitle.search(regEx)
|
||||||
|
indexContent = postContent.search(regEx)
|
||||||
|
|
||||||
|
if (indexTitle < 0 && indexContent < 0) {
|
||||||
|
isMatch = false
|
||||||
|
} else {
|
||||||
|
isMatch = true
|
||||||
|
matchingNum++
|
||||||
|
if (indexContent < 0) indexContent = 0
|
||||||
|
|
||||||
|
let start = 0
|
||||||
|
let end = 0
|
||||||
|
|
||||||
|
start = indexContent < 11 ? 0 : indexContent - 10
|
||||||
|
end = start === 0 ? 70 : indexContent + keyword.length + 60
|
||||||
|
|
||||||
|
if (end > postContent.length) end = postContent.length
|
||||||
|
|
||||||
|
const matchContent = '...' +
|
||||||
|
postContent
|
||||||
|
.substring(start, end)
|
||||||
|
.replace(regEx, `<em class="search-keyword">${keyword}</em>`) +
|
||||||
|
'...'
|
||||||
|
|
||||||
|
resultStr += matchContent
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isMatch) {
|
||||||
|
const matchingPost = {
|
||||||
|
title: escapeHtml(postTitle),
|
||||||
|
content: resultStr,
|
||||||
|
url: postUrl,
|
||||||
|
type: postType,
|
||||||
|
matchingNum: matchingNum
|
||||||
|
}
|
||||||
|
|
||||||
|
matchingResults.push(matchingPost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchingResults
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 如果不存在就重新加载
|
||||||
|
const searchPlugin = function () {
|
||||||
|
if (localStorage.getItem('docsify.search.expires') > Date.now()) {
|
||||||
|
INDEXS = JSON.parse(localStorage.getItem('docsify.search.index'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const paths = CONFIG.paths === 'auto' ? getAllPaths() : CONFIG.paths
|
||||||
|
const len = paths.length
|
||||||
|
const { load, marked, slugify } = window.Docsify.utils
|
||||||
|
let count = 0
|
||||||
|
const done = () => {
|
||||||
|
localStorage.setItem('docsify.search.expires', Date.now() + CONFIG.maxAge)
|
||||||
|
localStorage.setItem('docsify.search.index', JSON.stringify(INDEXS))
|
||||||
|
}
|
||||||
|
|
||||||
|
paths.forEach(path => {
|
||||||
|
load(genFilePath(path)).then(content => {
|
||||||
|
genIndex(path, marked(content))
|
||||||
|
slugify.clear()
|
||||||
|
count++
|
||||||
|
|
||||||
|
if (len === count) done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const install = function () {
|
||||||
|
if (!window.Docsify || !window.Docsify.installed) {
|
||||||
|
console.error('[Docsify] Please load docsify.js first.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
window.$docsify.plugins = [].concat(window.$docsify.plugins, searchPlugin)
|
||||||
|
|
||||||
|
const userConfig = window.$docsify.search
|
||||||
|
const isNil = window.Docsify.utils.isNil
|
||||||
|
|
||||||
|
if (Array.isArray(userConfig)) {
|
||||||
|
CONFIG.paths = userConfig
|
||||||
|
} else if (isObj(userConfig)) {
|
||||||
|
CONFIG.paths = Array.isArray(userConfig.paths) ? userConfig.paths : 'auto'
|
||||||
|
CONFIG.maxAge = isNil(userConfig.maxAge) ? CONFIG.maxAge : userConfig.maxAge
|
||||||
|
CONFIG.placeholder = userConfig.placeholder || CONFIG.placeholder
|
||||||
|
}
|
||||||
|
|
||||||
|
new SearchComponent()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default install()
|
||||||
|
|
@ -68,7 +68,11 @@ export function init () {
|
||||||
|
|
||||||
markdown = text => emojify(md(text))
|
markdown = text => emojify(md(text))
|
||||||
|
|
||||||
window.Docsify.utils.marked = markdown
|
window.Docsify.utils.marked = text => {
|
||||||
|
const result = markdown(text)
|
||||||
|
toc = []
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,17 +80,19 @@ export function init () {
|
||||||
*/
|
*/
|
||||||
export function renderApp (dom, replace) {
|
export function renderApp (dom, replace) {
|
||||||
const nav = document.querySelector('nav') || document.createElement('nav')
|
const nav = document.querySelector('nav') || document.createElement('nav')
|
||||||
|
const body = document.body
|
||||||
|
const head = document.head
|
||||||
|
|
||||||
if (!$docsify.repo) nav.classList.add('no-badge')
|
if (!$docsify.repo) nav.classList.add('no-badge')
|
||||||
|
|
||||||
dom[replace ? 'outerHTML' : 'innerHTML'] = tpl.corner($docsify.repo) +
|
dom[replace ? 'outerHTML' : 'innerHTML'] = tpl.corner($docsify.repo) +
|
||||||
($docsify.coverpage ? tpl.cover() : '') +
|
($docsify.coverpage ? tpl.cover() : '') +
|
||||||
tpl.main()
|
tpl.main()
|
||||||
document.body.insertBefore(nav, document.body.children[0])
|
body.insertBefore(nav, body.children[0])
|
||||||
|
|
||||||
// theme color
|
// theme color
|
||||||
if ($docsify.themeColor) {
|
if ($docsify.themeColor) {
|
||||||
document.head.innerHTML += tpl.theme($docsify.themeColor)
|
head.innerHTML += tpl.theme($docsify.themeColor)
|
||||||
polyfill.cssVars()
|
polyfill.cssVars()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,7 +108,7 @@ export function renderApp (dom, replace) {
|
||||||
if ($docsify.coverpage) {
|
if ($docsify.coverpage) {
|
||||||
!isMobile() && window.addEventListener('scroll', event.sticky)
|
!isMobile() && window.addEventListener('scroll', event.sticky)
|
||||||
} else {
|
} else {
|
||||||
document.body.classList.add('sticky')
|
body.classList.add('sticky')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,9 +162,8 @@ export function renderSidebar (content) {
|
||||||
html = tpl.tree(genTree(toc, $docsify.maxLevel), '<ul>')
|
html = tpl.tree(genTree(toc, $docsify.maxLevel), '<ul>')
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(html)
|
renderTo('.sidebar-nav', html)
|
||||||
renderTo('.sidebar>div', html)
|
const target = event.activeLink('.sidebar-nav', true)
|
||||||
const target = event.activeLink('.sidebar>div', true)
|
|
||||||
if (target) renderSubSidebar(target)
|
if (target) renderSubSidebar(target)
|
||||||
toc = []
|
toc = []
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,15 @@
|
||||||
z-index: 999999;
|
z-index: 999999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search a:hover {
|
||||||
|
color: var(--theme-color, $color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search .search-keyword {
|
||||||
|
color: var(--theme-color, $color-primary);
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ export function corner (data) {
|
||||||
* Render main content
|
* Render main content
|
||||||
*/
|
*/
|
||||||
export function main () {
|
export function main () {
|
||||||
const aside = `${toggle()}<aside class="sidebar"><div></div></aside>`
|
const aside = `${toggle()}<aside class="sidebar"><div class="sidebar-nav"></div></aside>`
|
||||||
|
|
||||||
return (isMobile() ? `${aside}<main>` : `<main>${aside}`) +
|
return (isMobile() ? `${aside}<main>` : `<main>${aside}`) +
|
||||||
`<section class="content">
|
`<section class="content">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue