fix(ui): use CSS group-hover for reliable volume panel display
This commit is contained in:
@@ -31,6 +31,7 @@ const initPlayer = (): void => {
|
|||||||
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
|
||||||
|
const volumeUnderline = container.querySelector('[data-volume-underline]') as HTMLElement
|
||||||
const timeDisplay = container.querySelector('[data-time]') as HTMLElement
|
const timeDisplay = container.querySelector('[data-time]') as HTMLElement
|
||||||
const progressWrap = container.querySelector('[data-progress-wrap]') as HTMLElement
|
const progressWrap = container.querySelector('[data-progress-wrap]') as HTMLElement
|
||||||
const progress = container.querySelector('[data-progress]') as HTMLElement
|
const progress = container.querySelector('[data-progress]') as HTMLElement
|
||||||
@@ -84,7 +85,6 @@ const initPlayer = (): void => {
|
|||||||
}
|
}
|
||||||
let controlsTimeout: number | undefined
|
let controlsTimeout: number | undefined
|
||||||
let isScrubbing = false
|
let isScrubbing = false
|
||||||
let isHoveringVolume = false
|
|
||||||
let lastKnownVolume = 1
|
let lastKnownVolume = 1
|
||||||
let activeSubtitles: Array<{ start: number, end: number, text: string }> = []
|
let activeSubtitles: Array<{ start: number, end: number, text: string }> = []
|
||||||
let currentSubtitleTracks: Array<{ lang: string, label: string, url: string }> = []
|
let currentSubtitleTracks: Array<{ lang: string, label: string, url: string }> = []
|
||||||
@@ -627,7 +627,7 @@ const initPlayer = (): void => {
|
|||||||
container.classList.add('show-controls')
|
container.classList.add('show-controls')
|
||||||
window.clearTimeout(controlsTimeout)
|
window.clearTimeout(controlsTimeout)
|
||||||
controlsTimeout = window.setTimeout(() => {
|
controlsTimeout = window.setTimeout(() => {
|
||||||
if (!isScrubbing && !isHoveringVolume && !video.paused) {
|
if (!isScrubbing && !video.paused) {
|
||||||
container.classList.remove('show-controls')
|
container.classList.remove('show-controls')
|
||||||
}
|
}
|
||||||
}, 2000)
|
}, 2000)
|
||||||
@@ -852,35 +852,12 @@ const initPlayer = (): void => {
|
|||||||
showControls()
|
showControls()
|
||||||
})
|
})
|
||||||
|
|
||||||
const setVolumePanelOpen = (isOpen: boolean): void => {
|
volumeRange?.addEventListener('pointerdown', () => {
|
||||||
if (volumePanel) {
|
volumePanel?.classList.add('is-dragging')
|
||||||
volumePanel.classList.toggle('volume-panel-visible', isOpen)
|
})
|
||||||
}
|
|
||||||
volumeWrap?.classList.toggle('is-volume-open', isOpen)
|
|
||||||
isHoveringVolume = isOpen
|
|
||||||
if (isOpen) showControls()
|
|
||||||
}
|
|
||||||
|
|
||||||
const openVolumePanel = (): void => {
|
window.addEventListener('pointerup', () => {
|
||||||
setVolumePanelOpen(true)
|
volumePanel?.classList.remove('is-dragging')
|
||||||
}
|
|
||||||
|
|
||||||
const closeVolumePanel = (): void => {
|
|
||||||
setVolumePanelOpen(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
closeVolumePanel()
|
|
||||||
|
|
||||||
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))
|
||||||
|
|||||||
@@ -114,26 +114,24 @@ templ VideoPlayer(data shared.WatchPageData) {
|
|||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
data-volume-wrap
|
data-volume-wrap
|
||||||
class="relative flex h-9 w-9 items-center justify-center overflow-visible sm:h-10 sm:w-10"
|
class="group/volume relative flex h-9 w-9 items-center justify-center overflow-visible sm:h-10 sm:w-10"
|
||||||
>
|
>
|
||||||
<span
|
|
||||||
data-volume-bridge
|
|
||||||
class="volume-bridge-off absolute inset-x-0 bottom-full h-[calc(100%+26px)]"
|
|
||||||
></span>
|
|
||||||
<div
|
<div
|
||||||
data-volume-panel
|
data-volume-panel
|
||||||
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"
|
class="pointer-events-none absolute bottom-full left-1/2 z-30 -translate-x-1/2 pb-3 opacity-0 invisible transition-all duration-200 group-hover/volume:pointer-events-auto group-hover/volume:opacity-100 group-hover/volume:visible focus-within:pointer-events-auto focus-within:opacity-100 focus-within:visible [&.is-dragging]:pointer-events-auto [&.is-dragging]:opacity-100 [&.is-dragging]:visible"
|
||||||
>
|
>
|
||||||
<input
|
<div class="flex items-center justify-center rounded-md bg-[#2B2B2B] px-3 py-3 shadow-xl">
|
||||||
data-volume-range
|
<input
|
||||||
type="range"
|
data-volume-range
|
||||||
min="0"
|
type="range"
|
||||||
max="100"
|
min="0"
|
||||||
step="1"
|
max="100"
|
||||||
value="100"
|
step="1"
|
||||||
class="h-24 w-4 cursor-pointer appearance-none bg-transparent accent-white [writing-mode:vertical-lr] [direction:rtl]"
|
value="100"
|
||||||
aria-label="Volume"
|
class="h-24 w-1.5 cursor-pointer rounded-full bg-white/20 accent-[#e50914] outline-none [writing-mode:vertical-lr] [direction:rtl]"
|
||||||
/>
|
aria-label="Volume"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
data-mute
|
data-mute
|
||||||
@@ -161,10 +159,11 @@ templ VideoPlayer(data shared.WatchPageData) {
|
|||||||
<line x1="20" y1="9" x2="16" y2="15" stroke="white" stroke-width="1.85" stroke-linecap="round"/>
|
<line x1="20" y1="9" x2="16" y2="15" stroke="white" stroke-width="1.85" stroke-linecap="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<span
|
<span
|
||||||
class="volume-underline pointer-events-none absolute bottom-0 left-1/2 h-0.5 w-6 -translate-x-1/2 bg-white opacity-0 transition-opacity"
|
data-volume-underline
|
||||||
></span>
|
class="volume-underline pointer-events-none absolute bottom-0 left-1/2 h-0.5 w-6 -translate-x-1/2 bg-white opacity-0 transition-opacity"
|
||||||
</div>
|
></span>
|
||||||
|
</div>
|
||||||
<span
|
<span
|
||||||
data-time
|
data-time
|
||||||
class="min-w-0 text-sm text-white tabular-nums sm:text-base"
|
class="min-w-0 text-sm text-white tabular-nums sm:text-base"
|
||||||
|
|||||||
Reference in New Issue
Block a user