Compare commits

...

5 Commits

Author SHA1 Message Date
612d673cbb
style: add text-xs classes to playroom time displays for consistency
Some checks failed
构建扩展程序 / 发布至 Chrome 应用商店 (push) Blocked by required conditions
构建扩展程序 / 发布至 Firefox 附加组件库 (push) Blocked by required conditions
构建扩展程序 / 发布至 Edge 附加组件商店 (push) Blocked by required conditions
构建扩展程序 / 构建 Chrome 扩展程序 (push) Failing after 11m32s
构建扩展程序 / 构建 Firefox 附加组件 (push) Failing after 11m28s
Ensure consistent font sizing across different browsers by applying
Tailwind's text-xs utility classes to current time, format detector,
and duration display elements in the playroom interface.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-04 21:07:38 +10:00
1c5ee95086
refactor: improve code quality in Playroom.vue
- Use Number.isNaN instead of isNaN for better type safety
- Convert anonymous function to arrow function for consistency
- Add explicit braces to single-line if statement for clarity

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-04 21:07:19 +10:00
6461c0adac
style: add text-xs class to player title for non-Chrome browsers
Ensure consistent font size rendering across different browsers
by applying Tailwind's text-xs utility class to the song title
in the mini player component.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-04 21:03:09 +10:00
672b2d80d5
refactor: simplify currentTrack computed property in Player.vue
Remove unnecessary else clause for cleaner code structure.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-04 21:02:24 +10:00
92093ef80d
fix: resolve playroom UI state inconsistency when page loses focus
When lyrics are enabled and the page loses focus while playing a song without lyrics,
then plays a song with lyrics, returning to the page caused controller and lyrics
layout to become misaligned. Added page focus handlers to sync UI state correctly.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-04 20:54:54 +10:00
3 changed files with 136 additions and 8 deletions

View File

