Created
September 4, 2020 10:54
-
-
Save dive2Pro/ab3c95e972dd3549989451cb4109a861 to your computer and use it in GitHub Desktop.
给 roam 添加边栏
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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