feat(seekbar): configurable seekbar styles with animated preview

Add five seekbar styles selectable in Settings → Appearance:
Waveform, Line & Dot, Bar, Thick Bar, and Segmented. Each option
shows an animated canvas preview using requestAnimationFrame.

Style is persisted in authStore (seekbarStyle, default: waveform).
Translations added for all 7 languages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Psychotoxical
2026-04-08 01:39:08 +02:00
parent ada7dd010f
commit 829936a78d
10 changed files with 377 additions and 53 deletions
+25 -1
View File
@@ -18,7 +18,8 @@ import { lastfmGetToken, lastfmAuthUrl, lastfmGetSession, lastfmGetUserInfo, Las
import LastfmIcon from '../components/LastfmIcon';
import CustomSelect from '../components/CustomSelect';
import ThemePicker from '../components/ThemePicker';
import { useAuthStore, ServerProfile } from '../store/authStore';
import { useAuthStore, ServerProfile, type SeekbarStyle } from '../store/authStore';
import { SeekbarPreview } from '../components/WaveformSeek';
import { IS_LINUX } from '../utils/platform';
import { useThemeStore } from '../store/themeStore';
import { useFontStore, FontId } from '../store/fontStore';
@@ -1147,6 +1148,29 @@ export default function Settings() {
</div>
</section>
<section className="settings-section">
<div className="settings-section-header">
<Sliders size={18} />
<h2>{t('settings.seekbarStyle')}</h2>
</div>
<div className="settings-card">
<div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: '0.75rem' }}>
{t('settings.seekbarStyleDesc')}
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
{(['waveform', 'linedot', 'bar', 'thick', 'segmented'] as SeekbarStyle[]).map(style => (
<SeekbarPreview
key={style}
style={style}
label={t(`settings.seekbar${style.charAt(0).toUpperCase() + style.slice(1)}` as any)}
selected={auth.seekbarStyle === style}
onClick={() => auth.setSeekbarStyle(style)}
/>
))}
</div>
</div>
</section>
<SidebarCustomizer />
</>
)}