Merge remote-tracking branch 'origin/main' into refactor/backend-pilot

This commit is contained in:
Psychotoxical
2026-05-09 18:12:01 +02:00
3 changed files with 57 additions and 20 deletions
+8
View File
@@ -211,6 +211,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Fixed
### Home — Because-you-listened rail compact in narrow layouts
**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#520](https://github.com/Psychotoxical/psysonic/pull/520)**
* When the rail container drops below the 2-card threshold (≈ 696 px — sidebar + queue both open, mini, etc.), the home **Because-you-listened** section now switches to the standard `AlbumRow` layout instead of stretching the hero-style cards to full width. The narrow path inherits the rail's existing perf tuning (artwork budget, viewport windowing, scroll paging).
* Wide layouts (>= 696 px) keep the existing 3-up hero cards with the "Similar to X" pill, album metadata, and album release-type pills — full-screen view is unchanged.
* Detection runs through a single `ResizeObserver` on the rail wrapper. The wide path adds zero extra renders.
### Security — Tauri patch for IPC origin-confusion (GHSA-7gmj-67g7-phm9)
**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#509](https://github.com/Psychotoxical/psysonic/pull/509)**
+48 -19
View File
@@ -1,4 +1,4 @@
import React, { memo, useEffect, useMemo, useState } from 'react';
import React, { memo, useEffect, useMemo, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Play, ListPlus, Music } from 'lucide-react';
@@ -14,6 +14,7 @@ import CachedImage, { useCachedUrl } from './CachedImage';
import { usePlayerStore, songToTrack } from '../store/playerStore';
import { useAuthStore } from '../store/authStore';
import { playAlbum } from '../utils/playAlbum';
import AlbumRow from './AlbumRow';
const ANCHOR_HISTORY_KEY_PREFIX = 'psysonic_because_anchor_history:';
const PICKS_HISTORY_KEY_PREFIX = 'psysonic_because_picks:';
@@ -125,6 +126,24 @@ export default function BecauseYouLikeRail({
);
const [anchor, setAnchor] = useState<Anchor | null>(null);
const [recs, setRecs] = useState<SubsonicAlbum[]>([]);
const containerRef = useRef<HTMLDivElement>(null);
const [narrow, setNarrow] = useState(false);
// 696px ≙ exactly 2 BecauseCards side-by-side (2*340 + 16 gap). Below that
// the hero-style cards stretch full-width and dwarf the rest of the page,
// so we swap in a standard AlbumRow which is already perf-tuned for narrow
// rails (artwork budget, viewport windowing, scroll-paging).
useEffect(() => {
const el = containerRef.current;
if (!el) return;
const ro = new ResizeObserver(entries => {
for (const entry of entries) {
setNarrow(entry.contentRect.width < 696);
}
});
ro.observe(el);
return () => ro.disconnect();
}, []);
useEffect(() => {
let cancelled = false;
@@ -208,26 +227,36 @@ export default function BecauseYouLikeRail({
return () => { cancelled = true; };
}, [pool, activeServerId]);
if (!anchor || recs.length === 0) return null;
if (!anchor || recs.length === 0) {
return <div ref={containerRef} />;
}
const sectionTitle = t('home.becauseYouLikeFor', { artist: anchor.name });
return (
<section className="album-row-section because-you-like-rail">
<div className="album-row-header">
<h2 className="section-title" style={{ marginBottom: 0 }}>
{t('home.becauseYouLikeFor', { artist: anchor.name })}
</h2>
</div>
<div className="because-card-grid">
{recs.map(album => (
<BecauseCard
key={album.id}
album={album}
anchor={anchor.name}
disableArtwork={disableArtwork}
/>
))}
</div>
</section>
<div ref={containerRef}>
{narrow ? (
<AlbumRow title={sectionTitle} albums={recs} disableArtwork={disableArtwork} />
) : (
<section className="album-row-section because-you-like-rail">
<div className="album-row-header">
<h2 className="section-title" style={{ marginBottom: 0 }}>
{sectionTitle}
</h2>
</div>
<div className="because-card-grid">
{recs.map(album => (
<BecauseCard
key={album.id}
album={album}
anchor={anchor.name}
disableArtwork={disableArtwork}
/>
))}
</div>
</section>
)}
</div>
);
}
+1 -1
View File
@@ -13916,7 +13916,7 @@ html[data-perf-disable-home-artwork-clip="true"] .home-lite-artwork .song-card-c
/* Hide the 3rd card only inside the 2-column range, so:
>= 1052px (3 cols) -> 3 cards in one row
696-1051px (2 cols) -> 2 cards in one row, orphan dropped
< 696px (1 col) -> 3 cards stacked, orphan welcome
Below 696px the rail switches to a standard AlbumRow in JS no layout here.
Math: 3*340 + 2*16 = 1052 (3-col cutoff), 2*340 + 1*16 = 696 (2-col cutoff). */
@container (min-width: 696px) and (max-width: 1051px) {
.because-card-grid > :nth-child(n+3) {