@ -24,9 +24,9 @@ console.log('[Player] 检查 store 方法:', {
const currentTrack = computed(() => { const currentTrack = computed(() => {
if (playQueueStore.playMode.shuffle && playQueueStore.shuffleList.length > 0) { if (playQueueStore.playMode.shuffle && playQueueStore.shuffleList.length > 0) {
return playQueueStore.list[playQueueStore.shuffleList[playQueueStore.currentIndex]] return playQueueStore.list[playQueueStore.shuffleList[playQueueStore.currentIndex]]
} else {
return playQueueStore.list[playQueueStore.currentIndex]
} }
return playQueueStore.list[playQueueStore.currentIndex]
}) })
// //
@ -395,7 +395,7 @@ setInterval(syncVolumeFromStorage, 100)
<RouterLink to="/playroom"> <RouterLink to="/playroom">
<div class="flex items-center w-32 h-9"> <div class="flex items-center w-32 h-9">
<span class="truncate">{{ getCurrentTrack()?.song.name }}</span> <span class="truncate text-xs">{{ getCurrentTrack()?.song.name }}</span>
</div> </div>
</RouterLink> </RouterLink>

View File

@ -543,8 +543,39 @@ watch(() => props.lrcSrc, async (newSrc) => {
} }
}, { immediate: true }) }, { immediate: true })
//
let handleVisibilityChange: (() => void) | null = null
//
function setupPageFocusHandlers() {
handleVisibilityChange = () => {
if (document.hidden) {
//
if (scrollTween) scrollTween.pause()
if (highlightTween) highlightTween.pause()
} else {
//
if (scrollTween && scrollTween.paused()) scrollTween.resume()
if (highlightTween && highlightTween.paused()) highlightTween.resume()
//
nextTick(() => {
if (currentLineIndex.value >= 0 && autoScroll.value && !userScrolling.value) {
scrollToLine(currentLineIndex.value, false) // 使
}
})
}
}
document.addEventListener('visibilitychange', handleVisibilityChange)
}
// //
onMounted(() => { onMounted(() => {
//
setupPageFocusHandlers()
// //
if (controlPanel.value) { if (controlPanel.value) {
gsap.fromTo(controlPanel.value, gsap.fromTo(controlPanel.value,
@ -577,6 +608,11 @@ onUnmounted(() => {
if (scrollTween) scrollTween.kill() if (scrollTween) scrollTween.kill()
if (highlightTween) highlightTween.kill() if (highlightTween) highlightTween.kill()
if (userScrollTimeout) clearTimeout(userScrollTimeout) if (userScrollTimeout) clearTimeout(userScrollTimeout)
//
if (handleVisibilityChange) {
document.removeEventListener('visibilitychange', handleVisibilityChange)
}
}) })
// //

View File

@ -83,6 +83,9 @@ onMounted(async () => {
thumbUpdate() thumbUpdate()
setupEntranceAnimations() setupEntranceAnimations()
//
setupPageFocusHandlers()
}) })
function timeFormatter(time: number) { function timeFormatter(time: number) {
@ -90,7 +93,7 @@ function timeFormatter(time: number) {
if (timeInSeconds < 0) { return '-:--' } if (timeInSeconds < 0) { return '-:--' }
const minutes = Math.floor(timeInSeconds / 60) const minutes = Math.floor(timeInSeconds / 60)
const seconds = Math.floor(timeInSeconds % 60) const seconds = Math.floor(timeInSeconds % 60)
if (isNaN(minutes) || isNaN(seconds)) { return '-:--' } if (Number.isNaN(minutes) || Number.isNaN(seconds)) { return '-:--' }
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}` return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`
} }
@ -155,7 +158,7 @@ function createVolumeDraggable() {
// localStorage // localStorage
localStorage.setItem('audioVolume', newVolume.toString()) localStorage.setItem('audioVolume', newVolume.toString())
}, },
onDragEnd: function () { onDragEnd: () => {
// //
localStorage.setItem('audioVolume', volume.value.toString()) localStorage.setItem('audioVolume', volume.value.toString())
} }
@ -419,9 +422,98 @@ watch(() => [preferences.presentLyrics, getCurrentTrack()?.song.lyricUrl], (newV
} }
}, { immediate: true }) }, { immediate: true })
//
let handleVisibilityChange: (() => void) | null = null
let handlePageFocus: (() => void) | null = null
onUnmounted(() => { onUnmounted(() => {
//
if (handleVisibilityChange) {
document.removeEventListener('visibilitychange', handleVisibilityChange)
}
if (handlePageFocus) {
window.removeEventListener('focus', handlePageFocus)
}
}) })
//
function setupPageFocusHandlers() {
handleVisibilityChange = () => {
if (document.hidden) {
//
console.log('[Playroom] 页面失去焦点,暂停动画')
} else {
//
console.log('[Playroom] 页面重新获得焦点,同步状态')
nextTick(() => {
resyncLyricsState()
})
}
}
handlePageFocus = () => {
console.log('[Playroom] 窗口获得焦点,同步状态')
nextTick(() => {
resyncLyricsState()
})
}
//
document.addEventListener('visibilitychange', handleVisibilityChange)
window.addEventListener('focus', handlePageFocus)
}
//
function resyncLyricsState() {
const currentTrack = getCurrentTrack()
if (!currentTrack) { return }
console.log('[Playroom] 重新同步歌词状态')
//
if (controllerRef.value) {
gsap.set(controllerRef.value, {
marginLeft: '0rem',
marginRight: '0rem'
})
}
if (lyricsSection.value) {
gsap.set(lyricsSection.value, {
opacity: 1,
x: 0,
y: 0,
scale: 1
})
}
//
const shouldShowLyrics = preferences.presentLyrics && currentTrack.song.lyricUrl ? true : false
if (shouldShowLyrics !== presentLyrics.value) {
console.log(`[Playroom] 歌词状态不一致,重新设置: ${presentLyrics.value} -> ${shouldShowLyrics}`)
//
presentLyrics.value = shouldShowLyrics
//
if (shouldShowLyrics) {
nextTick(() => {
const tl = gsap.timeline()
tl.from(controllerRef.value, {
marginRight: '-40rem',
duration: 0.4,
ease: "power2.out"
}).fromTo(lyricsSection.value,
{ opacity: 0, x: 50, scale: 0.95 },
{ opacity: 1, x: 0, scale: 1, duration: 0.5, ease: "power2.out" },
"-=0.2"
)
})
}
}
}
// New: Watch for track changes and animate // New: Watch for track changes and animate
watch(() => playQueueStore.currentIndex, () => { watch(() => playQueueStore.currentIndex, () => {
if (albumCover.value) { if (albumCover.value) {
@ -513,9 +605,9 @@ watch(() => playQueueStore.currentIndex, () => {
<div class="w-full flex justify-between"> <div class="w-full flex justify-between">
<!-- ...existing time display code... --> <!-- ...existing time display code... -->
<div class="font-medium flex-1 text-left relative"> <div class="font-medium flex-1 text-left text-xs relative">
<span <span
class="text-black blur-lg absolute top-0">{{ timeFormatter(Math.floor(playQueueStore.currentTime)) }}</span> class="text-black blur-lg absolute top-0 text-xs">{{ timeFormatter(Math.floor(playQueueStore.currentTime)) }}</span>
<span <span
class="text-white/90 absolute top-0">{{ timeFormatter(Math.floor(playQueueStore.currentTime)) }}</span> class="text-white/90 absolute top-0">{{ timeFormatter(Math.floor(playQueueStore.currentTime)) }}</span>
</div> </div>
@ -526,7 +618,7 @@ watch(() => playQueueStore.currentIndex, () => {
<div class="flex flex-1"> <div class="flex flex-1">
<div class="flex-1" /> <div class="flex-1" />
<button <button
class="text-white/90 font-medium text-right relative transition-colors duration-200 hover:text-white" class="text-white/90 text-xs font-medium text-right relative transition-colors duration-200 hover:text-white"
@click="preferences.displayTimeLeft = !preferences.displayTimeLeft"> @click="preferences.displayTimeLeft = !preferences.displayTimeLeft">
<span <span
class="text-black blur-lg absolute top-0">{{ `${preferences.displayTimeLeft ? '-' : ''}${timeFormatter(preferences.displayTimeLeft ? Math.floor(playQueueStore.duration) - Math.floor(playQueueStore.currentTime) : playQueueStore.duration)}` }}</span> class="text-black blur-lg absolute top-0">{{ `${preferences.displayTimeLeft ? '-' : ''}${timeFormatter(preferences.displayTimeLeft ? Math.floor(playQueueStore.duration) - Math.floor(playQueueStore.currentTime) : playQueueStore.duration)}` }}</span>