Adjust lyrics styling / animations

This commit is contained in:
jeffvli 2023-06-03 18:03:32 -07:00 committed by Jeff
parent 7cd2077dcd
commit 5dd860735d
5 changed files with 47 additions and 28 deletions

View file

@ -7,16 +7,20 @@ interface LyricLineProps extends ComponentPropsWithoutRef<'div'> {
} }
const StyledText = styled(TextTitle)` const StyledText = styled(TextTitle)`
font-size: 2rem; color: var(--main-fg);
font-weight: 100; font-weight: 100;
line-height: 3.5rem; font-size: 2vmax;
line-height: 3.5vmax;
opacity: 0.5;
&.active, &.active {
&.credit {
font-size: 2.5rem;
font-weight: 800; font-weight: 800;
line-height: 4rem; font-size: 2.5vmax;
line-height: 4vmax;
opacity: 1;
} }
transition: opacity 0.3s ease-in-out, font-size 0.3s ease-in-out;
`; `;
export const LyricLine = ({ text, ...props }: LyricLineProps) => { export const LyricLine = ({ text, ...props }: LyricLineProps) => {

View file

@ -1,16 +1,15 @@
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { Center, Group } from '@mantine/core';
import isElectron from 'is-electron'; import isElectron from 'is-electron';
import { ErrorBoundary } from 'react-error-boundary'; import { ErrorBoundary } from 'react-error-boundary';
import { ErrorFallback } from '/@/renderer/features/action-required'; import { ErrorFallback } from '/@/renderer/features/action-required';
import { getServerById, useCurrentSong } from '/@/renderer/store'; import { getServerById, useCurrentSong } from '/@/renderer/store';
import { SynchronizedLyrics } from './synchronized-lyrics';
import { UnsynchronizedLyrics } from '/@/renderer/features/lyrics/unsynchronized-lyrics'; import { UnsynchronizedLyrics } from '/@/renderer/features/lyrics/unsynchronized-lyrics';
import { LyricLine } from '/@/renderer/features/lyrics/lyric-line';
import { Center, Group } from '@mantine/core';
import { RiInformationFill } from 'react-icons/ri'; import { RiInformationFill } from 'react-icons/ri';
import { TextTitle } from '/@/renderer/components'; import { TextTitle } from '/@/renderer/components';
import { LyricsResponse, SynchronizedLyricsArray } from '/@/renderer/api/types'; import { LyricsResponse, SynchronizedLyricsArray } from '/@/renderer/api/types';
import { useSongLyrics } from '/@/renderer/features/lyrics/queries/lyric-query'; import { useSongLyrics } from '/@/renderer/features/lyrics/queries/lyric-query';
import { SynchronizedLyrics } from './synchronized-lyrics';
const lyrics = isElectron() ? window.electron.lyrics : null; const lyrics = isElectron() ? window.electron.lyrics : null;
@ -120,18 +119,17 @@ export const Lyrics = () => {
</Group> </Group>
</Center> </Center>
)} )}
{source && (
<LyricLine
key="provided-by"
className="credit"
text={`Provided by: ${source}`}
/>
)}
{songLyrics && {songLyrics &&
(Array.isArray(songLyrics) ? ( (Array.isArray(songLyrics) ? (
<SynchronizedLyrics lyrics={songLyrics} /> <SynchronizedLyrics
lyrics={songLyrics}
source={source}
/>
) : ( ) : (
<UnsynchronizedLyrics lyrics={songLyrics} /> <UnsynchronizedLyrics
lyrics={songLyrics}
source={source}
/>
))} ))}
</ErrorBoundary> </ErrorBoundary>
); );

View file

