mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
feat: v1.8.0 — new themes, queue toolbar, lightbox, i18n (fr/nl)
Themes: - Add Poison (phosphor green on charcoal), Nucleo (warm brass light), Classic Winamp (LCD glow, Winamp yellow/orange) themes - Overhaul Psychowave — refined deep violet, no longer WIP - Reorganise ThemePicker into groups: Catppuccin, Nord, Retro, Tokyo Night, Psysonic Themes - Add --volume-accent CSS var for per-theme volume slider colour override Queue: - Full toolbar redesign with centred round buttons (Shuffle/Save/Load/Clear/Gapless/Crossfade) - Crossfade popover with 1–10 s range slider, right-aligned to avoid viewport overflow - Queue header: title + count + duration inline in accent colour, close button removed - Tech info (codec/bitrate) as frosted-glass overlay badge on cover art UI: - CoverLightbox shared component for album cover (AlbumHeader) and artist avatar (ArtistDetail) - NowPlayingDropdown: separate spinning/loading state — button always clickable, icon spins 600 ms min - Settings: "Experimental" badge on Crossfade and Gapless toggles - Help page: 2-column grid layout, new Crossfade & Gapless Q&A entry, updated theme/language entries i18n: - Full French (fr) and Dutch (nl) translations across all namespaces - Language selector sorted alphabetically (nl, en, fr, de) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ export default function NowPlayingDropdown() {
|
||||
const isPlaying = usePlayerStore(s => s.isPlaying);
|
||||
const ownUsername = useAuthStore(s => s.getActiveServer()?.username ?? '');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [spinning, setSpinning] = useState(false);
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const fetchNowPlaying = async () => {
|
||||
@@ -28,6 +29,13 @@ export default function NowPlayingDropdown() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
setSpinning(true);
|
||||
fetchNowPlaying().finally(() => {
|
||||
setTimeout(() => setSpinning(false), 600);
|
||||
});
|
||||
};
|
||||
|
||||
// Poll in background so the badge stays current without opening the dropdown
|
||||
useEffect(() => {
|
||||
fetchNowPlaying();
|
||||
@@ -104,11 +112,11 @@ export default function NowPlayingDropdown() {
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: '1px solid var(--border-subtle)', paddingBottom: '0.5rem' }}>
|
||||
<h3 style={{ margin: 0, fontSize: '14px', fontWeight: 600 }}>{t('nowPlaying.title')}</h3>
|
||||
<button
|
||||
onClick={fetchNowPlaying}
|
||||
className={`btn btn-ghost ${loading ? 'animate-spin' : ''}`}
|
||||
style={{ width: '28px', height: '28px', padding: 0 }}
|
||||
onClick={handleRefresh}
|
||||
className="btn btn-ghost"
|
||||
style={{ width: '28px', height: '28px', padding: 0, justifyContent: 'center' }}
|
||||
>
|
||||
<RefreshCw size={14} />
|
||||
<RefreshCw size={14} className={spinning ? 'animate-spin' : ''} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user