Only show SongContextMenu on hover
This commit is contained in:
@@ -14,8 +14,12 @@ import { useDispatch } from 'react-redux'
|
|||||||
import { Card, useMediaQuery } from '@material-ui/core'
|
import { Card, useMediaQuery } from '@material-ui/core'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import { playTracks } from '../audioplayer'
|
import { playTracks } from '../audioplayer'
|
||||||
import { DurationField, SongDetails, SongDatagridRow } from '../common'
|
import {
|
||||||
import { SongContextMenu } from '../song/SongContextMenu'
|
DurationField,
|
||||||
|
SongDetails,
|
||||||
|
SongDatagridRow,
|
||||||
|
SongContextMenu,
|
||||||
|
} from '../common'
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
(theme) => ({
|
(theme) => ({
|
||||||
|
|||||||
@@ -9,17 +9,24 @@ import StarIcon from '@material-ui/icons/Star'
|
|||||||
import StarBorderIcon from '@material-ui/icons/StarBorder'
|
import StarBorderIcon from '@material-ui/icons/StarBorder'
|
||||||
import NestedMenuItem from 'material-ui-nested-menu-item'
|
import NestedMenuItem from 'material-ui-nested-menu-item'
|
||||||
import { addTracks, setTrack } from '../audioplayer'
|
import { addTracks, setTrack } from '../audioplayer'
|
||||||
import { AddToPlaylistMenu } from '../common'
|
import AddToPlaylistMenu from './AddToPlaylistMenu'
|
||||||
import config from '../config'
|
import config from '../config'
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
noWrap: {
|
noWrap: {
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
},
|
},
|
||||||
|
menu: {
|
||||||
|
visibility: (props) => (props.visible ? 'visible' : 'hidden'),
|
||||||
|
},
|
||||||
|
star: {
|
||||||
|
visibility: (props) =>
|
||||||
|
props.visible || props.starred ? 'visible' : 'hidden',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const SongContextMenu = ({ className, record, onAddToPlaylist }) => {
|
const SongContextMenu = ({ record, onAddToPlaylist, visible }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles({ visible, starred: record.starred })
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const translate = useTranslate()
|
const translate = useTranslate()
|
||||||
const notify = useNotify()
|
const notify = useNotify()
|
||||||
@@ -54,7 +61,7 @@ export const SongContextMenu = ({ className, record, onAddToPlaylist }) => {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
const [toggleStar, { toggling: loading }] = useUpdate(
|
const [updateRecord, { loading: updating }] = useUpdate(
|
||||||
'albumSong',
|
'albumSong',
|
||||||
record.id,
|
record.id,
|
||||||
record,
|
record,
|
||||||
@@ -68,26 +75,36 @@ export const SongContextMenu = ({ className, record, onAddToPlaylist }) => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleToggleStar = (e, record) => {
|
const toggleStar = (record) => {
|
||||||
record.starred = !record.starred
|
record.starred = !record.starred
|
||||||
toggleStar()
|
updateRecord()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleToggleStar = (e, record) => {
|
||||||
|
toggleStar(record)
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
const open = Boolean(anchorEl)
|
const open = Boolean(anchorEl)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={`${classes.noWrap} ${className}`}>
|
<span className={classes.noWrap}>
|
||||||
{config.enableStarred && !onAddToPlaylist && (
|
{config.enableStarred && !onAddToPlaylist && (
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={(e) => handleToggleStar(e, record)}
|
onClick={(e) => handleToggleStar(e, record)}
|
||||||
size={'small'}
|
size={'small'}
|
||||||
disabled={loading}
|
disabled={updating}
|
||||||
|
className={classes.star}
|
||||||
>
|
>
|
||||||
{record.starred ? <StarIcon /> : <StarBorderIcon />}
|
{record.starred ? <StarIcon /> : <StarBorderIcon />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
<IconButton onClick={handleClick} size={'small'}>
|
<IconButton
|
||||||
|
onClick={handleClick}
|
||||||
|
size={'small'}
|
||||||
|
className={classes.menu}
|
||||||
|
disabled={updating}
|
||||||
|
>
|
||||||
<MoreVertIcon />
|
<MoreVertIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Menu
|
<Menu
|
||||||
@@ -119,4 +136,7 @@ export const SongContextMenu = ({ className, record, onAddToPlaylist }) => {
|
|||||||
SongContextMenu.propTypes = {
|
SongContextMenu.propTypes = {
|
||||||
record: PropTypes.object,
|
record: PropTypes.object,
|
||||||
onAddToPlaylist: PropTypes.func,
|
onAddToPlaylist: PropTypes.func,
|
||||||
|
visible: PropTypes.bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default SongContextMenu
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
import React from 'react'
|
import React, { useState, isValidElement, cloneElement } from 'react'
|
||||||
import { DatagridRow, useTranslate } from 'react-admin'
|
import { DatagridRow, useTranslate } from 'react-admin'
|
||||||
import { TableRow, TableCell, Typography } from '@material-ui/core'
|
import { TableCell, TableRow, Typography } from '@material-ui/core'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import RangeField from './RangeField'
|
import RangeField from './RangeField'
|
||||||
|
|
||||||
const SongDatagridRow = ({ record, children, multiDisc, ...rest }) => {
|
const SongDatagridRow = ({ record, children, multiDisc, ...rest }) => {
|
||||||
const translate = useTranslate()
|
const translate = useTranslate()
|
||||||
|
const [visible, setVisible] = useState(false)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{multiDisc && (
|
{multiDisc && (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
{record.trackNumber === 1 && (
|
{record.trackNumber === 1 && (
|
||||||
<TableCell colSpan={children.length + 1}>
|
<TableCell colSpan={children.length + 2}>
|
||||||
<Typography variant="h6">
|
<Typography variant="h6">
|
||||||
{record.discSubtitle
|
{record.discSubtitle
|
||||||
? translate('message.discSubtitle', {
|
? translate('message.discSubtitle', {
|
||||||
@@ -26,8 +27,19 @@ const SongDatagridRow = ({ record, children, multiDisc, ...rest }) => {
|
|||||||
)}
|
)}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
<DatagridRow record={record} {...rest}>
|
<DatagridRow
|
||||||
{children}
|
record={record}
|
||||||
|
onMouseEnter={() => setVisible(true)}
|
||||||
|
onMouseLeave={() => setVisible(false)}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{React.Children.map(children, (child) =>
|
||||||
|
child &&
|
||||||
|
isValidElement(child) &&
|
||||||
|
child.type.name === 'SongContextMenu'
|
||||||
|
? cloneElement(child, { visible, ...rest })
|
||||||
|
: child
|
||||||
|
)}
|
||||||
</DatagridRow>
|
</DatagridRow>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import DocLink from './DocLink'
|
|||||||
import List from './List'
|
import List from './List'
|
||||||
import SongDatagridRow from './SongDatagridRow'
|
import SongDatagridRow from './SongDatagridRow'
|
||||||
import AddToPlaylistMenu from './AddToPlaylistMenu'
|
import AddToPlaylistMenu from './AddToPlaylistMenu'
|
||||||
|
import SongContextMenu from './SongContextMenu'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Title,
|
Title,
|
||||||
@@ -30,4 +31,5 @@ export {
|
|||||||
ArtistLinkField,
|
ArtistLinkField,
|
||||||
artistLink,
|
artistLink,
|
||||||
AddToPlaylistMenu,
|
AddToPlaylistMenu,
|
||||||
|
SongContextMenu,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from 'react'
|
|||||||
import {
|
import {
|
||||||
BulkActionsToolbar,
|
BulkActionsToolbar,
|
||||||
Datagrid,
|
Datagrid,
|
||||||
|
DatagridBody,
|
||||||
DatagridLoading,
|
DatagridLoading,
|
||||||
ListToolbar,
|
ListToolbar,
|
||||||
TextField,
|
TextField,
|
||||||
@@ -11,8 +12,12 @@ import {
|
|||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { Card, useMediaQuery } from '@material-ui/core'
|
import { Card, useMediaQuery } from '@material-ui/core'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import { DurationField, SongDetails } from '../common'
|
import {
|
||||||
import { SongContextMenu } from '../song/SongContextMenu'
|
DurationField,
|
||||||
|
SongDetails,
|
||||||
|
SongContextMenu,
|
||||||
|
SongDatagridRow,
|
||||||
|
} from '../common'
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
(theme) => ({
|
(theme) => ({
|
||||||
@@ -50,6 +55,13 @@ const useStylesListToolbar = makeStyles({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const SongsDatagridBody = (props) => (
|
||||||
|
<DatagridBody {...props} row={<SongDatagridRow />} />
|
||||||
|
)
|
||||||
|
const SongsDatagrid = (props) => (
|
||||||
|
<Datagrid {...props} body={<SongsDatagridBody />} />
|
||||||
|
)
|
||||||
|
|
||||||
const PlaylistSongs = (props) => {
|
const PlaylistSongs = (props) => {
|
||||||
const classes = useStyles(props)
|
const classes = useStyles(props)
|
||||||
const classesToolbar = useStylesListToolbar(props)
|
const classesToolbar = useStylesListToolbar(props)
|
||||||
@@ -106,7 +118,7 @@ const PlaylistSongs = (props) => {
|
|||||||
size={'small'}
|
size={'small'}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Datagrid
|
<SongsDatagrid
|
||||||
expand={!isXsmall && <SongDetails />}
|
expand={!isXsmall && <SongDetails />}
|
||||||
rowClick={null}
|
rowClick={null}
|
||||||
{...controllerProps}
|
{...controllerProps}
|
||||||
@@ -117,7 +129,7 @@ const PlaylistSongs = (props) => {
|
|||||||
{isDesktop && <TextField source="artist" />}
|
{isDesktop && <TextField source="artist" />}
|
||||||
<DurationField source="duration" />
|
<DurationField source="duration" />
|
||||||
<SongContextMenu onAddToPlaylist={onAddToPlaylist} />
|
<SongContextMenu onAddToPlaylist={onAddToPlaylist} />
|
||||||
</Datagrid>
|
</SongsDatagrid>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+18
-4
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
Datagrid,
|
Datagrid,
|
||||||
|
DatagridBody,
|
||||||
Filter,
|
Filter,
|
||||||
FunctionField,
|
FunctionField,
|
||||||
NumberField,
|
NumberField,
|
||||||
@@ -8,12 +9,18 @@ import {
|
|||||||
TextField,
|
TextField,
|
||||||
} from 'react-admin'
|
} from 'react-admin'
|
||||||
import { useMediaQuery } from '@material-ui/core'
|
import { useMediaQuery } from '@material-ui/core'
|
||||||
import { DurationField, SimpleList, List, SongDetails } from '../common'
|
import {
|
||||||
|
DurationField,
|
||||||
|
SimpleList,
|
||||||
|
List,
|
||||||
|
SongDetails,
|
||||||
|
SongDatagridRow,
|
||||||
|
SongContextMenu,
|
||||||
|
} from '../common'
|
||||||
import { useDispatch } from 'react-redux'
|
import { useDispatch } from 'react-redux'
|
||||||
import { setTrack } from '../audioplayer'
|
import { setTrack } from '../audioplayer'
|
||||||
import { SongBulkActions } from './SongBulkActions'
|
import { SongBulkActions } from './SongBulkActions'
|
||||||
import { AlbumLinkField } from './AlbumLinkField'
|
import { AlbumLinkField } from './AlbumLinkField'
|
||||||
import { SongContextMenu } from './SongContextMenu'
|
|
||||||
|
|
||||||
const SongFilter = (props) => (
|
const SongFilter = (props) => (
|
||||||
<Filter {...props}>
|
<Filter {...props}>
|
||||||
@@ -21,6 +28,13 @@ const SongFilter = (props) => (
|
|||||||
</Filter>
|
</Filter>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const SongsDatagridBody = (props) => (
|
||||||
|
<DatagridBody {...props} row={<SongDatagridRow />} />
|
||||||
|
)
|
||||||
|
const SongsDatagrid = (props) => (
|
||||||
|
<Datagrid {...props} body={<SongsDatagridBody />} />
|
||||||
|
)
|
||||||
|
|
||||||
const SongList = (props) => {
|
const SongList = (props) => {
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
|
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
|
||||||
@@ -48,7 +62,7 @@ const SongList = (props) => {
|
|||||||
rightIcon={(r) => <SongContextMenu record={r} />}
|
rightIcon={(r) => <SongContextMenu record={r} />}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Datagrid
|
<SongsDatagrid
|
||||||
expand={<SongDetails />}
|
expand={<SongDetails />}
|
||||||
rowClick={(id, basePath, record) => dispatch(setTrack(record))}
|
rowClick={(id, basePath, record) => dispatch(setTrack(record))}
|
||||||
>
|
>
|
||||||
@@ -62,7 +76,7 @@ const SongList = (props) => {
|
|||||||
)}
|
)}
|
||||||
<DurationField source="duration" />
|
<DurationField source="duration" />
|
||||||
<SongContextMenu />
|
<SongContextMenu />
|
||||||
</Datagrid>
|
</SongsDatagrid>
|
||||||
)}
|
)}
|
||||||
</List>
|
</List>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user