mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 14:35:41 +00:00
feat(perf): 3-state animation mode (Full / Reduced / Static) (#441)
* feat(perf): 3-state animation mode (Full / Reduced / Static) Replaces the boolean `reducedAnimations` toggle with a three-way `animationMode` setting, suggested by Viktor Petrovich after the Windows audio fix (PR #426) shipped and confirmed a measurable GPU drop: - `full` (default): native frame rate, marquee scrolls normally - `reduced`: 30 fps cap on the animated seekbar wave; player marquee runs at half speed - `static`: rAF loop disabled; the seekbar repaints from the ~2 Hz audio:progress heartbeat. Player title/artist truncate with ellipsis instead of scrolling. Migration in `onRehydrateStorage` maps legacy `reducedAnimations: true` to `'reduced'`, anything else to `'full'`. Static is opt-in only. Settings UI follows the ReplayGain Auto/Track/Album pattern with a contextual hint that explains what each mode does. i18n: 5 new keys across 8 locales, 2 legacy keys removed. * docs(changelog): add #441 3-state animation mode entry * chore(credits): add #441 to Psychotoxical contributions
This commit is contained in:
committed by
GitHub
parent
364b29ceee
commit
98ff73d17a
@@ -1,4 +1,5 @@
|
||||
import React, { useRef, useState, useEffect, useCallback } from 'react';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
|
||||
interface Props {
|
||||
text: string;
|
||||
@@ -11,6 +12,7 @@ export default function MarqueeText({ text, className, style, onClick }: Props)
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const textRef = useRef<HTMLSpanElement>(null);
|
||||
const [scrollAmount, setScrollAmount] = useState(0);
|
||||
const animationMode = useAuthStore(s => s.animationMode);
|
||||
|
||||
const measure = useCallback(() => {
|
||||
const container = containerRef.current;
|
||||
@@ -30,17 +32,22 @@ export default function MarqueeText({ text, className, style, onClick }: Props)
|
||||
return () => ro.disconnect();
|
||||
}, [text, measure]);
|
||||
|
||||
// In `static` animation mode the marquee never scrolls — overflowing text
|
||||
// is truncated with an ellipsis (handled by CSS via data-anim-mode).
|
||||
const shouldScroll = scrollAmount > 0 && animationMode !== 'static';
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={`marquee-wrap${className ? ` ${className}` : ''}`}
|
||||
style={style}
|
||||
onClick={onClick}
|
||||
data-anim-mode={animationMode}
|
||||
>
|
||||
<span
|
||||
ref={textRef}
|
||||
className={scrollAmount > 0 ? 'marquee-scroll' : ''}
|
||||
style={scrollAmount > 0 ? { '--marquee-amount': `-${scrollAmount}px` } as React.CSSProperties : {}}
|
||||
className={shouldScroll ? 'marquee-scroll' : ''}
|
||||
style={shouldScroll ? { '--marquee-amount': `-${scrollAmount}px` } as React.CSSProperties : {}}
|
||||
>
|
||||
{text}
|
||||
</span>
|
||||
|
||||
Reference in New Issue
Block a user