diff --git a/electron/lyric.js b/electron/lyric.js
index 5171324..0815cc9 100644
--- a/electron/lyric.js
+++ b/electron/lyric.js
@@ -1,17 +1,19 @@
-const { BrowserWindow } = require('electron');
+const { BrowserWindow, screen } = require('electron');
const path = require('path');
const config = require('./config');
let lyricWindow = null;
+let isDragging = false;
const createWin = () => {
lyricWindow = new BrowserWindow({
width: 800,
- height: 300,
+ height: 200,
frame: false,
show: false,
transparent: true,
hasShadow: false,
+ alwaysOnTop: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
@@ -68,6 +70,44 @@ const loadLyricWindow = (ipcMain) => {
ipcMain.on('mouseleave-lyric', () => {
lyricWindow.setIgnoreMouseEvents(false);
});
+
+ // 开始拖动
+ ipcMain.on('lyric-drag-start', () => {
+ isDragging = true;
+ });
+
+ // 处理拖动移动
+ ipcMain.on('lyric-drag-move', (e, { deltaX, deltaY }) => {
+ if (!lyricWindow) return;
+
+ const [currentX, currentY] = lyricWindow.getPosition();
+ const { width: screenWidth, height: screenHeight } = screen.getPrimaryDisplay().workAreaSize;
+ const [windowWidth, windowHeight] = lyricWindow.getSize();
+
+ // 计算新位置,确保窗口不会移出屏幕
+ const newX = Math.max(0, Math.min(currentX + deltaX, screenWidth - windowWidth));
+ const newY = Math.max(0, Math.min(currentY + deltaY, screenHeight - windowHeight));
+
+ lyricWindow.setPosition(newX, newY);
+ });
+
+ // 结束拖动
+ ipcMain.on('lyric-drag-end', () => {
+ isDragging = false;
+ });
+
+ // 添加鼠标穿透事件处理
+ ipcMain.on('set-ignore-mouse', (e, shouldIgnore) => {
+ if (!lyricWindow) return;
+
+ if (shouldIgnore) {
+ // 设置鼠标穿透,但保留拖动区域可交互
+ lyricWindow.setIgnoreMouseEvents(true, { forward: true });
+ } else {
+ // 取消鼠标穿透
+ lyricWindow.setIgnoreMouseEvents(false);
+ }
+ });
};
module.exports = {
diff --git a/src/hooks/MusicHook.ts b/src/hooks/MusicHook.ts
index f3b56fb..652719a 100644
--- a/src/hooks/MusicHook.ts
+++ b/src/hooks/MusicHook.ts
@@ -92,7 +92,13 @@ export const audioServiceOn = (audio: typeof audioService) => {
// 监听结束
audio.onEnd(() => {
handleEnded();
- store.commit('nextPlay');
+ if (store.state.playMode === 1) {
+ // 单曲循环模式
+ audio.getCurrentSound()?.play();
+ } else {
+ // 列表循环模式
+ store.commit('nextPlay');
+ }
});
};
diff --git a/src/index.css b/src/index.css
index 612605c..22c36a1 100644
--- a/src/index.css
+++ b/src/index.css
@@ -10,6 +10,10 @@
width: 100%;
}
+.n-slider-handle-indicator--top {
+ @apply bg-transparent text-[#ffffffdd] text-2xl px-2 py-1 shadow-none mb-0 !important;
+}
+
.text-el {
@apply overflow-ellipsis overflow-hidden whitespace-nowrap;
}
diff --git a/src/layout/components/PlayBar.vue b/src/layout/components/PlayBar.vue
index 9120b02..e90973c 100644
--- a/src/layout/components/PlayBar.vue
+++ b/src/layout/components/PlayBar.vue
@@ -2,10 +2,14 @@
+
+
+
+
@@ -38,23 +42,26 @@
-
-
-
{{ getNowTime }}
-
-
{{ getAllTime }}
-
-
@@ -84,6 +86,8 @@ const isInitialized = ref(false);
// 字体大小控制
const fontSize = ref(24); // 默认字体大小
const fontSizeStep = 2; // 每次整的步长
+const animationFrameId = ref
(null);
+const lastUpdateTime = ref(performance.now());
// 静态数据
const staticData = ref<{
@@ -136,14 +140,21 @@ const clearHideTimer = () => {
// 处理鼠标进入窗口
const handleMouseEnter = () => {
- if (!lyricSetting.value.isLock) return;
- isHovering.value = true;
+ console.log('handleMouseEnter');
+ if (lyricSetting.value.isLock) {
+ isHovering.value = true;
+ windowData.electron.ipcRenderer.send('set-ignore-mouse', true);
+ } else {
+ windowData.electron.ipcRenderer.send('set-ignore-mouse', false);
+ }
};
// 处理鼠标离开窗口
const handleMouseLeave = () => {
+ console.log('handleMouseLeave');
if (!lyricSetting.value.isLock) return;
isHovering.value = false;
+ windowData.electron.ipcRenderer.send('set-ignore-mouse', false);
};
// 监听锁定状态变化
@@ -180,7 +191,7 @@ const wrapperStyle = computed(() => {
const containerCenter = containerHeight.value / 2;
// 计算当前行到顶部的距离(包含padding)
- const currentLineTop = currentIndex.value * lineHeight.value + containerHeight.value * 0.2; // 加上顶部padding
+ const currentLineTop = currentIndex.value * lineHeight.value + containerHeight.value * 0.2 + lineHeight.value; // 加上顶部padding
// 计算偏移量,使当前行居中
const targetOffset = containerCenter - currentLineTop;
@@ -265,10 +276,6 @@ onMounted(() => {
resizeObserver.disconnect();
});
});
-
-// 动画帧ID
-const animationFrameId = ref(null);
-
// 实际播放时间
const actualTime = ref(0);
@@ -317,9 +324,8 @@ const updateProgress = () => {
};
// 记录上次更新时间
-const lastUpdateTime = ref(performance.now());
-// 监听数据更新
+// 监听据更新
watch(
() => dynamicData.value,
(newData: any) => {
@@ -351,7 +357,7 @@ watch(
},
);
-// 修改数据更新处理
+// 修改数据更新处
const handleDataUpdate = (parsedData: {
nowTime: number;
startCurrentTime: number;
@@ -405,7 +411,7 @@ onMounted(() => {
animationFrameId.value = null;
}
- // 保据格式正确
+ // 确保数据格式正确
if (Array.isArray(parsedData.lrcArray)) {
staticData.value = {
lrcArray: parsedData.lrcArray,
@@ -446,6 +452,7 @@ const handleTop = () => {
const handleLock = () => {
lyricSetting.value.isLock = !lyricSetting.value.isLock;
+ windowData.electron.ipcRenderer.send('set-ignore-mouse', lyricSetting.value.isLock);
};
const handleClose = () => {
@@ -459,6 +466,74 @@ watch(
},
{ deep: true },
);
+
+// 添加拖动相关变量
+const isDragging = ref(false);
+const startPosition = ref({ x: 0, y: 0 });
+
+// 处理鼠标按下事件
+const handleMouseDown = (e: MouseEvent) => {
+ // 如果点击的是控制按钮区域或窗口被锁定,不处理拖动
+ if (
+ lyricSetting.value.isLock ||
+ (e.target as HTMLElement).closest('.control-buttons') ||
+ (e.target as HTMLElement).closest('.font-size-controls')
+ ) {
+ return;
+ }
+
+ // 只响应鼠标左键
+ if (e.button !== 0) return;
+
+ isDragging.value = true;
+ startPosition.value = { x: e.screenX, y: e.screenY };
+
+ // 添加全局鼠标事件监听
+ const handleMouseMove = (e: MouseEvent) => {
+ if (!isDragging.value) return;
+
+ const deltaX = e.screenX - startPosition.value.x;
+ const deltaY = e.screenY - startPosition.value.y;
+
+ // 发送移动事件到主进程
+ windowData.electron.ipcRenderer.send('lyric-drag-move', { deltaX, deltaY });
+ startPosition.value = { x: e.screenX, y: e.screenY };
+ };
+
+ const handleMouseUp = () => {
+ if (!isDragging.value) return;
+ isDragging.value = false;
+
+ // 移除事件监听
+ document.removeEventListener('mousemove', handleMouseMove);
+ document.removeEventListener('mouseup', handleMouseUp);
+ };
+
+ // 添加全局事件监听
+ document.addEventListener('mousemove', handleMouseMove);
+ document.addEventListener('mouseup', handleMouseUp);
+};
+
+// 组件卸载时清理
+onUnmounted(() => {
+ isDragging.value = false;
+});
+
+onMounted(() => {
+ const lyricLock = document.getElementById('lyric-lock');
+ if (lyricLock) {
+ lyricLock.onmouseenter = () => {
+ if (lyricSetting.value.isLock) {
+ windowData.electron.ipcRenderer.send('set-ignore-mouse', false);
+ }
+ };
+ lyricLock.onmouseleave = () => {
+ if (lyricSetting.value.isLock) {
+ windowData.electron.ipcRenderer.send('set-ignore-mouse', true);
+ }
+ };
+ }
+});
diff --git a/tailwind.config.js b/tailwind.config.js
index 82cd6a0..5894c6c 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,8 +1,14 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
- content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
+ content: ['./src/**/*.{vue,js,ts,jsx,tsx}'],
theme: {
- extend: {},
+ extend: {
+ colors: {
+ highlight: 'var(--highlight-color)',
+ text: 'var(--text-color)',
+ secondary: 'var(--text-secondary)',
+ },
+ },
},
plugins: [],
};