mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-10 03:17:27 +02:00
feat(ui): improve podcast display in playlist and podcast views
- Show podcast-aware album link in playlist (navigates to podcast channel page) - Show '-' instead of '[Unknown Artist]' for podcast episodes with no artist - Use best-resolution image URL in podcast list view - Add srcSet/sizes for responsive cover images in podcast grid and show views
This commit is contained in:
parent
6166396152
commit
3ce6141887
4 changed files with 31 additions and 3 deletions
|
|
@ -57,7 +57,10 @@ AlbumOrChannelLinkField.defaultProps = { addLabel: true, sortBy: 'album' }
|
|||
|
||||
const PodcastAwareArtistField = (props) => {
|
||||
const record = props.record
|
||||
if (record?.genre === 'Podcast' && !record?.artist) {
|
||||
const isPodcast = record?.genre === 'Podcast'
|
||||
const hasNoRealArtist =
|
||||
!record?.artist || record?.artist === '[Unknown Artist]'
|
||||
if (isPodcast && hasNoRealArtist) {
|
||||
return <span>-</span>
|
||||
}
|
||||
return <ArtistLinkField {...props} />
|
||||
|
|
|
|||
|
|
@ -42,6 +42,11 @@ const useStyles = makeStyles((theme) => ({
|
|||
},
|
||||
}))
|
||||
|
||||
const buildSrcSet = (images) => {
|
||||
if (!images || images.length === 0) return undefined
|
||||
return images.map((img) => `${img.url} ${img.width}w`).join(', ')
|
||||
}
|
||||
|
||||
const getColsForWidth = (width) => {
|
||||
if (width === 'xs') return 2
|
||||
if (width === 'sm') return 3
|
||||
|
|
@ -67,7 +72,13 @@ const PodcastGridView = ({ width, ...props }) => {
|
|||
<div className={classes.tileContainer}>
|
||||
<Link className={classes.link} to={linkToRecord(basePath, id, 'show')}>
|
||||
{record.imageUrl ? (
|
||||
<img src={record.imageUrl} alt={record.title} className={classes.cover} />
|
||||
<img
|
||||
src={record.imageUrl}
|
||||
srcSet={buildSrcSet(record.images)}
|
||||
sizes="(max-width: 600px) 50vw, (max-width: 960px) 33vw, (max-width: 1280px) 25vw, 20vw"
|
||||
alt={record.title}
|
||||
className={classes.cover}
|
||||
/>
|
||||
) : (
|
||||
<div className={classes.placeholder}>
|
||||
<MicIcon className={classes.placeholderIcon} style={{ fontSize: 48, color: '#888' }} />
|
||||
|
|
|
|||
|
|
@ -42,11 +42,18 @@ const PodcastFilter = (props) => (
|
|||
</Filter>
|
||||
)
|
||||
|
||||
const bestImageUrl = (record, targetWidth) => {
|
||||
if (!record.images || record.images.length === 0) return record.imageUrl
|
||||
const sorted = [...record.images].sort((a, b) => a.width - b.width)
|
||||
const best = sorted.find((img) => img.width >= targetWidth) || sorted[sorted.length - 1]
|
||||
return best ? best.url : record.imageUrl
|
||||
}
|
||||
|
||||
const CoverArtField = ({ record }) => {
|
||||
if (!record) return null
|
||||
if (record.imageUrl) {
|
||||
return (
|
||||
<Avatar src={record.imageUrl} variant="rounded" style={{ width: 55, height: 55 }} alt={record.title} />
|
||||
<Avatar src={bestImageUrl(record, 55)} variant="rounded" style={{ width: 55, height: 55 }} alt={record.title} />
|
||||
)
|
||||
}
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -88,6 +88,11 @@ const useStyles = makeStyles((theme) => ({
|
|||
tableWrapper: { marginTop: theme.spacing(2), overflowX: 'auto' },
|
||||
}))
|
||||
|
||||
const buildSrcSet = (images) => {
|
||||
if (!images || images.length === 0) return undefined
|
||||
return images.map((img) => `${img.url} ${img.width}w`).join(', ')
|
||||
}
|
||||
|
||||
const formatDuration = (seconds) => {
|
||||
if (!seconds) return ''
|
||||
const h = Math.floor(seconds / 3600)
|
||||
|
|
@ -153,6 +158,8 @@ const PodcastShow = (props) => {
|
|||
{record.imageUrl ? (
|
||||
<img
|
||||
src={record.imageUrl}
|
||||
srcSet={buildSrcSet(record.images)}
|
||||
sizes="192px"
|
||||
alt={record.title}
|
||||
style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: 4 }}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue