Stackedit/src/components/Toc.vue

143 lines
3.2 KiB
Vue
Raw Normal View History

2017-07-23 18:42:08 +00:00
<template>
<div class="toc">
2017-09-23 19:01:50 +00:00
<div class="toc__mask" :style="{top: (maskY - 5) + 'px'}"></div>
<div class="toc__inner"></div>
2017-07-23 18:42:08 +00:00
</div>
</template>
2017-08-06 00:58:39 +00:00
<script>
2017-09-23 19:01:50 +00:00
import Vue from 'vue';
import { mapGetters } from 'vuex';
2017-08-06 00:58:39 +00:00
import editorSvc from '../services/editorSvc';
export default {
2017-09-23 19:01:50 +00:00
data: () => ({
maskY: -999,
}),
computed: {
...mapGetters('layout', [
'styles',
]),
},
2017-08-06 00:58:39 +00:00
mounted() {
const tocElt = this.$el.querySelector('.toc__inner');
// TOC click behaviour
let isMousedown;
function onClick(e) {
if (!isMousedown) {
return;
}
e.preventDefault();
const y = e.clientY - tocElt.getBoundingClientRect().top;
editorSvc.sectionDescList.some((sectionDesc) => {
if (y >= sectionDesc.tocDimension.endOffset) {
return false;
}
const posInSection = (y - sectionDesc.tocDimension.startOffset)
/ (sectionDesc.tocDimension.height || 1);
const editorScrollTop = sectionDesc.editorDimension.startOffset
+ (sectionDesc.editorDimension.height * posInSection);
editorSvc.editorElt.parentNode.scrollTop = editorScrollTop;
const previewScrollTop = sectionDesc.previewDimension.startOffset
+ (sectionDesc.previewDimension.height * posInSection);
editorSvc.previewElt.parentNode.scrollTop = previewScrollTop;
return true;
});
}
tocElt.addEventListener('mouseup', () => {
isMousedown = false;
});
tocElt.addEventListener('mouseleave', () => {
isMousedown = false;
});
tocElt.addEventListener('mousedown', (e) => {
isMousedown = e.which === 1;
onClick(e);
});
tocElt.addEventListener('mousemove', (e) => {
onClick(e);
});
2017-09-23 19:01:50 +00:00
// Change mask postion on scroll
const updateMaskY = () => {
const scrollPosition = editorSvc.getScrollPosition();
const sectionDesc = editorSvc.sectionDescList[scrollPosition.sectionIdx];
this.maskY = sectionDesc.tocDimension.startOffset +
(scrollPosition.posInSection * sectionDesc.tocDimension.height);
};
Vue.nextTick(() => {
editorSvc.editorElt.parentNode.addEventListener('scroll', () => {
if (this.styles.showEditor) {
updateMaskY();
}
});
editorSvc.previewElt.parentNode.addEventListener('scroll', () => {
if (!this.styles.showEditor) {
updateMaskY();
}
});
});
2017-08-06 00:58:39 +00:00
},
};
</script>
<style lang="scss">
.toc__inner {
color: rgba(0, 0, 0, 0.75);
cursor: pointer;
font-size: 10px;
padding: 10px 20px 40px;
2017-08-06 00:58:39 +00:00
white-space: nowrap;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
* {
font-weight: inherit;
pointer-events: none;
}
.cl-toc-section {
* {
2017-08-25 10:37:46 +00:00
margin: 0.2em 0;
padding: 0.2em 0;
border-bottom: 0;
2017-08-06 00:58:39 +00:00
}
h2 {
margin-left: 8px;
}
h3 {
margin-left: 16px;
}
h4 {
margin-left: 24px;
}
h5 {
margin-left: 32px;
}
h6 {
margin-left: 40px;
}
}
}
2017-09-23 19:01:50 +00:00
.toc__mask {
position: absolute;
left: 0;
width: 100%;
height: 35px;
background-color: rgba(0, 0, 0, 0.05);
pointer-events: none;
}
2017-08-06 00:58:39 +00:00
</style>