diff --git a/src/core/event/scroll.js b/src/core/event/scroll.js index 47d64b417..35de1a292 100644 --- a/src/core/event/scroll.js +++ b/src/core/event/scroll.js @@ -36,7 +36,7 @@ function highlight(path) { const sidebar = dom.getNode('.sidebar'); const anchors = dom.findAll('.anchor'); - const wrap = dom.find(sidebar, '.sidebar-nav'); + const wrap = dom.find(sidebar, '.app-sub-sidebar'); let active = dom.find(sidebar, 'li.active'); const doc = document.documentElement; const top = ((doc && doc.scrollTop) || document.body.scrollTop) - coverHeight; @@ -70,12 +70,14 @@ function highlight(path) { li.classList.add('active'); active = li; + updateTree(active); + // Scroll into view // https://github.com/vuejs/vuejs.org/blob/master/themes/vue/source/js/common.js#L282-L297 if (!hoverOver && dom.body.classList.contains('sticky')) { const height = sidebar.clientHeight; const curOffset = 0; - const cur = active.offsetTop + active.clientHeight + 40; + const cur = active.offsetTop + active.clientHeight + height / 2; const isInView = active.offsetTop >= wrap.scrollTop && cur <= wrap.scrollTop + height; const notThan = cur - curOffset < height; @@ -85,6 +87,27 @@ function highlight(path) { } } +function updateTree(active) { + let prevParents = dom.findAll('.parent'); + let prevWifes = dom.findAll('.wife'); + let prevChanges = dom.findAll('.change'); + let prevExpands = dom.findAll('.expand'); + + prevParents.forEach(node => node.classList.remove('parent')); + prevWifes.forEach(node => node.classList.remove('wife')); + prevChanges.forEach(node => node.classList.remove('change')); + prevExpands.forEach(node => node.classList.remove('expand')); + + let father = active.parentNode; + while (father && father.className !== 'app-sub-sidebar') { + father.classList.add('parent'); + father = father.parentNode; + } + + let wife = active.lastChild; + wife.nodeName === 'UL' && wife.classList.add('wife'); +} + function getNavKey(path, id) { return `${decodeURIComponent(path)}?id=${decodeURIComponent(id)}`; } @@ -143,14 +166,25 @@ export function scrollIntoView(path, id) { return; } const topMargin = config().topMargin; + + let prevSections = dom.findAll('.current'); + prevSections.forEach(node => node.classList.remove('current')); + const section = dom.find('#' + id); - section && scrollTo(section, topMargin); + if (section) { + section.classList.add('current'); + scrollTo(section, topMargin); + } - const li = nav[getNavKey(path, id)]; const sidebar = dom.getNode('.sidebar'); const active = dom.find(sidebar, 'li.active'); active && active.classList.remove('active'); - li && li.classList.add('active'); + + const li = nav[getNavKey(path, id)]; + if (li) { + li.classList.add('active'); + updateTree(li); + } } const scrollEl = dom.$.scrollingElement || dom.$.documentElement; diff --git a/src/core/event/sidebar.js b/src/core/event/sidebar.js index f252f2b48..1f40ef73e 100644 --- a/src/core/event/sidebar.js +++ b/src/core/event/sidebar.js @@ -42,6 +42,17 @@ export function collapse(el) { target.nextSibling.classList.contains('app-sub-sidebar') ) { dom.toggleClass(target.parentNode, 'collapse'); + } else if ( + target.nodeName === 'SPAN' && + target.nextSibling && + target.nextSibling.classList.contains('section-link') + ) { + dom.toggleClass(target, 'change'); + + let expand = target.nextSibling.nextSibling; + if (expand && expand.nodeName === 'UL') { + dom.toggleClass(expand, 'expand'); + } } }); } diff --git a/src/core/render/compiler.js b/src/core/render/compiler.js index 5cb8f9e5a..95f49059e 100644 --- a/src/core/render/compiler.js +++ b/src/core/render/compiler.js @@ -277,7 +277,7 @@ export class Compiler { } const tree = this.cacheTree[currentPath] || genTree(toc, level); - html = treeTpl(tree, ''); + html = treeTpl(tree, ''); this.cacheTree[currentPath] = tree; } @@ -309,7 +309,7 @@ export class Compiler { cacheTree[currentPath] = tree; this.toc = []; - return treeTpl(tree); + return treeTpl(tree, ''); } header(text, level) { diff --git a/src/core/render/tpl.js b/src/core/render/tpl.js index 85efa436c..99f5fc9e5 100644 --- a/src/core/render/tpl.js +++ b/src/core/render/tpl.js @@ -84,19 +84,27 @@ export function cover() { * Render tree * @param {Array} toc Array of TOC section links * @param {String} tpl TPL list + * @param {Boolean} using specified TPL for all level(true), or root only(false) * @return {String} Rendered tree */ -export function tree(toc, tpl = '') { +export function tree(toc, tpl = '', all = false) { if (!toc || !toc.length) { return ''; } let innerHTML = ''; toc.forEach(node => { - innerHTML += `
  • ${node.title}
  • `; if (node.children) { - innerHTML += tree(node.children, tpl); + innerHTML += `
  • ${node.title}`; + if (!all) { + innerHTML += tree(node.children); + } else { + innerHTML += tree(node.children, tpl, true); + } + } else { + innerHTML += `
  • ${node.title}`; } + innerHTML += `
  • `; }); return tpl.replace('{inner}', innerHTML); } diff --git a/src/themes/basic/_layout.styl b/src/themes/basic/_layout.styl index 3d6d5c33b..7fa6f756b 100644 --- a/src/themes/basic/_layout.styl +++ b/src/themes/basic/_layout.styl @@ -470,3 +470,52 @@ body.close 40%, 80% transform rotate(10deg) + + +.app-sub-sidebar + + ul + display none + + ul.parent, + ul.wife, + ul.expand + display block + + ul.parent.expand, + ul.wife.expand + display none + + li span + display block + width 20px + font-family monospace + font-weight bold + font-size 20px + float left + &:after + content '\00A0' + &.change + &:after + content '\00A0' + + li.has-children + > span + &:after + content '\203A' + > span.change + &:after + content '-' + + li.parent, + li.has-children.active + > span + &:after + content '-' + > span.change + &:after + content '\203A' + +.current + span + color #c94922 \ No newline at end of file diff --git a/src/themes/dolphin.styl b/src/themes/dolphin.styl index 1b000aa21..871475ab5 100644 --- a/src/themes/dolphin.styl +++ b/src/themes/dolphin.styl @@ -39,12 +39,7 @@ body color var(--theme-color, $color-primary) font-weight 600 -.app-sub-sidebar - li - &::before - content '-' - padding-right 4px - float left + /* markdown content found on pages */ .markdown-section h1, .markdown-section h2, .markdown-section h3, .markdown-section h4, .markdown-section strong diff --git a/src/themes/vue.styl b/src/themes/vue.styl index 54f161de4..7456da3a9 100644 --- a/src/themes/vue.styl +++ b/src/themes/vue.styl @@ -39,13 +39,6 @@ body color var(--theme-color, $color-primary) font-weight 600 -.app-sub-sidebar - li - &::before - content '-' - padding-right 4px - float left - /* markdown content found on pages */ .markdown-section h1, .markdown-section h2, .markdown-section h3, .markdown-section h4, .markdown-section strong color #2c3e50