Adjust lyrics styling / animations
This commit is contained in:
parent
7cd2077dcd
commit
5dd860735d
5 changed files with 47 additions and 28 deletions
|
@ -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) => {
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
Reference in a new issue