178 lines
4.4 KiB
JavaScript
178 lines
4.4 KiB
JavaScript
import React from 'react'
|
|
import {
|
|
GridList,
|
|
GridListTile,
|
|
Typography,
|
|
GridListTileBar,
|
|
useMediaQuery,
|
|
} from '@material-ui/core'
|
|
import { makeStyles } from '@material-ui/core/styles'
|
|
import withWidth from '@material-ui/core/withWidth'
|
|
import { Link } from 'react-router-dom'
|
|
import { linkToRecord, Loading } from 'react-admin'
|
|
import { withContentRect } from 'react-measure'
|
|
import subsonic from '../subsonic'
|
|
import {
|
|
AlbumContextMenu,
|
|
PlayButton,
|
|
ArtistLinkField,
|
|
RangeField,
|
|
} from '../common'
|
|
|
|
const useStyles = makeStyles((theme) => ({
|
|
root: {
|
|
margin: '20px',
|
|
},
|
|
tileBar: {
|
|
transition: 'all 150ms ease-out',
|
|
opacity: 0,
|
|
textAlign: 'left',
|
|
marginBottom: '3px',
|
|
background:
|
|
'linear-gradient(to top, rgba(0,0,0,0.7) 0%,rgba(0,0,0,0.4) 70%,rgba(0,0,0,0) 100%)',
|
|
},
|
|
tileBarMobile: {
|
|
textAlign: 'left',
|
|
marginBottom: '3px',
|
|
background:
|
|
'linear-gradient(to top, rgba(0,0,0,0.7) 0%,rgba(0,0,0,0.4) 70%,rgba(0,0,0,0) 100%)',
|
|
},
|
|
albumArtistName: {
|
|
whiteSpace: 'nowrap',
|
|
overflow: 'hidden',
|
|
textOverflow: 'ellipsis',
|
|
textAlign: 'left',
|
|
fontSize: '1em',
|
|
},
|
|
albumName: {
|
|
fontSize: '14px',
|
|
color: theme.palette.type === 'dark' ? '#eee' : 'black',
|
|
overflow: 'hidden',
|
|
whiteSpace: 'nowrap',
|
|
textOverflow: 'ellipsis',
|
|
},
|
|
albumSubtitle: {
|
|
fontSize: '12px',
|
|
color: theme.palette.type === 'dark' ? '#c5c5c5' : '#696969',
|
|
overflow: 'hidden',
|
|
whiteSpace: 'nowrap',
|
|
textOverflow: 'ellipsis',
|
|
},
|
|
link: {
|
|
position: 'relative',
|
|
display: 'block',
|
|
textDecoration: 'none',
|
|
'&:hover $tileBar': {
|
|
opacity: 1,
|
|
},
|
|
},
|
|
albumLink: {
|
|
position: 'relative',
|
|
display: 'block',
|
|
textDecoration: 'none',
|
|
},
|
|
}))
|
|
|
|
const useCoverStyles = makeStyles({
|
|
cover: {
|
|
display: 'inline-block',
|
|
width: '100%',
|
|
height: (props) => props.height,
|
|
},
|
|
})
|
|
|
|
const getColsForWidth = (width) => {
|
|
if (width === 'xs') return 2
|
|
if (width === 'sm') return 3
|
|
if (width === 'md') return 4
|
|
if (width === 'lg') return 6
|
|
return 9
|
|
}
|
|
|
|
const Cover = withContentRect('bounds')(
|
|
({ album, measureRef, contentRect }) => {
|
|
// Force height to be the same as the width determined by the GridList
|
|
// noinspection JSSuspiciousNameCombination
|
|
const classes = useCoverStyles({ height: contentRect.bounds.width })
|
|
return (
|
|
<div ref={measureRef}>
|
|
<img
|
|
src={subsonic.url('getCoverArt', album.coverArtId || 'not_found', {
|
|
size: 300,
|
|
})}
|
|
alt={album.album}
|
|
className={classes.cover}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
)
|
|
|
|
const AlbumGridTile = ({ showArtist, record, basePath }) => {
|
|
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
|
|
const classes = useStyles()
|
|
|
|
return (
|
|
<div>
|
|
<Link
|
|
className={classes.link}
|
|
to={linkToRecord(basePath, record.id, 'show')}
|
|
>
|
|
<Cover album={record} />
|
|
<GridListTileBar
|
|
className={isDesktop ? classes.tileBar : classes.tileBarMobile}
|
|
subtitle={<PlayButton color={'white'} record={record} size="small" />}
|
|
actionIcon={<AlbumContextMenu record={record} color={'white'} />}
|
|
/>
|
|
</Link>
|
|
<Link
|
|
className={classes.albumLink}
|
|
to={linkToRecord(basePath, record.id, 'show')}
|
|
>
|
|
<Typography className={classes.albumName}>{record.name}</Typography>
|
|
{showArtist ? (
|
|
<ArtistLinkField record={record} className={classes.albumSubtitle} />
|
|
) : (
|
|
<RangeField
|
|
record={record}
|
|
source={'year'}
|
|
sortBy={'maxYear'}
|
|
sortByOrder={'DESC'}
|
|
className={classes.albumSubtitle}
|
|
/>
|
|
)}
|
|
</Link>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const LoadedAlbumGrid = ({ ids, data, basePath, width, isArtistView }) => {
|
|
const classes = useStyles()
|
|
|
|
return (
|
|
<div className={classes.root}>
|
|
<GridList
|
|
component={'div'}
|
|
cellHeight={'auto'}
|
|
cols={getColsForWidth(width)}
|
|
spacing={20}
|
|
>
|
|
{ids.map((id) => (
|
|
<GridListTile className={classes.gridListTile} key={id}>
|
|
<AlbumGridTile
|
|
record={data[id]}
|
|
basePath={basePath}
|
|
showArtist={!isArtistView}
|
|
/>
|
|
</GridListTile>
|
|
))}
|
|
</GridList>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const AlbumGridView = ({ loading, ...props }) =>
|
|
loading ? <Loading /> : <LoadedAlbumGrid {...props} />
|
|
|
|
export default withWidth()(AlbumGridView)
|