mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-06 20:10:12 +02:00
feat(lyrics): non-active lyric settings (#1954)
* feat: non-active lyric settings
This commit is contained in:
@@ -540,6 +540,8 @@
|
||||
"lyricOffset": "lyrics offset (ms)",
|
||||
"lyricGap": "lyric gap",
|
||||
"lyricSize": "lyric size",
|
||||
"lyricOpacityNonActive": "non-active lyric opacity",
|
||||
"lyricScaleNonActive": "non-active lyric scale",
|
||||
"opacity": "opacity",
|
||||
"showLyricMatch": "show lyric match",
|
||||
"showLyricProvider": "show lyric provider",
|
||||
|
||||
@@ -17,6 +17,7 @@ import { MultiSelect } from '/@/shared/components/multi-select/multi-select';
|
||||
import { NumberInput } from '/@/shared/components/number-input/number-input';
|
||||
import { SegmentedControl } from '/@/shared/components/segmented-control/segmented-control';
|
||||
import { Select } from '/@/shared/components/select/select';
|
||||
import { Slider } from '/@/shared/components/slider/slider';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Switch } from '/@/shared/components/switch/switch';
|
||||
import { TextInput } from '/@/shared/components/text-input/text-input';
|
||||
@@ -185,6 +186,48 @@ export const LyricsSettingsForm = ({ settingsKey }: LyricsSettingsFormProps) =>
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<Slider
|
||||
defaultValue={displaySettings.opacityNonActive}
|
||||
label={(e) => (e * 100).toFixed(0) + '%'}
|
||||
max={1.0}
|
||||
min={0.0}
|
||||
onChangeEnd={(e) => {
|
||||
updateDisplaySetting({
|
||||
opacityNonActive: e,
|
||||
});
|
||||
}}
|
||||
step={0.01}
|
||||
w={100}
|
||||
/>
|
||||
),
|
||||
description: '',
|
||||
title: t(`${t('page.fullscreenPlayer.config.lyricOpacityNonActive')}`, {
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<Slider
|
||||
defaultValue={displaySettings.scaleNonActive}
|
||||
label={(e) => (e * 100).toFixed(0) + '%'}
|
||||
max={1.0}
|
||||
min={0.5}
|
||||
onChangeEnd={(e) => {
|
||||
updateDisplaySetting({
|
||||
scaleNonActive: e,
|
||||
});
|
||||
}}
|
||||
step={0.01}
|
||||
w={100}
|
||||
/>
|
||||
),
|
||||
description: '',
|
||||
title: t(`${t('page.fullscreenPlayer.config.lyricScaleNonActive')}`, {
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<Switch
|
||||
|
||||
@@ -4,14 +4,18 @@
|
||||
line-height: 1.2;
|
||||
color: var(--theme-colors-foreground);
|
||||
word-break: normal;
|
||||
opacity: 0.35;
|
||||
opacity: var(--lyric-opacity);
|
||||
transform: scale(var(--lyric-scale));
|
||||
transform-origin: var(--lyric-scale-origin) center;
|
||||
transition:
|
||||
opacity 0.3s ease-in-out,
|
||||
transform 0.3s ease-in-out;
|
||||
opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1),
|
||||
transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.lyric-line:global(.active) {
|
||||
opacity: 1 !important;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.lyric-line:global(.unsynchronized) {
|
||||
|
||||
@@ -49,6 +49,11 @@ export const SynchronizedLyrics = ({
|
||||
? displaySettings.fontSize
|
||||
: 24,
|
||||
gap: displaySettings.gap && displaySettings.gap !== 0 ? displaySettings.gap : 24,
|
||||
opacityNonActive: displaySettings.opacityNonActive,
|
||||
scaleNonActive:
|
||||
displaySettings.scaleNonActive && displaySettings.scaleNonActive !== 0
|
||||
? displaySettings.scaleNonActive
|
||||
: 0.95,
|
||||
};
|
||||
const { mediaSeekToTimestamp } = usePlayerActions();
|
||||
const status = usePlayerStatus();
|
||||
@@ -308,7 +313,18 @@ export const SynchronizedLyrics = ({
|
||||
onMouseEnter={showScrollbar}
|
||||
onMouseLeave={hideScrollbar}
|
||||
ref={containerRef}
|
||||
style={{ gap: `${settings.gap}px`, ...style }}
|
||||
style={
|
||||
{
|
||||
// opacity/scale is set here for every lyric,
|
||||
// and then overwritten by CSS for active lyrics
|
||||
// to prevent expensive rerenders each lyric
|
||||
'--lyric-opacity': settings.opacityNonActive,
|
||||
'--lyric-scale': settings.scaleNonActive,
|
||||
'--lyric-scale-origin': settings.alignment,
|
||||
gap: `${settings.gap}px`,
|
||||
...style,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
{settings.showProvider && source && (
|
||||
<LyricLine
|
||||
|
||||
@@ -536,6 +536,8 @@ const LyricsDisplaySettingsSchema = z.object({
|
||||
fontSizeUnsync: z.number(),
|
||||
gap: z.number(),
|
||||
gapUnsync: z.number(),
|
||||
opacityNonActive: z.number(),
|
||||
scaleNonActive: z.number(),
|
||||
});
|
||||
|
||||
const LyricsSettingsSchema = z.object({
|
||||
@@ -1794,6 +1796,8 @@ const initialState: SettingsState = {
|
||||
fontSizeUnsync: 24,
|
||||
gap: 24,
|
||||
gapUnsync: 24,
|
||||
opacityNonActive: 0.2,
|
||||
scaleNonActive: 0.95,
|
||||
},
|
||||
},
|
||||
playback: {
|
||||
@@ -2211,7 +2215,10 @@ export const useSettingsStore = createWithEqualityFn<SettingsSlice>()(
|
||||
|
||||
state.lyrics = mainSettings;
|
||||
state.lyricsDisplay = {
|
||||
default: displaySettings,
|
||||
default: {
|
||||
...state.lyricsDisplay.default,
|
||||
...displaySettings,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user