audiobookshelf.audiobookshe.../layouts/docs.vue

148 lines
3.8 KiB
Vue
Raw Normal View History

2022-05-05 18:13:06 -05:00
<template>
<div class="w-screen h-screen max-w-full max-h-screen text-white bg-gradient overflow-hidden">
2023-02-05 09:57:57 +05:30
<div id="sidebar" class="hidden md:block overflow-y-auto fixed top-0 left-0 h-full bg-primary border-r border-white border-opacity-25">
2022-05-05 18:13:06 -05:00
<div class="flex justify-center items-center py-4 mb-6">
<nuxt-link to="/" class="h-12 w-12 -ml-4">
<img src="/Logo48.png" class="h-full w-full" />
</nuxt-link>
<nuxt-link to="/" class="text-2xl pl-2 sm:pl-4 font-book hover:underline">audiobookshelf</nuxt-link>
</div>
2022-12-24 11:04:20 -06:00
<template v-for="category in pageGrouping">
<div :key="category.title">
<p v-if="category.title !== 'Introduction'" class="px-4 py-1 text-xs font-bold text-white uppercase mt-6 mb-1">{{ category.title }}</p>
2022-05-05 18:13:06 -05:00
<sidebar-nav-item v-for="item in category.pages"
:key="item.hash"
:subpath="$route.path"
:hash="item.hash"
:text="item.title"
:selected="currentHash === item.hash"
/>
2022-12-24 11:04:20 -06:00
</div>
</template>
2022-05-05 18:13:06 -05:00
</div>
<div id="docs-content" class="overflow-y-auto max-w-full overflow-x-hidden">
<Nuxt />
</div>
</div>
</template>
<script>
export default {
2022-12-24 11:04:20 -06:00
async fetch() {
this.content = await this.$content(this.$route.name, { deep: true }).fetch()
2023-02-28 17:15:43 -06:00
this.content.sort((a, b) => Number(a.order) - Number(b.order))
2022-12-24 11:04:20 -06:00
if (process.env.NODE_ENV === 'development') console.log('CONTENT', this.content)
},
2022-05-05 18:13:06 -05:00
data() {
return {
2022-12-24 11:04:20 -06:00
content: [],
2022-05-05 18:29:24 -05:00
currentHash: null
2022-05-05 18:13:06 -05:00
}
},
2022-12-24 11:04:20 -06:00
computed: {
pageGrouping() {
const group = {}
this.content.forEach((c) => {
if (!group[c.category]) {
group[c.category] = {
title: c.category,
pages: [c]
}
} else {
group[c.category].pages.push(c)
}
})
return group
}
},
2022-05-05 18:13:06 -05:00
watch: {
'$route.hash'(newVal) {
if (newVal) {
this.scrollTo(newVal)
this.currentHash = newVal
}
}
},
methods: {
scrollTo(hashtag) {
const element = document.querySelector(hashtag);
if (element) {
element.scrollIntoView();
}
2022-05-05 18:13:06 -05:00
},
onScroll(evt) {
2022-12-24 11:04:20 -06:00
const clientHeight = evt.target.clientHeight
const scrollTop = evt.target.scrollTop
const scrollHeight = evt.target.scrollHeight
// Bottom of page
const bottomY = scrollHeight - scrollTop - clientHeight
if (bottomY < 200) {
const lastItem = this.content[this.content.length - 1]
if (lastItem.hash !== this.currentHash) {
this.currentHash = lastItem.hash
}
2022-05-05 18:13:06 -05:00
2022-12-24 11:04:20 -06:00
return
}
2022-05-05 18:13:06 -05:00
2022-12-24 11:04:20 -06:00
let closestItem = null
for (let i = 0; i < this.content.length; i++) {
const item = this.content[i]
const div = document.querySelector(item.hash)
if (!div) {
console.error('Item not found', item)
return
}
const box = div.getBoundingClientRect()
if (box.top >= 0 && box.top < window.innerHeight) {
2022-05-05 18:13:06 -05:00
closestItem = item
break
}
}
if (closestItem && closestItem.hash !== this.currentHash) {
this.currentHash = closestItem.hash
}
}
},
mounted() {
window['docs-content'].addEventListener('scroll', this.onScroll)
setTimeout(() => {
if (this.$route.hash) {
this.scrollTo(this.$route.hash)
this.currentHash = this.$route.hash
} else {
this.currentHash = '#intro'
}
}, 100)
2022-05-05 18:13:06 -05:00
},
beforeDestroy() {
window['docs-content'].removeEventListener('scroll', this.onScroll)
}
}
</script>
<style>
:root {
--sidebar-width: 280px;
}
#sidebar {
width: var(--sidebar-width);
}
#docs-content {
margin-left: var(--sidebar-width);
height: 100vh;
}
@media (max-width: 767px) {
#docs-content {
margin-left: 0px;
height: 100vh;
}
}
2023-02-05 09:57:57 +05:30
</style>