Skip to content

Sideplug #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/semantic.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
titleAndCommits: true
allowMergeCommits: true
allowRevertCommits: true
anyCommit: true
1 change: 1 addition & 0 deletions build/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const buildAllPlugin = function () {
{name: 'emoji', input: 'emoji.js'},
{name: 'external-script', input: 'external-script.js'},
{name: 'front-matter', input: 'front-matter/index.js'},
{name: 'sideplus', input: 'sideplus/index.js'},
{name: 'zoom-image', input: 'zoom-image.js'},
{name: 'disqus', input: 'disqus.js'},
{name: 'gitalk', input: 'gitalk.js'}
Expand Down
15 changes: 15 additions & 0 deletions docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,21 @@ A docsify.js plugin for displaying tabbed content from markdown.

Provided by [@jhildenbiddle](https://github.com/jhildenbiddle/docsify-tabs).

## sideplus

Using this plugin, you can expand/collapse sidebar items by click the arrow icon.

```
<script>
window.$docsify = {
loadSidebar: true,
maxLevel: 6,
subMaxLevel: 6,
}
</script>
<script src="lib/plugins/sideplus.js"></script>
```

## More plugins

See [awesome-docsify](awesome?id=plugins)
26 changes: 19 additions & 7 deletions src/core/event/scroll.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,46 @@
import Tweezer from 'tweezer.js';
import { isMobile } from '../util/env';
import * as dom from '../util/dom';
import { removeParams } from '../router/util';
import config from '../config';
import Tweezer from 'tweezer.js';

const nav = {};
let hoverOver = false;
let scroller = null;
let enableScrollEvent = true;
let coverHeight = 0;

const scrollEvent = {
plugin: false,
enable: true,
};
export { scrollEvent };

function scrollTo(el, offset = 0) {
if (scroller) {
scroller.stop();
}

enableScrollEvent = false;
scrollEvent.enable = false;
scroller = new Tweezer({
start: window.pageYOffset,
end: el.getBoundingClientRect().top + window.pageYOffset - offset,
duration: 500,
})
.on('tick', v => window.scrollTo(0, v))
.on('done', () => {
enableScrollEvent = true;
scrollEvent.enable = true;
scroller = null;
})
.begin();
}

function highlight(path) {
if (!enableScrollEvent) {
if (!scrollEvent.enable) {
return;
}

const sidebar = dom.getNode('.sidebar');
const anchors = dom.findAll('.anchor');
const wrap = dom.find(sidebar, '.sidebar-nav');
let active = dom.find(sidebar, 'li.active');
const doc = document.documentElement;
const top = ((doc && doc.scrollTop) || document.body.scrollTop) - coverHeight;
Expand Down Expand Up @@ -70,12 +74,20 @@ function highlight(path) {
li.classList.add('active');
active = li;

if (!scrollEvent.plugin) {
scrollSidebarIntoView(active);
}
}

export function scrollSidebarIntoView(active) {
const sidebar = dom.getNode('.sidebar');
const wrap = dom.find(sidebar, '.sidebar-nav');
// 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;
Expand Down
4 changes: 2 additions & 2 deletions src/core/render/compiler.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import marked from 'marked';
import { isAbsolutePath, getPath, getParentPath } from '../router/util';
import { isFn, merge, cached, isPrimitive } from '../util/core';
import { tree as treeTpl } from './tpl';
Expand All @@ -12,6 +11,7 @@ import { paragraphCompiler } from './compiler/paragraph';
import { taskListCompiler } from './compiler/taskList';
import { taskListItemCompiler } from './compiler/taskListItem';
import { linkCompiler } from './compiler/link';
import marked from 'marked';

const cachedLinks = {};

Expand Down Expand Up @@ -278,7 +278,7 @@ export class Compiler {
}

const tree = this.cacheTree[currentPath] || genTree(toc, level);
html = treeTpl(tree, '<ul>{inner}</ul>');
html = treeTpl(tree);
this.cacheTree[currentPath] = tree;
}

Expand Down
4 changes: 3 additions & 1 deletion src/core/render/tpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,12 @@ export function tree(toc, tpl = '<ul class="app-sub-sidebar">{inner}</ul>') {

let innerHTML = '';
toc.forEach(node => {
innerHTML += `<li><a class="section-link" href="${node.slug}">${node.title}</a></li>`;
innerHTML += `<li>`;
innerHTML += `<a class="section-link" href="${node.slug}">${node.title}</a>`;
if (node.children) {
innerHTML += tree(node.children, tpl);
}
innerHTML += `</li>`;
});
return tpl.replace('{inner}', innerHTML);
}
Expand Down
19 changes: 19 additions & 0 deletions src/plugins/sideplus/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* eslint-disable no-unused-vars */
/* eslint-disable no-console */
import { style } from './style';
import { rebuild, collapse } from './sidebar';
import { highlight } from './scroll';

const install = function(hook, vm) {
hook.doneEach(function() {
rebuild();
highlight();
});

hook.mounted(function() {
style();
collapse();
});
};

$docsify.plugins = [].concat(install, $docsify.plugins);
51 changes: 51 additions & 0 deletions src/plugins/sideplus/scroll.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { scrollSidebarIntoView, scrollEvent } from '../../core/event/scroll';

export function highlight() {
const dom = Docsify.dom;
scrollEvent.plugin = true;

dom.off('scroll', () => highlightParent());
dom.on('scroll', () => highlightParent());
}

function highlightParent() {
if (!scrollEvent.enable) {
return;
}

const dom = Docsify.dom;

const sidebar = dom.getNode('.sidebar');
let active = dom.find(sidebar, 'li.active');
let parents = dom.findAll(sidebar, 'li.parent');

parents.forEach(node => node.classList.remove('parent'));
active = findParents(active);

scrollSidebarIntoView(active);
}

function findParents(active) {
if (!active) {
return active;
}

let top = active;
let node = active.parentNode;

while (node) {
if (node.classList.contains('app-sub-sidebar')) {
node = node.parentNode;
continue;
} else if (node.classList.contains('has-children')) {
node.classList.add('parent');
if (node.classList.contains('collapse')) {
top = node;
}
node = node.parentNode;
continue;
} else {
return top;
}
}
}
41 changes: 41 additions & 0 deletions src/plugins/sideplus/sidebar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export function rebuild() {
const dom = Docsify.dom;

const sidebar = dom.getNode('.sidebar');
if (sidebar === null || sidebar === undefined) {
return;
}

const list = dom.findAll(sidebar, '.app-sub-sidebar li');

list.forEach(node => {
node.prepend(document.createElement('span'));
if (
node.lastChild &&
node.lastChild.classList &&
node.lastChild.classList.contains('app-sub-sidebar')
) {
node.classList.add('has-children');
}
});
}

export function collapse() {
const dom = Docsify.dom;

const sidebar = dom.getNode('.sidebar');
if (sidebar === null || sidebar === undefined) {
return;
}

dom.on(sidebar, 'click', ({ target }) => {
if (
target.nodeName === 'SPAN' &&
target.nextSibling &&
target.nextSibling.classList &&
target.nextSibling.classList.contains('section-link')
) {
dom.toggleClass(target.parentNode, 'collapse');
}
});
}
41 changes: 41 additions & 0 deletions src/plugins/sideplus/style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export function style() {
const code = `
.app-sub-sidebar li:before {
content: '';
padding: 0;
}
.app-sub-sidebar li > span:after {
content: '\\00A0';
font-size: 12px;
line-height: 1em;
padding: 0 12px 0 0;
float: left;
}
.app-sub-sidebar li.has-children > span:after {
-webkit-writing-mode: vertical-lr;
-ms-writing-mode: tb-lr;
writing-mode: vertical-lr;
content: '\\276F';
font-size: 12px;
line-height: 1em;
padding: 12px 3px 0 0;
float: left;
}
.app-sub-sidebar li.has-children.collapse > span:after {
-webkit-writing-mode: horizontal-tb;
-ms-writing-mode: lr-tb;
writing-mode: horizontal-tb;
content: '\\276F';
font-size: 12px;
line-height: 1em;
padding: 9px 7px 0 2px;
float: left;
}
.sidebar li.collapse.parent > a {
border-right: 2px solid;
color: var(--theme-color, #42b983);
font-weight: 600;
}`;

Docsify.dom.style(code);
}