feat(ui): add CoverArtAvatar component and integrate it into artist and playlist lists
Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
@@ -22,6 +22,7 @@ import { useDrag } from 'react-dnd'
|
||||
import clsx from 'clsx'
|
||||
import {
|
||||
ArtistContextMenu,
|
||||
CoverArtAvatar,
|
||||
List,
|
||||
QuickFilter,
|
||||
useGetHandleArtistClick,
|
||||
@@ -43,6 +44,10 @@ const useStyles = makeStyles({
|
||||
verticalAlign: 'text-top',
|
||||
},
|
||||
row: {
|
||||
'& td': {
|
||||
paddingTop: '4px !important',
|
||||
paddingBottom: '4px !important',
|
||||
},
|
||||
'&:hover': {
|
||||
'& $contextMenu': {
|
||||
visibility: 'visible',
|
||||
@@ -170,6 +175,7 @@ const ArtistListView = ({ hasShow, hasEdit, hasList, width, ...rest }) => {
|
||||
/>
|
||||
) : (
|
||||
<ArtistDatagrid rowClick={handleArtistLink} classes={{ row: classes.row }}>
|
||||
<CoverArtAvatar source="id" />
|
||||
<TextField source="name" />
|
||||
<FunctionField
|
||||
source="albumCount"
|
||||
|
||||
@@ -2,12 +2,13 @@ import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import List from '@material-ui/core/List'
|
||||
import ListItem from '@material-ui/core/ListItem'
|
||||
import ListItemAvatar from '@material-ui/core/ListItemAvatar'
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction'
|
||||
import ListItemText from '@material-ui/core/ListItemText'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import { sanitizeListRestProps } from 'react-admin'
|
||||
import { ArtistContextMenu, RatingField } from '../common'
|
||||
import { ArtistContextMenu, CoverArtAvatar, RatingField } from '../common'
|
||||
import config from '../config'
|
||||
|
||||
const useStyles = makeStyles(
|
||||
@@ -47,7 +48,11 @@ const ArtistSimpleList = ({
|
||||
data[id] && (
|
||||
<span key={id} onClick={() => linkType(id)}>
|
||||
<ListItem className={classes.listItem} button={true}>
|
||||
<ListItemAvatar>
|
||||
<CoverArtAvatar record={data[id]} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
style={{ marginLeft: '8px' }}
|
||||
primary={
|
||||
<>
|
||||
<div className={classes.title}>{data[id].name}</div>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useRecordContext } from 'react-admin'
|
||||
import { Avatar } from '@material-ui/core'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import clsx from 'clsx'
|
||||
import subsonic from '../subsonic'
|
||||
|
||||
const useStyles = makeStyles({
|
||||
avatar: {
|
||||
width: '55px',
|
||||
height: '55px',
|
||||
},
|
||||
square: {
|
||||
borderRadius: '4px',
|
||||
},
|
||||
})
|
||||
|
||||
export const CoverArtAvatar = ({
|
||||
record: recordProp,
|
||||
variant = 'circular',
|
||||
}) => {
|
||||
const classes = useStyles()
|
||||
const recordContext = useRecordContext()
|
||||
const record = recordProp || recordContext
|
||||
if (!record) return null
|
||||
const square = variant !== 'circular'
|
||||
return (
|
||||
<Avatar
|
||||
src={subsonic.getCoverArtUrl(record, 80, square)}
|
||||
variant={variant}
|
||||
className={clsx(classes.avatar, square && classes.square)}
|
||||
alt={record.name}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
CoverArtAvatar.defaultProps = { label: '', sortable: false }
|
||||
@@ -44,3 +44,4 @@ export * from './ParticipantsInfo'
|
||||
export * from './OverflowTooltip'
|
||||
export * from './useSearchRefocus'
|
||||
export * from './ImageUploadOverlay'
|
||||
export * from './CoverArtAvatar'
|
||||
|
||||
@@ -16,10 +16,10 @@ import {
|
||||
usePermissions,
|
||||
} from 'react-admin'
|
||||
import Switch from '@material-ui/core/Switch'
|
||||
import { Avatar } from '@material-ui/core'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import { useMediaQuery } from '@material-ui/core'
|
||||
import {
|
||||
CoverArtAvatar,
|
||||
DurationField,
|
||||
List,
|
||||
Writable,
|
||||
@@ -29,17 +29,11 @@ import {
|
||||
} from '../common'
|
||||
import PlaylistListActions from './PlaylistListActions'
|
||||
import ChangePublicStatusButton from './ChangePublicStatusButton'
|
||||
import subsonic from '../subsonic'
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
button: {
|
||||
color: theme.palette.type === 'dark' ? 'white' : undefined,
|
||||
},
|
||||
coverArt: {
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
borderRadius: '4px',
|
||||
},
|
||||
}))
|
||||
|
||||
const PlaylistFilter = (props) => {
|
||||
@@ -126,25 +120,6 @@ const ToggleAutoImport = ({ resource, source }) => {
|
||||
) : null
|
||||
}
|
||||
|
||||
const CoverArtField = () => {
|
||||
const classes = useStyles()
|
||||
const record = useRecordContext()
|
||||
if (!record) return null
|
||||
return (
|
||||
<Avatar
|
||||
src={subsonic.getCoverArtUrl(record, 80, true)}
|
||||
variant="square"
|
||||
className={classes.coverArt}
|
||||
alt={record.name}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
CoverArtField.defaultProps = {
|
||||
label: '',
|
||||
sortable: false,
|
||||
}
|
||||
|
||||
const PlaylistListBulkActions = (props) => {
|
||||
const classes = useStyles()
|
||||
return (
|
||||
@@ -204,7 +179,7 @@ const PlaylistList = (props) => {
|
||||
bulkActionButtons={!isXsmall && <PlaylistListBulkActions />}
|
||||
>
|
||||
<Datagrid rowClick="show" isRowSelectable={(r) => isWritable(r?.ownerId)}>
|
||||
<CoverArtField source="id" />
|
||||
<CoverArtAvatar source="id" variant="square" />
|
||||
<TextField source="name" />
|
||||
{columns}
|
||||
<Writable>
|
||||
|
||||
Reference in New Issue
Block a user