feat: better safe triangle for submenus

This commit is contained in:
Phan An 2024-03-17 18:37:58 +01:00
parent 563e9af0d3
commit c29abe4657
2 changed files with 35 additions and 28 deletions

View file

@ -47,11 +47,19 @@ const preventOffScreen = async (element: HTMLElement, isSubmenu = false) => {
} }
} }
const safeAreaHeight = ref('0px')
const safeAreaWidth = ref('0px')
const safeAreaClipPath = ref('0 0, 0 0, 0 0, 0 0')
type MenuItem = HTMLElement & {
eventsRegistered?: boolean
}
const initSubmenus = () => { const initSubmenus = () => {
el.value?.querySelectorAll('.has-sub').forEach(item => { el.value?.querySelectorAll<HTMLElement>('.has-sub').forEach((item: MenuItem) => {
const submenu = item.querySelector<HTMLElement>('.submenu') const submenu = item.querySelector<HTMLElement>('.submenu')
if (!submenu) { if (!submenu || item.eventsRegistered) {
return return
} }
@ -61,17 +69,27 @@ const initSubmenus = () => {
await preventOffScreen(submenu, true) await preventOffScreen(submenu, true)
}) })
item.addEventListener('mousemove', async (e: MouseEvent) => {
await nextTick()
const rect = submenu.getBoundingClientRect()
safeAreaHeight.value = rect.height + 'px'
safeAreaWidth.value = rect.x - e.clientX + 'px'
safeAreaClipPath.value = `polygon(100% 0, 0 ${e.clientY - rect.top}px, 100% 100%)`
})
item.addEventListener('mouseleave', () => { item.addEventListener('mouseleave', () => {
submenu.style.top = '0' submenu.style.top = '0'
submenu.style.bottom = 'auto' submenu.style.bottom = 'auto'
submenu.style.display = 'none' submenu.style.display = 'none'
}) })
item.eventsRegistered = true
}) })
} }
const open = async (_top = 0, _left = 0) => { const open = async (t = 0, l = 0) => {
top.value = _top top.value = t
left.value = _left left.value = l
shown.value = true shown.value = true
await nextTick() await nextTick()
@ -99,5 +117,17 @@ defineExpose({ open, close, shown })
<style lang="scss" scoped> <style lang="scss" scoped>
nav { nav {
user-select: none; user-select: none;
:deep(.has-sub)::after {
position: absolute;
content: '';
right: 0;
top: 0;
z-index: 2;
opacity: 0;
width: v-bind(safeAreaWidth);
height: v-bind(safeAreaHeight);
clip-path: v-bind(safeAreaClipPath);
}
} }
</style> </style>

View file

@ -386,29 +386,6 @@ menu {
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right 8px center; background-position: right 8px center;
background-size: 10px; background-size: 10px;
&:hover {
&::before, &::after {
content: '';
display: block;
position: absolute;
right: 0;
width: 75%;
z-index: 2;
animation: subMenuHoverHelp 1s;
}
&::before {
clip-path: polygon(100% 0, 0% 100%, 100% 100%);
bottom: 100%;
}
&::after {
clip-path: polygon(100% 0, 0 0, 100% 100%);
top: 100%;
}
}
} }
} }