Artist page improvements (#1391)

* Seperate mobile desktop components

* Fix err

* Rename classes and fix some styles

* Add lastFM button and remove console log

* Add Mbiz Icon

* render bio as dangerouslySetInnerHTML and remove unused css classes

* Add Fav and Stars

* Remove unstandardised class selector

* Remove ext link from m view

* Fix naming and simplify rounded styling

* Refactor ArtistShow:

- Extracted DesktopArtistDetails to its own file
- Removed album count as it was incorrect, it is not considering compilations
- Show bio and image from Native API, if it is available, before calling `getArtistInfo`

Co-authored-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Dnouv
2021-10-16 06:32:11 +05:30
committed by GitHub
parent 7505b5c554
commit 1d742cf8c7
8 changed files with 343 additions and 257 deletions
+21 -241
View File
@@ -1,11 +1,6 @@
import React, { useState, useEffect, useCallback } from 'react'
import { Typography, Collapse, Link } from '@material-ui/core'
import { makeStyles } from '@material-ui/core/styles'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
import CardMedia from '@material-ui/core/CardMedia'
import React, { useState, createElement, useEffect } from 'react'
import { useMediaQuery } from '@material-ui/core'
import {
useTranslate,
useShowController,
ShowContextProvider,
useRecordContext,
@@ -14,152 +9,22 @@ import {
} from 'react-admin'
import subsonic from '../subsonic'
import AlbumGridView from '../album/AlbumGridView'
import MobileArtistDetails from './MobileArtistDetails'
import DesktopArtistDetails from './DesktopArtistDetails'
const useStyles = makeStyles(
(theme) => ({
root: {
display: 'flex',
padding: '1em',
'& .MuiTypography-h5': {
wordBreak: 'break-word',
},
[theme.breakpoints.down('xs')]: {
padding: 'unset',
background: ({ img }) => `url(${img})`,
},
},
bgContainer: {
display: 'flex',
width: '100%',
[theme.breakpoints.down('xs')]: {
height: '15rem',
width: '100vw',
padding: 'unset',
backdropFilter: 'blur(1px)',
backgroundPosition: '50% 30%',
background: `linear-gradient(to bottom, rgba(52 52 52 / 72%), rgba(21 21 21))`,
},
},
albumList: {
margin: '20px',
display: 'grid',
},
details: {
display: 'flex',
flex: '1',
flexDirection: 'column',
},
bioBlock: {
display: 'inline-block',
marginTop: '1em',
float: 'left',
wordBreak: 'break-word',
cursor: 'pointer',
},
link: {
margin: '1px',
},
mdetails: {
display: 'none',
[theme.breakpoints.down('xs')]: {
display: 'flex',
alignItems: 'center',
width: '7rem',
marginLeft: '0.5rem',
flex: '1',
},
},
mbio: {
display: 'none',
[theme.breakpoints.down('xs')]: {
display: 'flex',
marginLeft: '3%',
marginRight: '3%',
zIndex: '1',
'& p': {
whiteSpace: ({ expanded }) => (expanded ? 'unset' : 'nowrap'),
overflow: 'hidden',
width: '95vw',
textOverflow: 'ellipsis',
},
},
},
content: {
flex: '1 0 auto',
},
cover: {
width: 151,
boxShadow: '0px 0px 6px 0px #565656',
borderRadius: '5px',
[theme.breakpoints.up('sm')]: {
borderRadius: '7em',
},
},
martImage: {
marginLeft: '1em',
maxHeight: '10rem',
backgroundColor: 'inherit',
display: 'none',
[theme.breakpoints.down('xs')]: {
marginTop: '4rem',
maxHeight: '7rem',
width: '7rem',
display: 'flex',
},
},
artImage: {
maxHeight: '9.5rem',
backgroundColor: 'inherit',
display: 'flex',
[theme.breakpoints.down('xs')]: {
marginTop: '4rem',
maxHeight: '7rem',
width: '7rem',
},
},
artDetail: {
flex: '1',
padding: '3%',
display: 'flex',
minHeight: '10rem',
'& .MuiPaper-elevation1': {
boxShadow: 'none',
padding: '4px',
},
[theme.breakpoints.down('xs')]: {
display: 'none',
},
},
artistSummary: {
marginBottom: '1em',
},
}),
{ name: 'NDArtistPage' }
)
const ArtistDetails = () => {
const ArtistDetails = (props) => {
const record = useRecordContext(props)
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('sm'))
const [artistInfo, setArtistInfo] = useState()
const [expanded, setExpanded] = useState(false)
const record = useRecordContext()
const artistId = record?.id
const title = record.name
let completeBioLink = ''
const link = artistInfo?.biography?.match(
/<a\s+(?:[^>]*?\s+)?href=(["'])(.*?)\1/
)
if (link) {
completeBioLink = link[2]
}
const biography = artistInfo?.biography?.replace(new RegExp('<.*>', 'g'), '')
const translate = useTranslate()
const img = artistInfo?.largeImageUrl
const classes = useStyles({ img, expanded })
const biography =
artistInfo?.biography?.replace(new RegExp('<.*>', 'g'), '') ||
record.biography
const img = artistInfo?.largeImageUrl || record.largeImageUrl
useEffect(() => {
subsonic
.getArtistInfo(artistId)
.getArtistInfo(record.id)
.then((resp) => resp.json['subsonic-response'])
.then((data) => {
if (data.status === 'ok') {
@@ -169,106 +34,21 @@ const ArtistDetails = () => {
.catch((e) => {
console.error('error on artist page', e)
})
}, [artistId, record])
const handleExpandClick = useCallback(() => {
setExpanded(!expanded)
}, [expanded, setExpanded])
}, [record])
const component = isDesktop ? DesktopArtistDetails : MobileArtistDetails
return (
<>
<div className={classes.root}>
<div className={classes.bgContainer}>
<Card className={classes.martImage}>
{artistInfo && (
<CardMedia
className={classes.cover}
image={`${artistInfo.mediumImageUrl}`}
title={title}
/>
)}
</Card>
<div className={classes.mdetails}>
<Typography component="h5" variant="h5">
{title}
</Typography>
</div>
<Card className={classes.artDetail}>
<Card className={classes.artImage}>
{artistInfo && (
<CardMedia
className={classes.cover}
image={`${artistInfo.mediumImageUrl}`}
title={title}
/>
)}
</Card>
<div className={classes.details}>
<CardContent className={classes.content}>
<Typography component="h5" variant="h5">
{title}
</Typography>
<Collapse
collapsedHeight={'4.5em'}
in={expanded}
timeout={'auto'}
className={classes.bioBlock}
>
<Typography variant={'body1'} onClick={handleExpandClick}>
<span dangerouslySetInnerHTML={{ __html: biography }} />
{completeBioLink !== '' && (
<Link
href={completeBioLink}
className={classes.link}
target="_blank"
rel="nofollow"
>
{translate('message.lastfmLink')}
</Link>
)}
</Typography>
</Collapse>
</CardContent>
</div>
</Card>
</div>
</div>
<div className={classes.mbio}>
<Collapse collapsedHeight={'1.5em'} in={expanded} timeout={'auto'}>
<Typography variant={'body1'} onClick={handleExpandClick}>
{biography}
<Link
href={completeBioLink}
className={classes.link}
target="_blank"
rel="nofollow"
>
{translate('message.lastfmLink')}
</Link>
</Typography>
</Collapse>
</div>
{createElement(component, {
img,
artistInfo,
record,
biography,
})}
</>
)
}
const ArtistAlbums = ({ ...props }) => {
const { ids } = props
const classes = useStyles()
const translate = useTranslate()
return (
<div className={classes.albumList}>
<div className={classes.artistSummary}>
{ids.length +
' ' +
translate('resources.album.name', { smart_count: ids.length })}
</div>
<AlbumGridView {...props} />
</div>
)
}
const AlbumShowLayout = (props) => {
const showContext = useShowContext(props)
const record = useRecordContext()
@@ -287,7 +67,7 @@ const AlbumShowLayout = (props) => {
perPage={0}
pagination={null}
>
<ArtistAlbums />
<AlbumGridView {...props} />
</ReferenceManyField>
)}
</>