@ -11,14 +11,21 @@ import { LyricLine } from '/@/renderer/features/lyrics/lyric-line';
import isElectron from 'is-electron'; import isElectron from 'is-electron';
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref'; import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
import { SynchronizedLyricsArray } from '/@/renderer/api/types'; import { SynchronizedLyricsArray } from '/@/renderer/api/types';
import styled from 'styled-components';
import { Text } from '/@/renderer/components';
const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null; const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null;
const SynchronizedLyricsContainer = styled.div`
padding: 3rem 0 10rem;
`;
interface SynchronizedLyricsProps { interface SynchronizedLyricsProps {
lyrics: SynchronizedLyricsArray; lyrics: SynchronizedLyricsArray;
source: string | null;
} }
export const SynchronizedLyrics = ({ lyrics }: SynchronizedLyricsProps) => { export const SynchronizedLyrics = ({ lyrics, source }: SynchronizedLyricsProps) => {
const playersRef = PlayersRef; const playersRef = PlayersRef;
const status = useCurrentStatus(); const status = useCurrentStatus();
const playerType = usePlayerType(); const playerType = usePlayerType();
@ -203,7 +210,8 @@ export const SynchronizedLyrics = ({ lyrics }: SynchronizedLyricsProps) => {
}, []); }, []);
return ( return (
<div className="synchronized-lyrics"> <SynchronizedLyricsContainer className="synchronized-lyrics">
{source && <Text $noSelect>Lyrics provided by: {source}</Text>}
{lyrics.map(([, text], idx) => ( {lyrics.map(([, text], idx) => (
<LyricLine <LyricLine
key={idx} key={idx}
@ -211,6 +219,6 @@ export const SynchronizedLyrics = ({ lyrics }: SynchronizedLyricsProps) => {
text={text} text={text}
/> />
))} ))}
</div> </SynchronizedLyricsContainer>
); );
}; };

View file

@ -1,17 +1,20 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { Text } from '/@/renderer/components';
import { LyricLine } from '/@/renderer/features/lyrics/lyric-line'; import { LyricLine } from '/@/renderer/features/lyrics/lyric-line';
interface UnsynchronizedLyricsProps { interface UnsynchronizedLyricsProps {
lyrics: string; lyrics: string;
source: string | null;
} }
export const UnsynchronizedLyrics = ({ lyrics }: UnsynchronizedLyricsProps) => { export const UnsynchronizedLyrics = ({ lyrics, source }: UnsynchronizedLyricsProps) => {
const lines = useMemo(() => { const lines = useMemo(() => {
return lyrics.split('\n'); return lyrics.split('\n');
}, [lyrics]); }, [lyrics]);
return ( return (
<div> <div className="unsynchronized-lyrics">
{source && <Text $noSelect>Lyrics provided by: {source}</Text>}
{lines.map((text, idx) => ( {lines.map((text, idx) => (
<LyricLine <LyricLine
key={idx} key={idx}

View file

@ -3,7 +3,7 @@ import { motion } from 'framer-motion';
import { HiOutlineQueueList } from 'react-icons/hi2'; import { HiOutlineQueueList } from 'react-icons/hi2';
import { RiFileMusicLine, RiFileTextLine, RiInformationFill } from 'react-icons/ri'; import { RiFileMusicLine, RiFileTextLine, RiInformationFill } from 'react-icons/ri';
import styled from 'styled-components'; import styled from 'styled-components';
import { Button, TextTitle } from '/@/renderer/components'; import { Button, ScrollArea, TextTitle } from '/@/renderer/components';
import { PlayQueue } from '/@/renderer/features/now-playing'; import { PlayQueue } from '/@/renderer/features/now-playing';
import { import {
useFullScreenPlayerStore, useFullScreenPlayerStore,
@ -27,10 +27,16 @@ const QueueContainer = styled.div`
} }
`; `;
const LyricsContainer = styled.div` const LyricsContainer = styled(ScrollArea)`
height: 100%;
overflow: scroll;
text-align: center; text-align: center;
mask-image: linear-gradient(
180deg,
transparent 5%,
rgba(0, 0, 0, 100%) 20%,
rgba(0, 0, 0, 100%) 85%,
transparent 95%
);
`; `;
const ActiveTabIndicator = styled(motion.div)` const ActiveTabIndicator = styled(motion.div)`
@ -118,7 +124,7 @@ export const FullScreenPlayerQueue = () => {
</Group> </Group>
</Center> </Center>
) : activeTab === 'lyrics' ? ( ) : activeTab === 'lyrics' ? (
<LyricsContainer> <LyricsContainer scrollHideDelay={0}>
<Lyrics /> <Lyrics />
</LyricsContainer> </LyricsContainer>
) : null} ) : null}