fix: TV-Modal schwarze Seite (xREL skip), aufklappbare Sektionen, TV-Staffelinfo
This commit is contained in:
@@ -387,6 +387,47 @@ function DemnächstGrid({ onOpenModal, xrelIds, onXrelLoaded }) {
|
||||
}
|
||||
|
||||
// ── Suche ────────────────────────────────────────────────────────────────────
|
||||
// ── Aufklappbare Film/Serien-Sektion ─────────────────────────────────────────
|
||||
function CollapsibleSection({ label, count, children, defaultOpen=true }) {
|
||||
const [open, setOpen] = useState(defaultOpen);
|
||||
return (
|
||||
<div style={{marginBottom:16}}>
|
||||
<button onClick={()=>setOpen(v=>!v)} style={{
|
||||
display:'flex',alignItems:'center',gap:8,background:'none',border:'none',cursor:'pointer',
|
||||
width:'100%',padding:'6px 0',marginBottom: open?10:0,
|
||||
}}>
|
||||
<span style={{color:'rgba(255,255,255,0.5)',fontFamily:'monospace',fontSize:11,letterSpacing:1}}>
|
||||
{label} ({count})
|
||||
</span>
|
||||
<div style={{flex:1,height:1,background:'rgba(255,255,255,0.07)'}}/>
|
||||
<span style={{color:'rgba(255,255,255,0.3)',fontSize:11,transform:open?'rotate(90deg)':'none',transition:'transform 0.2s'}}>▶</span>
|
||||
</button>
|
||||
{open && children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SectionedGrid({ films, serien, favIds, xrelIds, onToggle, onOpenModal }) {
|
||||
return (
|
||||
<div>
|
||||
{films.length > 0 && (
|
||||
<CollapsibleSection label="🎬 FILME" count={films.length}>
|
||||
<div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(130px,1fr))',gap:12}}>
|
||||
{films.map(m => <MovieCard key={'m'+m.id} movie={m} favIds={favIds} hasXrel={xrelIds?.has(m.id)} onToggleFav={onToggle} onOpenModal={onOpenModal}/>)}
|
||||
</div>
|
||||
</CollapsibleSection>
|
||||
)}
|
||||
{serien.length > 0 && (
|
||||
<CollapsibleSection label="📺 SERIEN" count={serien.length}>
|
||||
<div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(130px,1fr))',gap:12}}>
|
||||
{serien.map(m => <MovieCard key={'t'+m.id} movie={m} favIds={favIds} hasXrel={xrelIds?.has(m.id)} onToggleFav={onToggle} onOpenModal={onOpenModal}/>)}
|
||||
</div>
|
||||
</CollapsibleSection>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SucheGrid({ onOpenModal, xrelIds, onXrelLoaded }) {
|
||||
const [query, setQuery] = useState('');
|
||||
const [results, setResults] = useState(null); // null=noch nicht gesucht
|
||||
@@ -465,26 +506,7 @@ function SucheGrid({ onOpenModal, xrelIds, onXrelLoaded }) {
|
||||
{results !== null && results.length > 0 && (() => {
|
||||
const films = results.filter(m => m.media_type !== 'tv');
|
||||
const serien = results.filter(m => m.media_type === 'tv');
|
||||
return (
|
||||
<div>
|
||||
{films.length > 0 && (
|
||||
<div style={{marginBottom:20}}>
|
||||
<div style={{color:'rgba(255,255,255,0.4)',fontFamily:'monospace',fontSize:10,letterSpacing:1,marginBottom:8}}>🎬 FILME ({films.length})</div>
|
||||
<div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(130px,1fr))',gap:12}}>
|
||||
{films.map(m => <MovieCard key={'m'+m.id} movie={m} favIds={favIds} hasXrel={xrelIds?.has(m.id)} onToggleFav={onToggle} onOpenModal={onOpenModal}/>)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{serien.length > 0 && (
|
||||
<div>
|
||||
<div style={{color:'rgba(255,255,255,0.4)',fontFamily:'monospace',fontSize:10,letterSpacing:1,marginBottom:8}}>📺 SERIEN ({serien.length})</div>
|
||||
<div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(130px,1fr))',gap:12}}>
|
||||
{serien.map(m => <MovieCard key={'t'+m.id} movie={m} favIds={favIds} hasXrel={xrelIds?.has(m.id)} onToggleFav={onToggle} onOpenModal={onOpenModal}/>)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
return <SectionedGrid films={films} serien={serien} favIds={favIds} xrelIds={xrelIds} onToggle={onToggle} onOpenModal={onOpenModal}/>;
|
||||
})()}
|
||||
</div>
|
||||
);
|
||||
@@ -700,45 +722,38 @@ function FavoritenKalender({ onOpenModal }) {
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
{/* Filme */}
|
||||
{filmeFavs.length > 0 && (
|
||||
<div style={{color:'rgba(255,255,255,0.5)',fontFamily:'monospace',fontSize:11,fontWeight:700,letterSpacing:1,
|
||||
borderBottom:'1px solid rgba(255,255,255,0.07)',paddingBottom:6}}>
|
||||
🎬 FILME ({filmeFavs.length})
|
||||
</div>
|
||||
)}
|
||||
<CollapsibleSection label="🎬 FILME" count={filmeFavs.length}>
|
||||
{Object.entries(filmGroups).sort(([a],[b]) => a.localeCompare(b)).map(([key, group]) => (
|
||||
<div key={'film-'+key}>
|
||||
<div style={{ ...S.head, marginBottom:10, display:'flex', alignItems:'center', gap:8 }}>
|
||||
<div key={'film-'+key} style={{marginBottom:12}}>
|
||||
<div style={{...S.head,marginBottom:6,display:'flex',alignItems:'center',gap:6}}>
|
||||
<span>{group.label.toUpperCase()}</span>
|
||||
<div style={{ flex:1, height:1, background:'rgba(255,255,255,0.07)' }}/>
|
||||
<span style={{ fontSize:9 }}>{group.items.length} Film{group.items.length!==1?'e':''}</span>
|
||||
<div style={{flex:1,height:1,background:'rgba(255,255,255,0.07)'}}/>
|
||||
<span style={{fontSize:9}}>{group.items.length}×</span>
|
||||
</div>
|
||||
<div style={{ display:'flex', flexDirection:'column', gap:8 }}>
|
||||
<div style={{display:'flex',flexDirection:'column',gap:6}}>
|
||||
{group.items.map(f => <FavCard key={f.tmdb_id} f={f} onOpenModal={onOpenModal} onRemove={removeFav}/>)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{/* Serien */}
|
||||
{serienFavs.length > 0 && (
|
||||
<div style={{color:'rgba(255,255,255,0.5)',fontFamily:'monospace',fontSize:11,fontWeight:700,letterSpacing:1,
|
||||
borderBottom:'1px solid rgba(255,255,255,0.07)',paddingBottom:6,marginTop:8}}>
|
||||
📺 SERIEN ({serienFavs.length})
|
||||
</div>
|
||||
</CollapsibleSection>
|
||||
)}
|
||||
{serienFavs.length > 0 && (
|
||||
<CollapsibleSection label="📺 SERIEN" count={serienFavs.length}>
|
||||
{Object.entries(serienGroups).sort(([a],[b]) => a.localeCompare(b)).map(([key, group]) => (
|
||||
<div key={'serie-'+key}>
|
||||
<div style={{ ...S.head, marginBottom:10, display:'flex', alignItems:'center', gap:8 }}>
|
||||
<div key={'serie-'+key} style={{marginBottom:12}}>
|
||||
<div style={{...S.head,marginBottom:6,display:'flex',alignItems:'center',gap:6}}>
|
||||
<span>{group.label.toUpperCase()}</span>
|
||||
<div style={{ flex:1, height:1, background:'rgba(255,255,255,0.07)' }}/>
|
||||
<span style={{ fontSize:9 }}>{group.items.length} Serie{group.items.length!==1?'n':''}</span>
|
||||
<div style={{flex:1,height:1,background:'rgba(255,255,255,0.07)'}}/>
|
||||
<span style={{fontSize:9}}>{group.items.length}×</span>
|
||||
</div>
|
||||
<div style={{ display:'flex', flexDirection:'column', gap:8 }}>
|
||||
<div style={{display:'flex',flexDirection:'column',gap:6}}>
|
||||
{group.items.map(f => <FavCard key={f.tmdb_id} f={f} onOpenModal={onOpenModal} onRemove={removeFav}/>)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{/* Alte groups-Schleife entfernt – DUMMY damit Code nicht bricht */}
|
||||
</CollapsibleSection>
|
||||
)}
|
||||
{false && Object.entries({}).map(([key, group]) => (
|
||||
<div key={key}>
|
||||
<div style={{ ...S.head, marginBottom:10, display:'flex', alignItems:'center', gap:8 }}>
|
||||
@@ -813,7 +828,8 @@ function MovieModal({ tmdbId, mediaType='movie', onClose, mobile, onHasXrel, noY
|
||||
setDetail(d);
|
||||
detailRef.current = d;
|
||||
setLoading(false);
|
||||
// Gecachte Releases laden sobald wir den Titel kennen
|
||||
// Gecachte Releases laden (nur für Filme)
|
||||
if (mediaType !== 'tv') {
|
||||
const params = new URLSearchParams({
|
||||
title: d.title || '',
|
||||
orig: d.original_title || '',
|
||||
@@ -826,12 +842,13 @@ function MovieModal({ tmdbId, mediaType='movie', onClose, mobile, onHasXrel, noY
|
||||
if (r.xrel?.length > 0) { setXrel(r.xrel); onHasXrel?.(tmdbId); }
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
})
|
||||
.catch(e => { setError(e.message); setLoading(false); });
|
||||
const prev = document.body.style.overflow;
|
||||
document.body.style.overflow = 'hidden';
|
||||
return () => { document.body.style.overflow = prev; };
|
||||
}, [tmdbId]);
|
||||
}, [tmdbId, mediaType]);
|
||||
|
||||
const searchXrel = async (forceRefresh = false) => {
|
||||
const d = detailRef.current;
|
||||
@@ -931,7 +948,9 @@ function MovieModal({ tmdbId, mediaType='movie', onClose, mobile, onHasXrel, noY
|
||||
)}
|
||||
<div style={{ display:'flex', gap:5, flexWrap:'wrap', marginBottom:8 }}>
|
||||
{detail.vote_average > 0 && <Badge bg="rgba(255,230,109,0.15)" color="#ffe66d">★ {detail.vote_average.toFixed(1)}</Badge>}
|
||||
{detail.runtime > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.7)">⏱ {detail.runtime} Min</Badge>}
|
||||
{detail.media_type !== 'tv' && detail.runtime > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.7)">⏱ {detail.runtime} Min</Badge>}
|
||||
{detail.media_type === 'tv' && detail.number_of_seasons > 0 && <Badge bg="rgba(96,165,250,0.15)" color="#60a5fa">📺 {detail.number_of_seasons} Staffel{detail.number_of_seasons!==1?'n':''}</Badge>}
|
||||
{detail.media_type === 'tv' && detail.number_of_episodes > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.7)">{detail.number_of_episodes} Ep.</Badge>}
|
||||
{fskStyle && <Badge bg={fskStyle.bg} color={fskStyle.color}>FSK {detail.fsk}</Badge>}
|
||||
{detail.release_date && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.55)">🇩🇪 {fmtDE(detail.release_date)}</Badge>}
|
||||
{detail.countries?.length > 0 && <Badge bg="rgba(255,255,255,0.07)" color="rgba(255,255,255,0.4)">🌍 {detail.countries.slice(0,2).join(' · ')}</Badge>}
|
||||
|
||||
Reference in New Issue
Block a user