diff --git a/src/renderer/features/lyrics/components/lyrics-search-form.module.css b/src/renderer/features/lyrics/components/lyrics-search-form.module.css index 8e8081fc5..d5470d656 100644 --- a/src/renderer/features/lyrics/components/lyrics-search-form.module.css +++ b/src/renderer/features/lyrics/components/lyrics-search-form.module.css @@ -17,3 +17,19 @@ } } } + +.selected { + background-color: alpha(var(--theme-colors-primary), 0.3); + + &:hover, + &:active, + &:focus-visible { + @mixin dark { + background-color: alpha(var(--theme-colors-primary), 0.4); + } + + @mixin light { + background-color: alpha(var(--theme-colors-primary), 0.4); + } + } +} diff --git a/src/renderer/features/lyrics/components/lyrics-search-form.tsx b/src/renderer/features/lyrics/components/lyrics-search-form.tsx index e08ccffd6..b90d0ca3a 100644 --- a/src/renderer/features/lyrics/components/lyrics-search-form.tsx +++ b/src/renderer/features/lyrics/components/lyrics-search-form.tsx @@ -1,13 +1,25 @@ -import { openModal } from '@mantine/modals'; +import { closeAllModals, openModal } from '@mantine/modals'; import { useQuery } from '@tanstack/react-query'; +import clsx from 'clsx'; import orderBy from 'lodash/orderBy'; -import { useMemo } from 'react'; +import { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import styles from './lyrics-search-form.module.css'; import i18n from '/@/i18n/i18n'; import { lyricsQueries } from '/@/renderer/features/lyrics/api/lyrics-api'; +import { + SynchronizedLyrics, + SynchronizedLyricsProps, +} from '/@/renderer/features/lyrics/synchronized-lyrics'; +import { + UnsynchronizedLyrics, + UnsynchronizedLyricsProps, +} from '/@/renderer/features/lyrics/unsynchronized-lyrics'; +import { usePlayerSong } from '/@/renderer/store'; +import { Button } from '/@/shared/components/button/button'; +import { Center } from '/@/shared/components/center/center'; import { Divider } from '/@/shared/components/divider/divider'; import { Group } from '/@/shared/components/group/group'; import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area'; @@ -25,9 +37,10 @@ import { interface SearchResultProps { data: InternetProviderLyricSearchResponse; + isSelected?: boolean; onClick?: () => void; } -const SearchResult = ({ data, onClick }: SearchResultProps) => { +const SearchResult = ({ data, isSelected, onClick }: SearchResultProps) => { const { artist, id, name, score, source } = data; const percentageScore = useMemo(() => { @@ -39,7 +52,12 @@ const SearchResult = ({ data, onClick }: SearchResultProps) => { source === LyricSource.GENIUS ? id.replace(/^((http[s]?|ftp):\/)?\/?([^:/\s]+)/g, '') : id; return ( - + + ); }; @@ -154,7 +250,12 @@ export const openLyricSearchModal = ({ artist, name, onSearchOverride }: LyricSe children: ( ), - size: 'lg', + size: 'xl', + styles: { + body: { + height: '600px', + }, + }, title: i18n.t('form.lyricSearch.title', { postProcess: 'titleCase' }) as string, }); }; diff --git a/src/renderer/features/lyrics/lyrics.tsx b/src/renderer/features/lyrics/lyrics.tsx index f83f83548..dde4bf409 100644 --- a/src/renderer/features/lyrics/lyrics.tsx +++ b/src/renderer/features/lyrics/lyrics.tsx @@ -54,7 +54,34 @@ export const Lyrics = () => { const [override, setOverride] = useState(undefined); + const { data: overrideData, isInitialLoading: isOverrideLoading } = useQuery( + lyricsQueries.songLyricsByRemoteId({ + options: { + enabled: !!override, + }, + query: { + remoteSongId: override?.id, + remoteSource: override?.source as LyricSource | undefined, + song: currentSong, + }, + serverId: currentSong?._serverId || '', + }), + ); + const [lyrics, synced] = useMemo(() => { + // If override data is available, use it + if (override && overrideData) { + const overrideLyrics: FullLyricsMetadata = { + artist: override.artist, + lyrics: overrideData, + name: override.name, + remote: override.remote ?? true, + source: override.source, + }; + return [overrideLyrics, Array.isArray(overrideData)]; + } + + // Otherwise, use the regular data if (Array.isArray(data)) { if (data.length > 0) { const selectedLyric = data[Math.min(index, data.length - 1)]; @@ -65,13 +92,14 @@ export const Lyrics = () => { } return [undefined, false]; - }, [data, index]); + }, [data, index, override, overrideData]); const handleOnSearchOverride = useCallback((params: LyricsOverride) => { setOverride(params); }, []); const handleOnResetLyric = useCallback(() => { + setOverride(undefined); queryClient.invalidateQueries({ exact: true, queryKey: queryKeys.songs.lyrics(currentSong?._serverId, { songId: currentSong?.id }), @@ -117,19 +145,6 @@ export const Lyrics = () => { await fetchTranslation(); }, [translatedLyrics, showTranslation, fetchTranslation]); - const { isInitialLoading: isOverrideLoading } = useQuery( - lyricsQueries.songLyricsByRemoteId({ - options: { - enabled: !!override, - }, - query: { - remoteSongId: override?.id, - remoteSource: override?.source as LyricSource | undefined, - song: currentSong, - }, - serverId: currentSong?._serverId || '', - }), - ); usePlayerEvents( { diff --git a/src/renderer/features/lyrics/synchronized-lyrics.tsx b/src/renderer/features/lyrics/synchronized-lyrics.tsx index 8ffce1f18..13f447bec 100644 --- a/src/renderer/features/lyrics/synchronized-lyrics.tsx +++ b/src/renderer/features/lyrics/synchronized-lyrics.tsx @@ -21,6 +21,7 @@ const mpris = isElectron() && utils?.isLinux() ? window.api.mpris : null; export interface SynchronizedLyricsProps extends Omit { lyrics: SynchronizedLyricsArray; + style?: React.CSSProperties; translatedLyrics?: null | string; } @@ -30,6 +31,7 @@ export const SynchronizedLyrics = ({ name, remote, source, + style, translatedLyrics, }: SynchronizedLyricsProps) => { const playbackType = usePlaybackType(); @@ -245,7 +247,7 @@ export const SynchronizedLyrics = ({ id="sychronized-lyrics-scroll-container" onMouseEnter={showScrollbar} onMouseLeave={hideScrollbar} - style={{ gap: `${settings.gap}px` }} + style={{ gap: `${settings.gap}px`, ...style }} > {settings.showProvider && source && (