259 lines
6.2 KiB
JavaScript
259 lines
6.2 KiB
JavaScript
import isDesktop from '../helper/isDesktop'
|
|
|
|
|
|
/**
|
|
* Calculate nested children height in sidebar menu
|
|
* @param {HTMLElement} el
|
|
*/
|
|
const calculateChildrenHeight = (el, deep = false) => {
|
|
const children = el.children
|
|
|
|
let height = 0
|
|
for(let i = 0; i < el.childElementCount; i++) {
|
|
const child = children[i]
|
|
height += child.querySelector('.submenu-link').clientHeight
|
|
|
|
// 2-level menu
|
|
if(deep && child.classList.contains('has-sub')) {
|
|
const subsubmenu = child.querySelector('.submenu')
|
|
|
|
if(subsubmenu.classList.contains('submenu-open')) {
|
|
const childrenHeight = ~~[...subsubmenu.querySelectorAll('.submenu-link')].reduce((acc,curr) => acc + curr.clientHeight,0)
|
|
height += childrenHeight
|
|
}
|
|
}
|
|
|
|
}
|
|
el.style.setProperty('--submenu-height', height + 'px')
|
|
return height
|
|
}
|
|
|
|
/**
|
|
* a Sidebar component
|
|
* @param {HTMLElement} el - sidebar element
|
|
* @param {object} options={} - options
|
|
*/
|
|
class Sidebar {
|
|
constructor(el, options = {}) {
|
|
this.sidebarEL = el instanceof HTMLElement ? el : document.querySelector(el)
|
|
this.options = options
|
|
this.init()
|
|
}
|
|
|
|
/**
|
|
* initialize the sidebar
|
|
*/
|
|
init() {
|
|
// add event listener to sidebar
|
|
document
|
|
.querySelectorAll(".burger-btn")
|
|
.forEach((el) => el.addEventListener("click", this.toggle.bind(this)))
|
|
document
|
|
.querySelectorAll(".sidebar-hide")
|
|
.forEach((el) => el.addEventListener("click", this.toggle.bind(this)))
|
|
window.addEventListener("resize", this.onResize.bind(this))
|
|
|
|
|
|
const toggleSubmenu = (el) => {
|
|
if (el.classList.contains("submenu-open")) {
|
|
el.classList.remove('submenu-open')
|
|
el.classList.add('submenu-closed')
|
|
} else {
|
|
el.classList.remove("submenu-closed")
|
|
el.classList.add("submenu-open")
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
let sidebarItems = document.querySelectorAll(".sidebar-item.has-sub")
|
|
for (var i = 0; i < sidebarItems.length; i++) {
|
|
let sidebarItem = sidebarItems[i]
|
|
|
|
sidebarItems[i]
|
|
.querySelector(".sidebar-link")
|
|
.addEventListener("click", (e) => {
|
|
e.preventDefault()
|
|
let submenu = sidebarItem.querySelector(".submenu")
|
|
toggleSubmenu(submenu)
|
|
})
|
|
|
|
|
|
// If submenu has submenu
|
|
const submenuItems = sidebarItem.querySelectorAll('.submenu-item.has-sub')
|
|
submenuItems.forEach(item => {
|
|
item.addEventListener('click', () => {
|
|
const submenuLevelTwo = item.querySelector('.submenu')
|
|
toggleSubmenu(submenuLevelTwo)
|
|
|
|
// Pass second .submenu
|
|
const height = calculateChildrenHeight(item.parentElement, true)
|
|
|
|
})
|
|
})
|
|
}
|
|
|
|
// Perfect Scrollbar Init
|
|
if (typeof PerfectScrollbar == "function") {
|
|
const container = document.querySelector(".sidebar-wrapper")
|
|
const ps = new PerfectScrollbar(container, {
|
|
wheelPropagation: false,
|
|
})
|
|
}
|
|
|
|
// Scroll into active sidebar
|
|
setTimeout(() => {
|
|
this.forceElementVisibility(document.querySelector(".sidebar-item.active"))
|
|
}, 300)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* On Sidebar Rezise Event
|
|
*/
|
|
onResize() {
|
|
if (isDesktop(window)) {
|
|
this.sidebarEL.classList.add("active")
|
|
} else {
|
|
this.sidebarEL.classList.remove("active")
|
|
}
|
|
|
|
// reset
|
|
this.deleteBackdrop()
|
|
this.toggleOverflowBody(true)
|
|
}
|
|
|
|
/**
|
|
* Toggle Sidebar
|
|
*/
|
|
toggle() {
|
|
const sidebarState = this.sidebarEL.classList.contains("active")
|
|
if (sidebarState) {
|
|
this.hide()
|
|
} else {
|
|
this.show()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show Sidebar
|
|
*/
|
|
show() {
|
|
this.sidebarEL.classList.add("active")
|
|
this.sidebarEL.classList.remove("inactive")
|
|
this.createBackdrop()
|
|
this.toggleOverflowBody()
|
|
}
|
|
|
|
/**
|
|
* Hide Sidebar
|
|
*/
|
|
hide() {
|
|
this.sidebarEL.classList.remove("active")
|
|
this.sidebarEL.classList.add("inactive")
|
|
this.deleteBackdrop()
|
|
this.toggleOverflowBody()
|
|
}
|
|
|
|
/**
|
|
* Create Sidebar Backdrop
|
|
*/
|
|
createBackdrop() {
|
|
if (isDesktop(window)) return
|
|
this.deleteBackdrop()
|
|
const backdrop = document.createElement("div")
|
|
backdrop.classList.add("sidebar-backdrop")
|
|
backdrop.addEventListener("click", this.hide.bind(this))
|
|
document.body.appendChild(backdrop)
|
|
}
|
|
|
|
/**
|
|
* Delete Sidebar Backdrop
|
|
*/
|
|
deleteBackdrop() {
|
|
const backdrop = document.querySelector(".sidebar-backdrop")
|
|
if (backdrop) {
|
|
backdrop.remove()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Toggle Overflow Body
|
|
*/
|
|
toggleOverflowBody(active) {
|
|
if(isDesktop(window)) return;
|
|
const sidebarState = this.sidebarEL.classList.contains("active")
|
|
const body = document.querySelector("body")
|
|
if (typeof active == "undefined") {
|
|
body.style.overflowY = sidebarState ? "hidden" : "auto"
|
|
} else {
|
|
body.style.overflowY = active ? "auto" : "hidden"
|
|
}
|
|
}
|
|
|
|
isElementInViewport(el) {
|
|
var rect = el.getBoundingClientRect()
|
|
|
|
return (
|
|
rect.top >= 0 &&
|
|
rect.left >= 0 &&
|
|
rect.bottom <=
|
|
(window.innerHeight || document.documentElement.clientHeight) &&
|
|
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
|
)
|
|
}
|
|
|
|
forceElementVisibility(el) {
|
|
if (!this.isElementInViewport(el)) {
|
|
el.scrollIntoView(false)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let sidebarEl = document.getElementById("sidebar")
|
|
|
|
/**
|
|
* On First Load
|
|
*/
|
|
const onFirstLoad = (sidebarEL) => {
|
|
if(!sidebarEl) return
|
|
if (isDesktop(window)) {
|
|
sidebarEL.classList.add("active")
|
|
sidebarEL.classList.add('sidebar-desktop')
|
|
}
|
|
|
|
// Get submenus size
|
|
let submenus = document.querySelectorAll(".sidebar-item.has-sub .submenu")
|
|
for (var i = 0; i < submenus.length; i++) {
|
|
let submenu = submenus[i]
|
|
const sidebarItem = submenu.parentElement
|
|
const height = submenu.clientHeight
|
|
|
|
if(sidebarItem.classList.contains('active')) submenu.classList.add('submenu-open')
|
|
else submenu.classList.add('submenu-closed')
|
|
setTimeout(() => {
|
|
const height = calculateChildrenHeight(submenu, true)
|
|
}, 50);
|
|
}
|
|
}
|
|
|
|
if(document.readyState !== 'loading') {
|
|
onFirstLoad(sidebarEl)
|
|
}
|
|
else {
|
|
window.addEventListener('DOMContentLoaded', () => onFirstLoad(sidebarEl))
|
|
}
|
|
/**
|
|
* Create Sidebar Wrapper
|
|
*/
|
|
if (sidebarEl) {
|
|
window.sidebar = new Sidebar(sidebarEl)
|
|
}
|