From 31393eb7e560717e9b549d289ab26130cf43ec47 Mon Sep 17 00:00:00 2001 From: imsyy Date: Tue, 26 May 2026 18:08:56 +0800 Subject: [PATCH 01/10] =?UTF-8?q?style:=20=E4=BC=98=E5=8C=96=E6=92=AD?= =?UTF-8?q?=E6=94=BE=E5=88=97=E8=A1=A8=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components.d.ts | 2 + src/components/list/PlaylistPanel.vue | 229 ------------------ src/components/list/QueuePopover.vue | 190 +++++++++++++++ .../player/FullPlayer/QueuePanel.vue | 143 +++++++++++ src/components/player/FullPlayer/index.vue | 43 +++- src/components/player/Toolbar.vue | 21 +- src/components/ui/SNumberInput.vue | 3 +- src/components/ui/SVirtualList.vue | 20 +- src/composables/useQueuePanel.ts | 72 ++++++ src/core/hotkey/registry.ts | 6 +- src/layouts/MainLayout.vue | 17 -- src/stores/status.ts | 9 +- 12 files changed, 492 insertions(+), 263 deletions(-) delete mode 100644 src/components/list/PlaylistPanel.vue create mode 100644 src/components/list/QueuePopover.vue create mode 100644 src/components/player/FullPlayer/QueuePanel.vue create mode 100644 src/composables/useQueuePanel.ts diff --git a/components.d.ts b/components.d.ts index ca197163..f3a9f337 100644 --- a/components.d.ts +++ b/components.d.ts @@ -169,6 +169,8 @@ declare module 'vue' { PopoverRoot: typeof import('reka-ui')['PopoverRoot'] PopoverTrigger: typeof import('reka-ui')['PopoverTrigger'] QualityControl: typeof import('./src/components/player/QualityControl.vue')['default'] + QueuePanel: typeof import('./src/components/player/FullPlayer/QueuePanel.vue')['default'] + QueuePopover: typeof import('./src/components/list/QueuePopover.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] SAlert: typeof import('./src/components/ui/SAlert.vue')['default'] diff --git a/src/components/list/PlaylistPanel.vue b/src/components/list/PlaylistPanel.vue deleted file mode 100644 index 42dd6c59..00000000 --- a/src/components/list/PlaylistPanel.vue +++ /dev/null @@ -1,229 +0,0 @@ - - - diff --git a/src/components/list/QueuePopover.vue b/src/components/list/QueuePopover.vue new file mode 100644 index 00000000..1ea77965 --- /dev/null +++ b/src/components/list/QueuePopover.vue @@ -0,0 +1,190 @@ + + + diff --git a/src/components/player/FullPlayer/QueuePanel.vue b/src/components/player/FullPlayer/QueuePanel.vue new file mode 100644 index 00000000..65d54227 --- /dev/null +++ b/src/components/player/FullPlayer/QueuePanel.vue @@ -0,0 +1,143 @@ + + + diff --git a/src/components/player/FullPlayer/index.vue b/src/components/player/FullPlayer/index.vue index 3e495581..77b65a63 100644 --- a/src/components/player/FullPlayer/index.vue +++ b/src/components/player/FullPlayer/index.vue @@ -78,9 +78,10 @@ const hasLyric = computed(() => media.parsedLyric.length > 0 || media.lyricLoadi const { isFullscreen, toggleFullscreen } = useWindowControls(); /** 封面是否居中 */ -const coverCentered = computed( - () => !showLyric.value || (settings.player.autoCenterCover && !hasLyric.value), -); +const coverCentered = computed(() => { + if (status.fullQueueOpen) return false; + return !showLyric.value || (settings.player.autoCenterCover && !hasLyric.value); +}); /** 弹簧配置 */ const springConfig = computed(() => ({ @@ -191,6 +192,16 @@ const advanceLyric = (): void => writeOffset(songOffset.value + LYRIC_OFFSET_STE const delayLyric = (): void => writeOffset(songOffset.value - LYRIC_OFFSET_STEP); /** 重置歌词偏移 */ const resetLyricOffset = (): void => writeOffset(0); + +/** 切换歌词展示 */ +const toggleLyric = (): void => { + if (status.fullQueueOpen) { + status.fullQueueOpen = false; + showLyric.value = true; + } else { + showLyric.value = !showLyric.value; + } +}; diff --git a/src/stores/status.ts b/src/stores/status.ts index 26e7c5f6..03979da8 100644 --- a/src/stores/status.ts +++ b/src/stores/status.ts @@ -25,8 +25,10 @@ export const useStatusStore = defineStore( const trackLoading = ref(false); /** 菜单折叠状态 */ const isExpanded = ref(false); - /** 播放列表状态 */ - const playlistOpen = ref(false); + /** 外层播放队列 */ + const outerQueueOpen = ref(false); + /** 播放器播放队列 */ + const fullQueueOpen = ref(false); /** 搜索弹窗状态 */ const searchOpen = ref(false); /** 全屏播放器是否展示歌词 */ @@ -97,7 +99,8 @@ export const useStatusStore = defineStore( progress, trackLoading, isExpanded, - playlistOpen, + outerQueueOpen, + fullQueueOpen, searchOpen, showLyric, outputDevices, From f25cfb59d0a1fa10e14810d601c53e7602a8f0c7 Mon Sep 17 00:00:00 2001 From: imsyy Date: Tue, 26 May 2026 23:29:09 +0800 Subject: [PATCH 02/10] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E9=83=A8?= =?UTF-8?q?=E5=88=86=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components.d.ts | 2 + src/components/player/FullPlayer/index.vue | 32 ++++++++++++++- src/components/player/PlayerBar.vue | 47 ++++++++++++++++++++++ src/components/player/QualityControl.vue | 28 ++++++++----- src/components/player/TrackInfo.vue | 4 +- src/components/ui/SCombobox.vue | 1 + src/components/ui/SContextMenu.vue | 2 + src/components/ui/SDropdownMenu.vue | 2 + src/components/ui/SPopover.vue | 1 + src/components/ui/SPopselect.vue | 1 + src/components/ui/SSelect.vue | 1 + src/components/ui/STooltip.vue | 1 + src/composables/useTrackMenu.ts | 19 +++++++-- src/i18n/locales/en-US.json | 1 + src/i18n/locales/zh-CN.json | 1 + 15 files changed, 124 insertions(+), 19 deletions(-) diff --git a/components.d.ts b/components.d.ts index f3a9f337..8ba7031e 100644 --- a/components.d.ts +++ b/components.d.ts @@ -108,6 +108,8 @@ declare module 'vue' { IconLucideMicVocal: typeof import('~icons/lucide/mic-vocal')['default'] IconLucideMinimize: typeof import('~icons/lucide/minimize')['default'] IconLucideMinus: typeof import('~icons/lucide/minus')['default'] + IconLucideMoreHorizontal: typeof import('~icons/lucide/more-horizontal')['default'] + IconLucideMoreVertical: typeof import('~icons/lucide/more-vertical')['default'] IconLucideMusic: typeof import('~icons/lucide/music')['default'] IconLucidePause: typeof import('~icons/lucide/pause')['default'] IconLucidePlay: typeof import('~icons/lucide/play')['default'] diff --git a/src/components/player/FullPlayer/index.vue b/src/components/player/FullPlayer/index.vue index 77b65a63..d1bb1c1a 100644 --- a/src/components/player/FullPlayer/index.vue +++ b/src/components/player/FullPlayer/index.vue @@ -1,16 +1,20 @@ + + + @@ -100,6 +133,19 @@ const onSeekDragEnd = (value: number): void => { + + + @@ -111,4 +157,5 @@ const onSeekDragEnd = (value: number): void => { + diff --git a/src/components/player/QualityControl.vue b/src/components/player/QualityControl.vue index 390e0fae..263821e2 100644 --- a/src/components/player/QualityControl.vue +++ b/src/components/player/QualityControl.vue @@ -13,7 +13,7 @@ const media = useMediaStore(); const settings = useSettingsStore(); /** 是否支持切换在线音质 */ -const isNetease = computed(() => media.track?.source === "netease"); +const canSwitchQuality = computed(() => media.track?.source === "netease" && !media.track?.cloud); /** 实际播放音质 */ const qualityLabel = computed(() => getQualityLabel(media.detail?.quality)); @@ -39,7 +39,7 @@ const onQualityChange = (value: string | number | boolean): void => { - - {{ qualityLabel }} - + + {{ qualityLabel }} + + diff --git a/src/components/player/TrackInfo.vue b/src/components/player/TrackInfo.vue index d73d7499..929f0a2f 100644 --- a/src/components/player/TrackInfo.vue +++ b/src/components/player/TrackInfo.vue @@ -52,10 +52,10 @@ const isArtistLinkable = (artist: Artist): boolean => { /> - +
-
+
{ diff --git a/src/components/ui/SContextMenu.vue b/src/components/ui/SContextMenu.vue index da43bbe9..72fd0d38 100644 --- a/src/components/ui/SContextMenu.vue +++ b/src/components/ui/SContextMenu.vue @@ -46,6 +46,7 @@ const menuItemClass = @@ -63,6 +64,7 @@ const menuItemClass =