fix: stabilize volume hover panel
This commit is contained in:
@@ -232,7 +232,7 @@ templ VideoPlayer(data WatchPageData) {
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<div data-volume-wrap class="volume-wrap relative flex h-10 w-10 items-center justify-center overflow-visible">
|
<div data-volume-wrap class="volume-wrap relative flex h-10 w-10 items-center justify-center overflow-visible">
|
||||||
<span data-volume-bridge class="pointer-events-none absolute inset-x-0 bottom-full h-[calc(100%+100px)]"></span>
|
<span data-volume-bridge class="absolute inset-x-0 bottom-full h-[calc(100%+26px)]"></span>
|
||||||
<div class="volume-panel pointer-events-none absolute bottom-[calc(100%+26px)] left-1/2 z-30 -translate-x-1/2 opacity-0 invisible transition-opacity">
|
<div class="volume-panel pointer-events-none absolute bottom-[calc(100%+26px)] left-1/2 z-30 -translate-x-1/2 opacity-0 invisible transition-opacity">
|
||||||
<input
|
<input
|
||||||
data-volume-range
|
data-volume-range
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ const initPlayer = (): void => {
|
|||||||
const iconPause = container.querySelector('[data-icon-pause]') as SVGElement
|
const iconPause = container.querySelector('[data-icon-pause]') as SVGElement
|
||||||
const muteBtn = container.querySelector('[data-mute]') as HTMLButtonElement
|
const muteBtn = container.querySelector('[data-mute]') as HTMLButtonElement
|
||||||
const volumeWrap = container.querySelector('[data-volume-wrap]') as HTMLElement
|
const volumeWrap = container.querySelector('[data-volume-wrap]') as HTMLElement
|
||||||
|
const volumePanel = container.querySelector('.volume-panel') as HTMLElement
|
||||||
const volumeRange = container.querySelector('[data-volume-range]') as HTMLInputElement
|
const volumeRange = container.querySelector('[data-volume-range]') as HTMLInputElement
|
||||||
const iconVolume = container.querySelector('[data-icon-volume]') as SVGElement
|
const iconVolume = container.querySelector('[data-icon-volume]') as SVGElement
|
||||||
const iconMuted = container.querySelector('[data-icon-muted]') as SVGElement
|
const iconMuted = container.querySelector('[data-icon-muted]') as SVGElement
|
||||||
@@ -501,25 +502,35 @@ const initPlayer = (): void => {
|
|||||||
showControls()
|
showControls()
|
||||||
})
|
})
|
||||||
|
|
||||||
muteBtn?.addEventListener('mouseenter', () => {
|
const setVolumePanelOpen = (isOpen: boolean): void => {
|
||||||
muteBtn.classList.add('show-volume')
|
if (volumePanel) {
|
||||||
isHoveringVolume = true
|
volumePanel.classList.toggle('is-visible', isOpen)
|
||||||
showControls()
|
}
|
||||||
})
|
volumeWrap?.classList.toggle('is-volume-open', isOpen)
|
||||||
|
isHoveringVolume = isOpen
|
||||||
|
if (isOpen) showControls()
|
||||||
|
}
|
||||||
|
|
||||||
muteBtn?.addEventListener('mouseleave', () => {
|
const openVolumePanel = (): void => {
|
||||||
isHoveringVolume = false
|
setVolumePanelOpen(true)
|
||||||
showControls()
|
}
|
||||||
})
|
|
||||||
|
|
||||||
volumeWrap?.addEventListener('focusin', () => {
|
const closeVolumePanel = (): void => {
|
||||||
isHoveringVolume = true
|
setVolumePanelOpen(false)
|
||||||
showControls()
|
}
|
||||||
})
|
|
||||||
|
|
||||||
volumeWrap?.addEventListener('focusout', () => {
|
closeVolumePanel()
|
||||||
isHoveringVolume = false
|
|
||||||
showControls()
|
muteBtn?.addEventListener('mouseenter', openVolumePanel)
|
||||||
|
|
||||||
|
volumeWrap?.addEventListener('mouseleave', closeVolumePanel)
|
||||||
|
|
||||||
|
volumeWrap?.addEventListener('focusin', openVolumePanel)
|
||||||
|
|
||||||
|
volumeWrap?.addEventListener('focusout', (event: FocusEvent) => {
|
||||||
|
const nextTarget = event.relatedTarget
|
||||||
|
if (nextTarget instanceof Node && volumeWrap.contains(nextTarget)) return
|
||||||
|
closeVolumePanel()
|
||||||
})
|
})
|
||||||
|
|
||||||
backwardBtn?.addEventListener('click', () => seekBy(-10))
|
backwardBtn?.addEventListener('click', () => seekBy(-10))
|
||||||
|
|||||||
@@ -75,29 +75,21 @@
|
|||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.55);
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.55);
|
||||||
}
|
}
|
||||||
|
|
||||||
.volume-wrap::before {
|
.volume-panel.is-visible {
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: -10px;
|
|
||||||
right: -10px;
|
|
||||||
bottom: 100%;
|
|
||||||
height: 130px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.volume-wrap:has([data-mute]:hover) .volume-panel,
|
|
||||||
.volume-wrap:has([data-volume-bridge]:hover) .volume-panel,
|
|
||||||
.volume-wrap:has(.volume-panel:hover) .volume-panel,
|
|
||||||
.volume-wrap:focus-within .volume-panel,
|
|
||||||
.volume-panel:hover,
|
|
||||||
.volume-panel:focus-within {
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.volume-wrap:has([data-mute]:hover) .volume-underline,
|
.volume-wrap[data-volume-wrap] [data-volume-bridge] {
|
||||||
.volume-wrap:has([data-volume-bridge]:hover) .volume-underline,
|
pointer-events: none;
|
||||||
.volume-wrap:has(.volume-panel:hover) .volume-underline,
|
}
|
||||||
|
|
||||||
|
.volume-wrap.is-volume-open[data-volume-wrap] [data-volume-bridge] {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.volume-wrap:has(.volume-panel.is-visible) .volume-underline,
|
||||||
.volume-wrap:focus-within .volume-underline {
|
.volume-wrap:focus-within .volume-underline {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user