detail page components

This commit is contained in:
2026-03-27 23:06:44 +02:00
parent 02f0f58ec9
commit a039249ede
41 changed files with 6470 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
import { useNavigate } from 'react-router-dom'
import type { TmdbCastMember } from '../../api/tmdb'
interface Props {
crew: TmdbCastMember[] | null | undefined
}
const COMPOSER_JOBS = new Set([
'Original Music Composer',
'Music',
'Composer',
'Theme Song Performance',
])
/**
* "Theme by ..." line surfaced from TMDB credits.crew. Surfaces the
* composer(s) without burying them in the dense crew strip. Renders
* nothing when there's no composer credit.
*/
export default function ComposerBlock({ crew }: Props) {
const navigate = useNavigate()
if (!crew || crew.length === 0) return null
const seen = new Set<number>()
const composers: TmdbCastMember[] = []
for (const c of crew) {
if (!c.job || !COMPOSER_JOBS.has(c.job)) continue
if (seen.has(c.id)) continue
seen.add(c.id)
composers.push(c)
if (composers.length >= 3) break
}
if (composers.length === 0) return null
return (
<p className="text-[12.5px] text-text-3 leading-relaxed">
<span className="text-text-4 mr-1.5">Theme by</span>
{composers.map((c, i) => (
<span key={c.id}>
<button
onClick={() => navigate(`/person/${c.id}`)}
className="text-text-1 font-medium hover:text-accent transition focus-ring rounded"
>
{c.name}
</button>
{i < composers.length - 1 && <span className="text-text-5 mx-1.5">·</span>}
</span>
))}
</p>
)
}