mirror of
https://github.com/navidrome/navidrome.git
synced 2025-12-23 23:18:05 -05:00
The bulk action buttons (Make Public, Make Private, Delete) on the playlists list were displaying with poor text contrast when using dark themes like AMusic. The buttons had pinkish text (theme's primary color) on a dark red background, making them difficult to read. This fix applies the same styling pattern used for song bulk actions by adding a makeStyles hook that sets white text color for dark themes. This ensures proper contrast between the button text and background while maintaining correct styling on light themes. Tested on AMusic (dark) and Light themes to verify contrast improvement and backward compatibility. Signed-off-by: Deluan <deluan@navidrome.org>
189 lines
4.3 KiB
JavaScript
189 lines
4.3 KiB
JavaScript
import React, { useMemo } from 'react'
|
|
import {
|
|
Datagrid,
|
|
DateField,
|
|
EditButton,
|
|
Filter,
|
|
NumberField,
|
|
ReferenceInput,
|
|
SearchInput,
|
|
SelectInput,
|
|
TextField,
|
|
useUpdate,
|
|
useNotify,
|
|
useRecordContext,
|
|
BulkDeleteButton,
|
|
usePermissions,
|
|
} from 'react-admin'
|
|
import Switch from '@material-ui/core/Switch'
|
|
import { makeStyles } from '@material-ui/core/styles'
|
|
import { useMediaQuery } from '@material-ui/core'
|
|
import {
|
|
DurationField,
|
|
List,
|
|
Writable,
|
|
isWritable,
|
|
useSelectedFields,
|
|
useResourceRefresh,
|
|
} from '../common'
|
|
import PlaylistListActions from './PlaylistListActions'
|
|
import ChangePublicStatusButton from './ChangePublicStatusButton'
|
|
|
|
const useStyles = makeStyles((theme) => ({
|
|
button: {
|
|
color: theme.palette.type === 'dark' ? 'white' : undefined,
|
|
},
|
|
}))
|
|
|
|
const PlaylistFilter = (props) => {
|
|
const { permissions } = usePermissions()
|
|
return (
|
|
<Filter {...props} variant={'outlined'}>
|
|
<SearchInput source="q" alwaysOn />
|
|
{permissions === 'admin' && (
|
|
<ReferenceInput
|
|
source="owner_id"
|
|
label={'resources.playlist.fields.ownerName'}
|
|
reference="user"
|
|
perPage={0}
|
|
sort={{ field: 'name', order: 'ASC' }}
|
|
alwaysOn
|
|
>
|
|
<SelectInput optionText="name" />
|
|
</ReferenceInput>
|
|
)}
|
|
</Filter>
|
|
)
|
|
}
|
|
|
|
const TogglePublicInput = ({ resource, source }) => {
|
|
const record = useRecordContext()
|
|
const notify = useNotify()
|
|
const [togglePublic] = useUpdate(
|
|
resource,
|
|
record.id,
|
|
{
|
|
...record,
|
|
public: !record.public,
|
|
},
|
|
{
|
|
undoable: false,
|
|
onFailure: (error) => {
|
|
notify('ra.page.error', 'warning')
|
|
},
|
|
},
|
|
)
|
|
|
|
const handleClick = (e) => {
|
|
togglePublic()
|
|
e.stopPropagation()
|
|
}
|
|
|
|
return (
|
|
<Switch
|
|
checked={record[source]}
|
|
onClick={handleClick}
|
|
disabled={!isWritable(record.ownerId)}
|
|
/>
|
|
)
|
|
}
|
|
|
|
const ToggleAutoImport = ({ resource, source }) => {
|
|
const record = useRecordContext()
|
|
const notify = useNotify()
|
|
const [ToggleAutoImport] = useUpdate(
|
|
resource,
|
|
record.id,
|
|
{
|
|
...record,
|
|
sync: !record.sync,
|
|
},
|
|
{
|
|
undoable: false,
|
|
onFailure: (error) => {
|
|
notify('ra.page.error', 'warning')
|
|
},
|
|
},
|
|
)
|
|
const handleClick = (e) => {
|
|
ToggleAutoImport()
|
|
e.stopPropagation()
|
|
}
|
|
|
|
return record.path ? (
|
|
<Switch
|
|
checked={record[source]}
|
|
onClick={handleClick}
|
|
disabled={!isWritable(record.ownerId)}
|
|
/>
|
|
) : null
|
|
}
|
|
|
|
const PlaylistListBulkActions = (props) => {
|
|
const classes = useStyles()
|
|
return (
|
|
<>
|
|
<ChangePublicStatusButton
|
|
public={true}
|
|
{...props}
|
|
className={classes.button}
|
|
/>
|
|
<ChangePublicStatusButton
|
|
public={false}
|
|
{...props}
|
|
className={classes.button}
|
|
/>
|
|
<BulkDeleteButton {...props} className={classes.button} />
|
|
</>
|
|
)
|
|
}
|
|
|
|
const PlaylistList = (props) => {
|
|
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
|
|
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
|
|
useResourceRefresh('playlist')
|
|
|
|
const toggleableFields = useMemo(
|
|
() => ({
|
|
ownerName: isDesktop && <TextField source="ownerName" />,
|
|
songCount: !isXsmall && <NumberField source="songCount" />,
|
|
duration: <DurationField source="duration" />,
|
|
updatedAt: isDesktop && (
|
|
<DateField source="updatedAt" sortByOrder={'DESC'} />
|
|
),
|
|
public: !isXsmall && (
|
|
<TogglePublicInput source="public" sortByOrder={'DESC'} />
|
|
),
|
|
comment: <TextField source="comment" />,
|
|
sync: <ToggleAutoImport source="sync" sortByOrder={'DESC'} />,
|
|
}),
|
|
[isDesktop, isXsmall],
|
|
)
|
|
|
|
const columns = useSelectedFields({
|
|
resource: 'playlist',
|
|
columns: toggleableFields,
|
|
defaultOff: ['comment'],
|
|
})
|
|
|
|
return (
|
|
<List
|
|
{...props}
|
|
exporter={false}
|
|
filters={<PlaylistFilter />}
|
|
actions={<PlaylistListActions />}
|
|
bulkActionButtons={!isXsmall && <PlaylistListBulkActions />}
|
|
>
|
|
<Datagrid rowClick="show" isRowSelectable={(r) => isWritable(r?.ownerId)}>
|
|
<TextField source="name" />
|
|
{columns}
|
|
<Writable>
|
|
<EditButton />
|
|
</Writable>
|
|
</Datagrid>
|
|
</List>
|
|
)
|
|
}
|
|
|
|
export default PlaylistList
|