feat: 优化桌面歌词添加歌曲控制 上一首下一首 播放暂停

This commit is contained in:
alger
2024-12-16 22:12:28 +08:00
parent e1557a51a3
commit 85bd0ad015
5 changed files with 229 additions and 147 deletions
+1 -1
View File
@@ -66,7 +66,7 @@ function createWindow() {
store.set('set', setJson); store.set('set', setJson);
} }
loadLyricWindow(ipcMain); loadLyricWindow(ipcMain, mainWin);
} }
// 限制只能启动一个应用 // 限制只能启动一个应用
+40 -21
View File
@@ -1,11 +1,11 @@
const { BrowserWindow, screen } = require('electron'); const { BrowserWindow, screen, ipcRenderer } = require('electron');
const path = require('path'); const path = require('path');
const config = require('./config'); const config = require('./config');
let lyricWindow = null; let lyricWindow = null;
let isDragging = false;
const createWin = () => { const createWin = () => {
console.log('Creating lyric window');
lyricWindow = new BrowserWindow({ lyricWindow = new BrowserWindow({
width: 800, width: 800,
height: 200, height: 200,
@@ -21,16 +21,26 @@ const createWin = () => {
webSecurity: false, webSecurity: false,
}, },
}); });
// 监听窗口关闭事件
lyricWindow.on('closed', () => {
console.log('Lyric window closed');
lyricWindow = null;
});
}; };
const loadLyricWindow = (ipcMain) => { const loadLyricWindow = (ipcMain, mainWin) => {
ipcMain.on('open-lyric', () => { ipcMain.on('open-lyric', () => {
console.log('Received open-lyric request');
if (lyricWindow) { if (lyricWindow) {
console.log('Lyric window exists, focusing');
if (lyricWindow.isMinimized()) lyricWindow.restore(); if (lyricWindow.isMinimized()) lyricWindow.restore();
lyricWindow.focus(); lyricWindow.focus();
lyricWindow.show(); lyricWindow.show();
return; return;
} }
console.log('Creating new lyric window');
createWin(); createWin();
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
lyricWindow.webContents.openDevTools({ mode: 'detach' }); lyricWindow.webContents.openDevTools({ mode: 'detach' });
@@ -41,26 +51,39 @@ const loadLyricWindow = (ipcMain) => {
} }
lyricWindow.setMinimumSize(600, 200); lyricWindow.setMinimumSize(600, 200);
// 隐藏任务栏
lyricWindow.setSkipTaskbar(true); lyricWindow.setSkipTaskbar(true);
lyricWindow.show(); lyricWindow.once('ready-to-show', () => {
console.log('Lyric window ready to show');
lyricWindow.show();
});
}); });
ipcMain.on('send-lyric', (e, data) => { ipcMain.on('send-lyric', (e, data) => {
if (lyricWindow) { if (lyricWindow && !lyricWindow.isDestroyed()) {
lyricWindow.webContents.send('receive-lyric', data); try {
lyricWindow.webContents.send('receive-lyric', data);
} catch (error) {
console.error('Error processing lyric data:', error);
}
} else {
console.log('Cannot send lyric: window not available or destroyed');
} }
}); });
ipcMain.on('top-lyric', (e, data) => { ipcMain.on('top-lyric', (e, data) => {
lyricWindow.setAlwaysOnTop(data); if (lyricWindow && !lyricWindow.isDestroyed()) {
lyricWindow.setAlwaysOnTop(data);
}
}); });
ipcMain.on('close-lyric', () => { ipcMain.on('close-lyric', () => {
lyricWindow.close(); if (lyricWindow && !lyricWindow.isDestroyed()) {
lyricWindow = null; lyricWindow.webContents.send('lyric-window-close');
mainWin.webContents.send('lyric-control-back', 'close');
lyricWindow.close();
lyricWindow = null;
}
}); });
ipcMain.on('mouseenter-lyric', () => { ipcMain.on('mouseenter-lyric', () => {
@@ -71,11 +94,6 @@ const loadLyricWindow = (ipcMain) => {
lyricWindow.setIgnoreMouseEvents(false); lyricWindow.setIgnoreMouseEvents(false);
}); });
// 开始拖动
ipcMain.on('lyric-drag-start', () => {
isDragging = true;
});
// 处理拖动移动 // 处理拖动移动
ipcMain.on('lyric-drag-move', (e, { deltaX, deltaY }) => { ipcMain.on('lyric-drag-move', (e, { deltaX, deltaY }) => {
if (!lyricWindow) return; if (!lyricWindow) return;
@@ -91,11 +109,6 @@ const loadLyricWindow = (ipcMain) => {
lyricWindow.setPosition(newX, newY); lyricWindow.setPosition(newX, newY);
}); });
// 结束拖动
ipcMain.on('lyric-drag-end', () => {
isDragging = false;
});
// 添加鼠标穿透事件处理 // 添加鼠标穿透事件处理
ipcMain.on('set-ignore-mouse', (e, shouldIgnore) => { ipcMain.on('set-ignore-mouse', (e, shouldIgnore) => {
if (!lyricWindow) return; if (!lyricWindow) return;
@@ -108,6 +121,12 @@ const loadLyricWindow = (ipcMain) => {
lyricWindow.setIgnoreMouseEvents(false); lyricWindow.setIgnoreMouseEvents(false);
} }
}); });
// 添加播放控制处理
ipcMain.on('control-back', (e, command) => {
console.log('Received control-back request:', command);
mainWin.webContents.send('lyric-control-back', command);
});
}; };
module.exports = { module.exports = {
+76 -59
View File
@@ -17,6 +17,7 @@ export const correctionTime = ref(0.4); // 歌词矫正时间Correction time
export const currentLrcProgress = ref(0); // 来存储当前歌词的进度 export const currentLrcProgress = ref(0); // 来存储当前歌词的进度
export const playMusic = computed(() => store.state.playMusic as SongResult); // 当前播放歌曲 export const playMusic = computed(() => store.state.playMusic as SongResult); // 当前播放歌曲
export const sound = ref<Howl | null>(audioService.getCurrentSound()); export const sound = ref<Howl | null>(audioService.getCurrentSound());
export const isLyricWindowOpen = ref(false); // 新增状态
document.onkeyup = (e) => { document.onkeyup = (e) => {
// 检查事件目标是否是输入框元素 // 检查事件目标是否是输入框元素
@@ -53,13 +54,18 @@ watch(
watch( watch(
() => store.state.playMusic, () => store.state.playMusic,
() => { () => {
nextTick(() => { nextTick(async () => {
lrcArray.value = playMusic.value.lyric?.lrcArray || []; lrcArray.value = playMusic.value.lyric?.lrcArray || [];
lrcTimeArray.value = playMusic.value.lyric?.lrcTimeArray || []; lrcTimeArray.value = playMusic.value.lyric?.lrcTimeArray || [];
// 当歌词数据更新时,如果歌词窗口打开,则发送数据
if (isElectron.value && isLyricWindowOpen.value && lrcArray.value.length > 0) {
sendLyricToWin();
}
}); });
}, },
{ {
deep: true, deep: true,
immediate: true,
}, },
); );
@@ -76,8 +82,13 @@ export const audioServiceOn = (audio: typeof audioService) => {
if (newIndex !== nowIndex.value) { if (newIndex !== nowIndex.value) {
nowIndex.value = newIndex; nowIndex.value = newIndex;
currentLrcProgress.value = 0; currentLrcProgress.value = 0;
// 当歌词索引更新时,发送歌词数据
if (isElectron.value && isLyricWindowOpen.value) {
sendLyricToWin();
}
} }
if (isElectron.value) { // 定期发送歌词数据更新
if (isElectron.value && isLyricWindowOpen.value) {
sendLyricToWin(); sendLyricToWin();
} }
}, 50); }, 50);
@@ -87,11 +98,14 @@ export const audioServiceOn = (audio: typeof audioService) => {
audio.onPause(() => { audio.onPause(() => {
store.commit('setPlayMusic', false); store.commit('setPlayMusic', false);
clearInterval(interval); clearInterval(interval);
// 暂停时也发送一次状态更新
if (isElectron.value && isLyricWindowOpen.value) {
sendLyricToWin();
}
}); });
// 监听结束 // 监听结束
audio.onEnd(() => { audio.onEnd(() => {
handleEnded();
if (store.state.playMode === 1) { if (store.state.playMode === 1) {
// 单曲循环模式 // 单曲循环模式
audio.getCurrentSound()?.play(); audio.getCurrentSound()?.play();
@@ -213,7 +227,7 @@ export const useLyricProgress = () => {
}; };
}; };
// 设置前播放时间 // 设置前播放时间
export const setAudioTime = (index: number) => { export const setAudioTime = (index: number) => {
const currentSound = sound.value; const currentSound = sound.value;
if (!currentSound) return; if (!currentSound) return;
@@ -241,72 +255,33 @@ export const getLrcTimeRange = (index: number) => ({
watch( watch(
() => lrcArray.value, () => lrcArray.value,
(newLrcArray) => { (newLrcArray) => {
if (newLrcArray.length > 0 && isElectron.value) { if (newLrcArray.length > 0 && isElectron.value && isLyricWindowOpen.value) {
// 重新初始化歌词数据
initLyricWindow();
// 发送当前状态
sendLyricToWin(); sendLyricToWin();
} }
}, },
); );
// 监听播放状态变化
watch(isPlaying, (newIsPlaying) => {
if (isElectron.value) {
sendLyricToWin(newIsPlaying);
}
});
// 处理歌曲结束
export const handleEnded = () => {
if (isElectron.value) {
setTimeout(() => {
initLyricWindow();
sendLyricToWin();
}, 100);
}
};
// 初始化歌词数据
export const initLyricWindow = () => {
if (!isElectron.value) return;
try {
if (lrcArray.value.length > 0) {
console.log('Initializing lyric window with data:', {
lrcArray: lrcArray.value,
lrcTimeArray: lrcTimeArray.value,
allTime: allTime.value,
});
const staticData = {
type: 'init',
lrcArray: lrcArray.value,
lrcTimeArray: lrcTimeArray.value,
allTime: allTime.value,
};
windowData.electronAPI.sendLyric(JSON.stringify(staticData));
} else {
console.log('No lyrics available for initialization');
}
} catch (error) {
console.error('Error initializing lyric window:', error);
}
};
// 发送歌词更新数据 // 发送歌词更新数据
export const sendLyricToWin = (isPlay: boolean = true) => { export const sendLyricToWin = () => {
if (!isElectron.value) return; if (!isElectron.value || !isLyricWindowOpen.value) {
console.log('Cannot send lyric: electron or lyric window not available');
return;
}
try { try {
if (lrcArray.value.length > 0) { if (lrcArray.value.length > 0) {
const nowIndex = getLrcIndex(nowTime.value); const nowIndex = getLrcIndex(nowTime.value);
const updateData = { const updateData = {
type: 'update', type: 'full',
nowIndex, nowIndex,
nowTime: nowTime.value, nowTime: nowTime.value,
startCurrentTime: lrcTimeArray.value[nowIndex], startCurrentTime: lrcTimeArray.value[nowIndex],
nextTime: lrcTimeArray.value[nowIndex + 1], nextTime: lrcTimeArray.value[nowIndex + 1],
isPlay, isPlay: isPlaying.value,
lrcArray: lrcArray.value,
lrcTimeArray: lrcTimeArray.value,
allTime: allTime.value,
playMusic: playMusic.value,
}; };
windowData.electronAPI.sendLyric(JSON.stringify(updateData)); windowData.electronAPI.sendLyric(JSON.stringify(updateData));
} }
@@ -317,13 +292,55 @@ export const sendLyricToWin = (isPlay: boolean = true) => {
export const openLyric = () => { export const openLyric = () => {
if (!isElectron.value) return; if (!isElectron.value) return;
console.log('Opening lyric window'); console.log('Opening lyric window with current song:', playMusic.value?.name);
windowData.electronAPI.openLyric(); windowData.electronAPI.openLyric();
isLyricWindowOpen.value = true;
// 延迟一下初始化,确保窗口已经创建 // 延迟一下初始化,确保窗口已经创建
setTimeout(() => { setTimeout(() => {
console.log('Initializing lyric window after delay'); if (isLyricWindowOpen.value) {
initLyricWindow(); console.log('Initializing lyric window with data:', {
sendLyricToWin(); hasLyrics: lrcArray.value.length > 0,
songName: playMusic.value?.name,
});
sendLyricToWin();
}
}, 500); }, 500);
}; };
// 添加关闭歌词窗口的方法
export const closeLyric = () => {
if (!isElectron.value) return;
isLyricWindowOpen.value = false;
windowData.electron.ipcRenderer.send('close-lyric');
};
// 添加播放控制命令监听
if (isElectron.value) {
windowData.electron.ipcRenderer.on('lyric-control-back', (command: string) => {
console.log('Received playback control command:', command);
switch (command) {
case 'playpause':
if (store.state.play) {
store.commit('setPlayMusic', false);
audioService.getCurrentSound()?.pause();
} else {
store.commit('setPlayMusic', true);
audioService.getCurrentSound()?.play();
}
break;
case 'prev':
store.commit('prevPlay');
break;
case 'next':
store.commit('nextPlay');
break;
case 'close':
closeLyric();
break;
default:
console.log('Unknown command:', command);
break;
}
});
}
+10 -2
View File
@@ -69,7 +69,11 @@
</n-tooltip> </n-tooltip>
<n-tooltip v-if="isElectron" class="music-lyric" trigger="hover" :z-index="9999999"> <n-tooltip v-if="isElectron" class="music-lyric" trigger="hover" :z-index="9999999">
<template #trigger> <template #trigger>
<i class="iconfont ri-netease-cloud-music-line" @click="openLyric"></i> <i
class="iconfont ri-netease-cloud-music-line"
:class="{ 'text-green-500': isLyricWindowOpen }"
@click="openLyricWindow"
></i>
</template> </template>
歌词 歌词
</n-tooltip> </n-tooltip>
@@ -113,7 +117,7 @@ import { useTemplateRef } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
import SongItem from '@/components/common/SongItem.vue'; import SongItem from '@/components/common/SongItem.vue';
import { allTime, isElectron, nowTime, openLyric, sound } from '@/hooks/MusicHook'; import { allTime, isElectron, isLyricWindowOpen, nowTime, openLyric, sound } from '@/hooks/MusicHook';
import type { SongResult } from '@/type/music'; import type { SongResult } from '@/type/music';
import { getImgUrl, secondToMinute, setAnimationClass } from '@/utils'; import { getImgUrl, secondToMinute, setAnimationClass } from '@/utils';
@@ -253,6 +257,10 @@ const toggleFavorite = async (e: Event) => {
store.commit('addToFavorite', playMusic.value.id); store.commit('addToFavorite', playMusic.value.id);
} }
}; };
const openLyricWindow = () => {
openLyric();
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
+102 -64
View File
@@ -18,15 +18,28 @@
<i class="ri-add-line"></i> <i class="ri-add-line"></i>
</n-button> </n-button>
</n-button-group> </n-button-group>
<div>{{ staticData.playMusic.name }}</div>
</div>
<!-- 添加播放控制按钮 -->
<div class="play-controls">
<div class="control-button" @click="handlePrev">
<i class="ri-skip-back-fill"></i>
</div>
<div class="control-button play-button" @click="handlePlayPause">
<i :class="dynamicData.isPlay ? 'ri-pause-fill' : 'ri-play-fill'"></i>
</div>
<div class="control-button" @click="handleNext">
<i class="ri-skip-forward-fill"></i>
</div>
</div> </div>
<div class="control-buttons"> <div class="control-buttons">
<div class="control-button" @click="checkTheme"> <div class="control-button" @click="checkTheme">
<i v-if="lyricSetting.theme === 'light'" class="ri-sun-line"></i> <i v-if="lyricSetting.theme === 'light'" class="ri-sun-line"></i>
<i v-else class="ri-moon-line"></i> <i v-else class="ri-moon-line"></i>
</div> </div>
<div class="control-button" @click="handleTop"> <!-- <div class="control-button" @click="handleTop">
<i class="ri-pushpin-line" :class="{ active: lyricSetting.isTop }"></i> <i class="ri-pushpin-line" :class="{ active: lyricSetting.isTop }"></i>
</div> </div> -->
<div id="lyric-lock" class="control-button" @click="handleLock"> <div id="lyric-lock" class="control-button" @click="handleLock">
<i v-if="lyricSetting.isLock" class="ri-lock-line"></i> <i v-if="lyricSetting.isLock" class="ri-lock-line"></i>
<i v-else class="ri-lock-unlock-line"></i> <i v-else class="ri-lock-unlock-line"></i>
@@ -46,7 +59,10 @@
v-for="(line, index) in staticData.lrcArray" v-for="(line, index) in staticData.lrcArray"
:key="index" :key="index"
class="lyric-line" class="lyric-line"
:style="lyricLineStyle" :style="{
...lyricLineStyle,
display: line.text ? 'flex' : 'none',
}"
:class="{ :class="{
'lyric-line-current': index === currentIndex, 'lyric-line-current': index === currentIndex,
'lyric-line-passed': index < currentIndex, 'lyric-line-passed': index < currentIndex,
@@ -71,18 +87,18 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'; import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import { SongResult } from '@/type/music';
defineOptions({ defineOptions({
name: 'Lyric', name: 'Lyric',
}); });
const windowData = window as any; const windowData = window as any;
const containerRef = ref<HTMLElement | null>(null); const containerRef = ref<HTMLElement | null>(null);
const containerHeight = ref(0); const containerHeight = ref(0);
const lineHeight = ref(60); const lineHeight = ref(60);
const currentIndex = ref(0); const currentIndex = ref(0);
const isInitialized = ref(false);
// 字体大小控制 // 字体大小控制
const fontSize = ref(24); // 默认字体大小 const fontSize = ref(24); // 默认字体大小
const fontSizeStep = 2; // 每次整的步长 const fontSizeStep = 2; // 每次整的步长
@@ -94,10 +110,12 @@ const staticData = ref<{
lrcArray: Array<{ text: string; trText: string }>; lrcArray: Array<{ text: string; trText: string }>;
lrcTimeArray: number[]; lrcTimeArray: number[];
allTime: number; allTime: number;
playMusic: SongResult;
}>({ }>({
lrcArray: [], lrcArray: [],
lrcTimeArray: [], lrcTimeArray: [],
allTime: 0, allTime: 0,
playMusic: {} as SongResult,
}); });
// 动态数据 // 动态数据
@@ -140,7 +158,6 @@ const clearHideTimer = () => {
// 处理鼠标进入窗口 // 处理鼠标进入窗口
const handleMouseEnter = () => { const handleMouseEnter = () => {
console.log('handleMouseEnter');
if (lyricSetting.value.isLock) { if (lyricSetting.value.isLock) {
isHovering.value = true; isHovering.value = true;
windowData.electron.ipcRenderer.send('set-ignore-mouse', true); windowData.electron.ipcRenderer.send('set-ignore-mouse', true);
@@ -151,7 +168,6 @@ const handleMouseEnter = () => {
// 处理鼠标离开窗口 // 处理鼠标离开窗口
const handleMouseLeave = () => { const handleMouseLeave = () => {
console.log('handleMouseLeave');
if (!lyricSetting.value.isLock) return; if (!lyricSetting.value.isLock) return;
isHovering.value = false; isHovering.value = false;
windowData.electron.ipcRenderer.send('set-ignore-mouse', false); windowData.electron.ipcRenderer.send('set-ignore-mouse', false);
@@ -180,7 +196,7 @@ onUnmounted(() => {
// 计算歌词滚动位置 // 计算歌词滚动位置
const wrapperStyle = computed(() => { const wrapperStyle = computed(() => {
if (!isInitialized.value || !containerHeight.value) { if (!containerHeight.value) {
return { return {
transform: 'translateY(0)', transform: 'translateY(0)',
transition: 'none', transition: 'none',
@@ -208,7 +224,7 @@ const wrapperStyle = computed(() => {
return { return {
transform: `translateY(${finalOffset}px)`, transform: `translateY(${finalOffset}px)`,
transition: isInitialized.value ? 'transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)' : 'none', transition: 'transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
}; };
}); });
@@ -281,8 +297,8 @@ const actualTime = ref(0);
// 计算当前行的进度 // 计算当前行的进度
const currentProgress = computed(() => { const currentProgress = computed(() => {
const { startCurrentTime, nextTime, isPlay } = dynamicData.value; const { startCurrentTime, nextTime } = dynamicData.value;
if (!startCurrentTime || !nextTime || !isPlay) return 0; if (!startCurrentTime || !nextTime) return 0;
const duration = nextTime - startCurrentTime; const duration = nextTime - startCurrentTime;
const elapsed = actualTime.value - startCurrentTime; const elapsed = actualTime.value - startCurrentTime;
@@ -364,22 +380,34 @@ const handleDataUpdate = (parsedData: {
nextTime: number; nextTime: number;
isPlay: boolean; isPlay: boolean;
nowIndex: number; nowIndex: number;
lrcArray: Array<{ text: string; trText: string }>;
lrcTimeArray: number[];
allTime: number;
playMusic: SongResult;
}) => { }) => {
// 确保数据存在且格式正确 // 确保数据存在且格式正确
if (!parsedData || typeof parsedData.nowTime !== 'number') { if (!parsedData) {
console.error('Invalid update data received:', parsedData); console.error('Invalid update data received:', parsedData);
return; return;
} }
// 更新静态数据
staticData.value = {
lrcArray: parsedData.lrcArray || [],
lrcTimeArray: parsedData.lrcTimeArray || [],
allTime: parsedData.allTime || 0,
playMusic: parsedData.playMusic || {},
};
// 更新动态数据
dynamicData.value = { dynamicData.value = {
nowTime: parsedData.nowTime, nowTime: parsedData.nowTime || 0,
startCurrentTime: parsedData.startCurrentTime, startCurrentTime: parsedData.startCurrentTime || 0,
nextTime: parsedData.nextTime, nextTime: parsedData.nextTime || 0,
isPlay: parsedData.isPlay, isPlay: parsedData.isPlay,
}; };
// 更新索引 // 更新索引
if (typeof parsedData.nowIndex === 'number' && parsedData.nowIndex !== currentIndex.value) { if (typeof parsedData.nowIndex === 'number') {
currentIndex.value = parsedData.nowIndex; currentIndex.value = parsedData.nowIndex;
} }
}; };
@@ -400,33 +428,7 @@ onMounted(() => {
windowData.electron.ipcRenderer.on('receive-lyric', (data: string) => { windowData.electron.ipcRenderer.on('receive-lyric', (data: string) => {
try { try {
const parsedData = JSON.parse(data); const parsedData = JSON.parse(data);
if (parsedData.type === 'init') { handleDataUpdate(parsedData);
// 初始化重置状态
currentIndex.value = 0;
isInitialized.value = false;
// 清理可能存在的动画
if (animationFrameId.value) {
cancelAnimationFrame(animationFrameId.value);
animationFrameId.value = null;
}
// 确保数据格式正确
if (Array.isArray(parsedData.lrcArray)) {
staticData.value = {
lrcArray: parsedData.lrcArray,
lrcTimeArray: parsedData.lrcTimeArray || [],
allTime: parsedData.allTime || 0,
};
} else {
console.error('Invalid lyric array format:', parsedData);
}
nextTick(() => {
isInitialized.value = true;
});
} else if (parsedData.type === 'update') {
handleDataUpdate(parsedData);
}
} catch (error) { } catch (error) {
console.error('Error parsing lyric data:', error); console.error('Error parsing lyric data:', error);
} }
@@ -467,7 +469,7 @@ watch(
{ deep: true }, { deep: true },
); );
// 添拖动相关变量 // 添拖动相关变量
const isDragging = ref(false); const isDragging = ref(false);
const startPosition = ref({ x: 0, y: 0 }); const startPosition = ref({ x: 0, y: 0 });
@@ -534,6 +536,19 @@ onMounted(() => {
}; };
} }
}); });
// 添加播放控制相关的函数
const handlePlayPause = () => {
windowData.electron.ipcRenderer.send('control-back', 'playpause');
};
const handlePrev = () => {
windowData.electron.ipcRenderer.send('control-back', 'prev');
};
const handleNext = () => {
windowData.electron.ipcRenderer.send('control-back', 'next');
};
</script> </script>
<style> <style>
@@ -554,7 +569,7 @@ body {
cursor: default; cursor: default;
&:hover { &:hover {
background: rgba(0, 0, 0, 0.3); background: rgba(0, 0, 0, 0.5);
.control-bar { .control-bar {
&-show { &-show {
opacity: 1; opacity: 1;
@@ -571,7 +586,7 @@ body {
--text-color: #ffffff; --text-color: #ffffff;
--text-secondary: rgba(255, 255, 255, 0.6); --text-secondary: rgba(255, 255, 255, 0.6);
--highlight-color: #1db954; --highlight-color: #1db954;
--control-bg: rgba(0, 0, 0, 0.3); --control-bg: rgba(124, 124, 124, 0.3);
} }
&.light { &.light {
@@ -584,13 +599,13 @@ body {
.control-bar { .control-bar {
position: absolute; position: absolute;
top: 0; top: 10px;
left: 0; left: 0;
right: 0; right: 0;
height: 40px; height: 80px;
display: flex; display: flex;
justify-content: flex-end; justify-content: space-between;
align-items: center; align-items: start;
padding: 0 20px; padding: 0 20px;
opacity: 0; opacity: 0;
visibility: hidden; visibility: hidden;
@@ -600,13 +615,28 @@ body {
z-index: 100; z-index: 100;
.font-size-controls { .font-size-controls {
margin-right: auto; // 将字体控制放在侧 -webkit-app-region: no-drag;
padding-right: 20px; color: var(--text-color);
display: flex;
align-items: center;
gap: 16px;
}
.play-controls {
position: absolute;
top: 0px;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
gap: 16px;
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
.n-button { .play-button {
width: 36px;
height: 36px;
i { i {
font-size: 16px; font-size: 24px;
} }
} }
} }
@@ -623,23 +653,21 @@ body {
} }
.control-button { .control-button {
width: 32px; width: 36px;
height: 32px; height: 36px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
cursor: pointer; cursor: pointer;
border-radius: 50%; border-radius: 8px;
color: var(--text-color); color: var(--text-color);
transition: all 0.2s ease; transition: all 0.2s ease;
backdrop-filter: blur(4px);
&:hover { &:hover {
background: var(--control-bg); background: var(--control-bg);
} }
i { i {
font-size: 18px; font-size: 20px;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.3); text-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
&.active { &.active {
@@ -650,7 +678,7 @@ body {
.lyric-container { .lyric-container {
position: absolute; position: absolute;
top: 40px; top: 80px;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
@@ -689,8 +717,7 @@ body {
opacity: 1; opacity: 1;
} }
&.lyric-line-passed, &.lyric-line-passed {
&.lyric-line-next {
opacity: 0.6; opacity: 0.6;
} }
} }
@@ -751,6 +778,10 @@ body {
.lyric_lock & .font-size-controls { .lyric_lock & .font-size-controls {
display: none; display: none;
} }
.lyric_lock & .play-controls {
display: none;
}
} }
.lyric_lock { .lyric_lock {
@@ -758,5 +789,12 @@ body {
&:hover { &:hover {
background: transparent; background: transparent;
} }
#lyric-lock {
position: absolute;
top: 0;
right: 72px;
background: var(--control-bg);
}
} }
</style> </style>