Merge branch 'main' into exp/orbit (pre-PR sync)

Conflicts resolved in:
- src/pages/SearchResults.tsx
- src/pages/AdvancedSearch.tsx

Both pages were rewritten on main (PR #303) to use the shared
<SongRow> component with click-to-enqueueAndPlay semantics. Orbit's
playSong helper that branched on orbit-active is no longer needed
at the page level — instead, orbit awareness moved INTO SongRow and
SongCard themselves: in an active orbit session both buttons collapse
into addTrackToOrbit (suggest for guests, host-enqueue for the host)
so we don't ship a queue replacement to every guest.

Also kept main's IntersectionObserver-based pagination on both pages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Psychotoxical
2026-04-25 16:34:38 +02:00
28 changed files with 1760 additions and 215 deletions
+16 -2
View File
@@ -1,7 +1,7 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
export type HomeSectionId = 'hero' | 'recent' | 'discover' | 'discoverArtists' | 'recentlyPlayed' | 'starred' | 'mostPlayed';
export type HomeSectionId = 'hero' | 'recent' | 'discover' | 'discoverSongs' | 'discoverArtists' | 'recentlyPlayed' | 'starred' | 'mostPlayed';
export interface HomeSectionConfig {
id: HomeSectionId;
@@ -12,6 +12,7 @@ export const DEFAULT_HOME_SECTIONS: HomeSectionConfig[] = [
{ id: 'hero', visible: true },
{ id: 'recent', visible: true },
{ id: 'discover', visible: true },
{ id: 'discoverSongs', visible: true },
{ id: 'discoverArtists', visible: true },
{ id: 'recentlyPlayed', visible: true },
{ id: 'starred', visible: true },
@@ -33,6 +34,19 @@ export const useHomeStore = create<HomeStore>()(
})),
reset: () => set({ sections: DEFAULT_HOME_SECTIONS }),
}),
{ name: 'psysonic_home' }
{
name: 'psysonic_home',
onRehydrateStorage: () => (state) => {
// Append any sections introduced after the user first persisted their order,
// so new defaults show up without forcing a manual Reset.
if (!state) return;
const safe = (state.sections ?? []).filter(
(s): s is HomeSectionConfig => s != null && typeof s.id === 'string',
);
const known = new Set(safe.map(s => s.id));
const missing = DEFAULT_HOME_SECTIONS.filter(s => !known.has(s.id));
state.sections = missing.length > 0 ? [...safe, ...missing] : safe;
},
}
)
);
+1
View File
@@ -12,6 +12,7 @@ export const DEFAULT_SIDEBAR_ITEMS: SidebarItemConfig[] = [
{ id: 'mainstage', visible: true },
{ id: 'newReleases', visible: true },
{ id: 'allAlbums', visible: true },
{ id: 'tracks', visible: true },
{ id: 'randomPicker', visible: true },
{ id: 'randomMix', visible: true },
{ id: 'randomAlbums', visible: true },