merge branch 'main' into redesign

This commit is contained in:
kveld9
2026-04-14 17:29:57 -03:00
31 changed files with 2648 additions and 298 deletions
+656 -209
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -117,6 +117,10 @@ export default function PlaylistDetail() {
const enablePlaylistCoverPhoto = useThemeStore(s => s.enablePlaylistCoverPhoto);
const showBitrate = useThemeStore(s => s.showBitrate);
const enableCoverArtBackground = useThemeStore(s => s.enableCoverArtBackground);
const enablePlaylistCoverPhoto = useThemeStore(s => s.enablePlaylistCoverPhoto);
const showBitrate = useThemeStore(s => s.showBitrate);
const [playlist, setPlaylist] = useState<SubsonicPlaylist | null>(null);
const [songs, setSongs] = useState<SubsonicSong[]>([]);
const [loading, setLoading] = useState(true);
+3 -1
View File
@@ -8,6 +8,7 @@ import ArtistRow from '../components/ArtistRow';
import { useTranslation } from 'react-i18next';
import { useDragDrop } from '../contexts/DragDropContext';
import { useAuthStore } from '../store/authStore';
import { useThemeStore } from '../store/themeStore';
function formatDuration(s: number) {
return `${Math.floor(s / 60)}:${(s % 60).toString().padStart(2, '0')}`;
@@ -23,6 +24,7 @@ export default function SearchResults() {
const currentTrack = usePlayerStore(s => s.currentTrack);
const psyDrag = useDragDrop();
const musicLibraryFilterVersion = useAuthStore(s => s.musicLibraryFilterVersion);
const showBitrate = useThemeStore(s => s.showBitrate);
useEffect(() => {
if (!query.trim()) { setResults(null); return; }
@@ -116,7 +118,7 @@ export default function SearchResults() {
<div className="track-artist-cell"><span className="track-artist" title={song.artist}>{song.artist}</span></div>
<div className="track-artist-cell"><span className="track-artist" title={song.album}>{song.album}</span></div>
<span className="track-codec" style={{ alignSelf: 'center' }}>
{[song.suffix?.toUpperCase(), song.bitRate ? `${song.bitRate} kbps` : ''].filter(Boolean).join(' · ')}
{[song.suffix?.toUpperCase(), showBitrate && song.bitRate ? `${song.bitRate} kbps` : ''].filter(Boolean).join(' · ')}
</span>
<span className="track-duration" style={{ textAlign: 'right' }}>
{formatDuration(song.duration)}
+41
View File
@@ -1612,6 +1612,47 @@ export default function Settings() {
</div>
</section>
<section className="settings-section">
<div className="settings-section-header">
<Palette size={18} />
<h2>{t('settings.visualOptionsTitle')}</h2>
</div>
<div className="settings-card">
<div className="settings-toggle-row">
<div>
<div style={{ fontWeight: 500 }}>{t('settings.coverArtBackground')}</div>
<div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{t('settings.coverArtBackgroundSub')}</div>
</div>
<label className="toggle-switch">
<input type="checkbox" checked={theme.enableCoverArtBackground} onChange={e => theme.setEnableCoverArtBackground(e.target.checked)} />
<span className="toggle-track" />
</label>
</div>
<div className="settings-section-divider" />
<div className="settings-toggle-row">
<div>
<div style={{ fontWeight: 500 }}>{t('settings.playlistCoverPhoto')}</div>
<div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{t('settings.playlistCoverPhotoSub')}</div>
</div>
<label className="toggle-switch">
<input type="checkbox" checked={theme.enablePlaylistCoverPhoto} onChange={e => theme.setEnablePlaylistCoverPhoto(e.target.checked)} />
<span className="toggle-track" />
</label>
</div>
<div className="settings-section-divider" />
<div className="settings-toggle-row">
<div>
<div style={{ fontWeight: 500 }}>{t('settings.showBitrate')}</div>
<div style={{ fontSize: 12, color: 'var(--text-muted)' }}>{t('settings.showBitrateSub')}</div>
</div>
<label className="toggle-switch">
<input type="checkbox" checked={theme.showBitrate} onChange={e => theme.setShowBitrate(e.target.checked)} />
<span className="toggle-track" />
</label>
</div>
</div>
</section>
<section className="settings-section">
<div className="settings-section-header">
<ZoomIn size={18} />