diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index 1b3556d0a..c23b584b5 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -473,6 +473,7 @@
"lyricFetchProvider_description": "select the providers to fetch lyrics from. the order of the providers is the order in which they will be queried",
"lyricOffset": "lyric offset (ms)",
"lyricOffset_description": "offset the lyric by the specified amount of milliseconds",
+ "lyricWdith": "lyric overlay width",
"minimizeToTray": "minimize to tray",
"minimizeToTray_description": "minimize the application to the system tray",
"minimumScrobblePercentage": "minimum scrobble duration (percentage)",
diff --git a/src/renderer/features/lyrics/lyrics-actions.tsx b/src/renderer/features/lyrics/lyrics-actions.tsx
index 3ce52b13e..769dc9e78 100644
--- a/src/renderer/features/lyrics/lyrics-actions.tsx
+++ b/src/renderer/features/lyrics/lyrics-actions.tsx
@@ -1,4 +1,4 @@
-import { Box, Group } from '@mantine/core';
+import { Box, Grid, Group } from '@mantine/core';
import isElectron from 'is-electron';
import { useTranslation } from 'react-i18next';
import { RiAddFill, RiSubtractFill } from 'react-icons/ri';
@@ -6,11 +6,14 @@ import { LyricsOverride } from '/@/renderer/api/types';
import { Button, NumberInput, Tooltip } from '/@/renderer/components';
import { openLyricSearchModal } from '/@/renderer/features/lyrics/components/lyrics-search-form';
import {
+ useAppStoreActions,
useCurrentSong,
useLyricsSettings,
+ useLyricsStore,
useSettingsStore,
useSettingsStoreActions,
} from '/@/renderer/store';
+import { useCallback } from 'react';
interface LyricsActionsProps {
onRemoveLyric: () => void;
@@ -26,7 +29,9 @@ export const LyricsActions = ({
const { t } = useTranslation();
const currentSong = useCurrentSong();
const { setSettings } = useSettingsStoreActions();
+ const { setLyrics } = useAppStoreActions();
const { delayMs, sources } = useLyricsSettings();
+ const { open, width } = useLyricsStore();
const handleLyricOffset = (e: number) => {
setSettings({
@@ -37,79 +42,120 @@ export const LyricsActions = ({
});
};
+ const setWidth = useCallback(
+ (newWidth: number) => {
+ setLyrics({ open, width: newWidth });
+ },
+ [open, setLyrics],
+ );
+
const isActionsDisabled = !currentSong;
const isDesktop = isElectron();
return (
-
+
+ {true && (
+
+
+ setWidth(Number(e.currentTarget.value))}
+ />
+
+
+ )}
{isDesktop && sources.length ? (
-
+
+
+
) : null}
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
{isDesktop && sources.length ? (
-
+
+
+
) : null}
-
-
{isDesktop && sources.length ? (
-
+
+
+
) : null}
-
+
);
};
diff --git a/src/renderer/features/lyrics/synchronized-lyrics.tsx b/src/renderer/features/lyrics/synchronized-lyrics.tsx
index 061d18889..3a5f0db9a 100644
--- a/src/renderer/features/lyrics/synchronized-lyrics.tsx
+++ b/src/renderer/features/lyrics/synchronized-lyrics.tsx
@@ -165,7 +165,12 @@ export const SynchronizedLyrics = ({
currentLyric.classList.add('active');
if (followRef.current) {
- doc?.scroll({ behavior: 'smooth', top: offsetTop });
+ // Have smooth scrolling for line-by-line, instant for large jumps
+ const behavior =
+ Math.abs(doc.scrollTop - offsetTop) > 8 * settings.fontSize
+ ? 'instant'
+ : 'smooth';
+ doc?.scroll({ behavior, top: offsetTop });
}
if (index !== lyricRef.current!.length - 1) {
@@ -178,7 +183,7 @@ export const SynchronizedLyrics = ({
}, nextTime - timeInMs - elapsed);
}
},
- [],
+ [settings.fontSize],
);
useEffect(() => {
diff --git a/src/renderer/layouts/default-layout/lyrics-overlay.tsx b/src/renderer/layouts/default-layout/lyrics-overlay.tsx
index e810fffd9..5c3884d9e 100644
--- a/src/renderer/layouts/default-layout/lyrics-overlay.tsx
+++ b/src/renderer/layouts/default-layout/lyrics-overlay.tsx
@@ -1,5 +1,5 @@
-import { AnimatePresence, Variants, motion, useDragControls } from 'framer-motion';
-import { useMemo, useRef } from 'react';
+import { useMemo, useRef, useState } from 'react';
+import { Variants, motion, useDragControls } from 'framer-motion';
import { Lyrics } from '/@/renderer/features/lyrics/lyrics';
import styled from 'styled-components';
import { Platform } from '/@/renderer/types';
@@ -21,6 +21,9 @@ export const LyricsOverlay = () => {
const dragControls = useDragControls();
const constraintsRef = useRef(null);
const { open, width } = useLyricsStore();
+ const lyricRef = useRef(null);
+
+ const [x, setX] = useState((document.body.clientWidth - width) / 2);
const variants: Variants = useMemo(
() => ({
@@ -29,7 +32,6 @@ export const LyricsOverlay = () => {
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
- left: 'calc(50vw - 225px)',
position: 'absolute',
top: '75px',
transition: {
@@ -37,6 +39,7 @@ export const LyricsOverlay = () => {
ease: 'anticipate',
},
width,
+ x,
}),
open: (windowBarStyle) => ({
boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.8)',
@@ -45,47 +48,45 @@ export const LyricsOverlay = () => {
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
- transition: {
- damping: 10,
- delay: 0,
- duration: 0.4,
- ease: 'anticipate',
- mass: 0.5,
- },
width,
+ x,
zIndex: 121,
}),
}),
- [width],
+ [width, x],
);
return (
-
- {open && (
-
-
-
-
-
- )}
-
+ open && (
+
+ {
+ // bodge to save the current position, so that on resize
+ // window does not snap back to 0
+ setX(lyricRef.current!.getBoundingClientRect().x);
+ }}
+ >
+
+
+
+ )
);
};
diff --git a/src/renderer/store/app.store.ts b/src/renderer/store/app.store.ts
index 428ea50ae..b0c84c343 100644
--- a/src/renderer/store/app.store.ts
+++ b/src/renderer/store/app.store.ts
@@ -93,7 +93,7 @@ export const useAppStore = create()(
isReorderingQueue: false,
lyrics: {
open: false,
- width: 450,
+ width: 525,
},
platform: Platform.WINDOWS,
sidebar: {