Skip to content

Instantly share code, notes, and snippets.

@dive2Pro
Created September 4, 2020 10:54
Show Gist options
  • Save dive2Pro/ab3c95e972dd3549989451cb4109a861 to your computer and use it in GitHub Desktop.
Save dive2Pro/ab3c95e972dd3549989451cb4109a861 to your computer and use it in GitHub Desktop.
给 roam 添加边栏
// 1. .roam-article 是根节点
// 2. 找到所有的 h1, h2, h3
// 3. 如果 h1, h2 , h3 有子组件, 给这些组件添加扩展功能
// 4. 遍历其子组件 根据子组件的层次, 设置左边导航栏的宽度
// 5. 子组件
let deepest = 1;
function style() {
var css = `
#side-dictory {
position: fixed;
top: 50%;
right: 2%;
display: flex;
flex-direction: column;
width: 150px;
}
#side-dictory:hover .side-item-title {
opacity: 0.5;
}
#side-dictory .side-item {
position: relative;
}
#side-dictory .side-item:hover {
opacity: 1 !important;
}
#side-dictory .side-item.highlight {
opacity: 1;
}
#side-dictory .side-item.highlight .side-item-title {
opacity: 1;
}
.side-item .side-item-title {
display: inline-block;
margin-top: -2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 12px;
line-height: 17px;
color: #8e8787;
display: inline-block;
opacity: 0;
width: 90px;
vertical-align: middle;
text-align: left;
transition: opacity .5s;
position: absolute;
left: 44px;
top: 6px;
}
.side-item .side-item-left {
width: 15px;
background: red;
height: 5px;
display: inline-block;
border-radius: 20px;
margin-right: 4px;
}
`,
head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
head.appendChild(style);
style.type = 'text/css';
if (style.styleSheet){
// This is required for IE8 and below.
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
style();
function dfs(root, elm) {
elm.sideEl = document.createElement('div')
elm.sideEl.className = 'side-item'
elm.parent = root;
const width = ((deepest - elm.level) / deepest) * 30;
$(elm.sideEl).append( `<span class="side-item-left" style="width: ${width}px;" />`)
$(elm.sideEl).append( `<span class="side-item-title">${elm.title}</span> `)
elm.sideEl.atom = elm;
root.append(elm.sideEl);
elm.children.each((i, item) => {
dfs(root, item);
})
expandSideHead(elm);
}
function createSideDirectory() {
// rebuild when pager change
const heads = findAllHeadsOrHaveChildren(getArticle(), 0);
const fragment = document.createDocumentFragment();
let root = $('#side-dictory')
if(root.length === 0) {
root = document.createElement('div');
root.id = 'side-dictory'
root = $(root);
} else {
}
root.empty();
heads.each((index, item) => dfs(fragment, item))
root.css({
position: "fixed",
top: "50%",
right: "2%"
})
root.off('click');
root.on('click', '.side-item' , function(evt) {
const a = $(evt.target).parents('.side-item')
console.log(a.get());
if(a.get().length) {
a.get()[0].atom.events.onClick();
}
})
root.append(fragment);
getArticle().append(root);
}
const TARGER_ELEMENTS = 'h1,h2,h3';
// functionality like: hightlight, click, scrolling
function expandSideHead(head) {
head.
events= {
onClick: () => {
head.el.scrollIntoView({ behavior: 'smooth' })
// TODO
},
highlight: () => {
let h = head;
while(h) {
$(h.sideEl).addClass('highlight');
h = $(h.el).closest('.roam-block-container').atom
}
},
unhighlight: () => {
let h = head;
while(h) {
$(h.sideEl).removeClass('highlight');
h = $(h.el).closest('.roam-block-container').atom
}
},
collapse: () => {}
}
}
function findIntheSameLevel(root) {
root
}
/**
*
* deepest: 4
* @type atom: ([
* {
* title: '',
* id: '',
* level: number,
* children: [],
* el: HTMLElement,
* sideEl: HTMLElement,
* parent: atom | null
* isHighlighting: false
* }
* ])
*
* [jqeury or](https://stackoverflow.com/a/10014528)
*
*/
function findAllHeadsOrHaveChildren(parent,level) {
if(deepest <= level) {
deepest = level + 1;
}
function expandAtom(index, el) {
let n = level - 1;
let fel = el;
while(fel.parentElement) {
if([].find.call(fel.parentElement.classList, ( name => {
return 'roam-block-container' === name
}))) {
n += 1;
}
fel = fel.parentElement;
}
return {
el: $(el).closest('.roam-block-container').get()[0],
title: el.innerText,
level: n,
sideEl: null,
parent,
}
}
// 有个缺陷: 只能同时拿到所有的目标节点, 会丢失层级概念.
const atoms = $(parent).find(TARGER_ELEMENTS).not('.rm-title-display').map(expandAtom);
if(!atoms.length) {
return $([]);
}
atoms.each(function (i, atom) {
atom.children = findAllHeadsOrHaveChildren(atom, level + 1)
} )
return atoms;
}
function getArticle() {
return $('.roam-article')
}
function isInViewport() {
const el = this.get()[0].atom.el;
var elementTop = el.offsetTop;
var elementBottom = elementTop + $(el).outerHeight();
var viewportTop = $('.roam-toolkit--panel').scrollTop();
var viewportBottom = viewportTop + $('.roam-toolkit--panel').height();
if(elementTop <= viewportTop + 3) {
// console.log(elementTop, elementBottom, viewportTop, viewportBottom)
} else {
// console.log(viewportTop, elementTop, this)
}
// 顶部的一定区域
return viewportTop +3 >= elementTop && viewportTop <= elementBottom +3
// return elementBottom > viewportTop && elementTop < viewportBottom && viewportTop- elementTop >= -5;
};
function onScroll() {
$('.side-item').each(function() {
if(!$(this).isInViewport) {
$.fn.isInViewport =isInViewport;
}
if ($(this).isInViewport()) {
const el = this.atom.el;
var elementTop = $(el).offset().top;
var viewportTop = $('.roam-toolkit--panel').scrollTop();
var elementBottom = elementTop + $(el).outerHeight();
this.atom.events.highlight();
console.log(elementTop, elementBottom, viewportTop)
// $(this).addClass('highlight')
} else {
this.atom.events.unhighlight();
// $(this).removeClass('highlight')
}
});
}
$('.roam-toolkit--panel').on('resize scroll', onScroll);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment