Files
My-KOPKB/fe/src/composables/useSideMenu.ts
T
ISMAIL MASSERAN 94ecbe5887 first init
2026-06-08 11:37:14 +08:00

85 lines
2.2 KiB
TypeScript

import { ref, onMounted, onUnmounted } from 'vue'
const ENIGMA_ROOT = '.enigma'
function getLayoutNodes() {
const root = document.querySelector(ENIGMA_ROOT)
if (!root) return null
return {
sideMenu: root.querySelector<HTMLElement>('.side-menu'),
content: root.querySelector<HTMLElement>('.content'),
}
}
function isCompactLayout() {
return getLayoutNodes()?.sideMenu?.classList.contains('side-menu--collapsed') ?? false
}
function applyCompactLayout(collapsed: boolean) {
const nodes = getLayoutNodes()
if (!nodes?.sideMenu || !nodes.content) return
nodes.sideMenu.classList.toggle('side-menu--collapsed', collapsed)
nodes.content.classList.toggle('content--compact', collapsed)
}
function persistCompactMenu(collapsed: boolean) {
queueMicrotask(() => {
localStorage.setItem('compactMenu', collapsed.toString())
})
}
export const useSideMenu = () => {
const mobileMenuOpen = ref(false)
const scrolled = ref(false)
const toggleCompactMenu = (event: MouseEvent) => {
event.preventDefault()
const collapsed = !isCompactLayout()
applyCompactLayout(collapsed)
persistCompactMenu(collapsed)
}
const openMobileMenu = (event: MouseEvent) => {
event.preventDefault()
mobileMenuOpen.value = true
}
const closeMobileMenu = (event: MouseEvent) => {
event.preventDefault()
mobileMenuOpen.value = false
}
const onScrollContent = (event: Event) => {
const target = event.target as HTMLElement
scrolled.value = target.scrollTop > 0
}
const onResize = () => {
if (window.innerWidth <= 1600) {
applyCompactLayout(true)
persistCompactMenu(true)
}
}
onMounted(() => {
applyCompactLayout(localStorage.getItem('compactMenu') === 'true')
window.addEventListener('resize', onResize)
onResize()
})
onUnmounted(() => {
window.removeEventListener('resize', onResize)
})
return {
mobileMenuOpen,
scrolled,
toggleCompactMenu,
openMobileMenu,
closeMobileMenu,
onScrollContent,
}
}