mirror of
https://github.com/koel/koel
synced 2024-11-12 23:47:09 +00:00
feat: better safe triangle for submenus
This commit is contained in:
parent
563e9af0d3
commit
c29abe4657
2 changed files with 35 additions and 28 deletions
|
@ -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>
|
||||||
|
|
|
@ -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%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue