diff --git a/ui/src/App.js b/ui/src/App.js index 97c27843..7643d98c 100644 --- a/ui/src/App.js +++ b/ui/src/App.js @@ -13,6 +13,7 @@ import album from './album' import artist from './artist' import { createMuiTheme } from '@material-ui/core/styles' import { Player, playQueueReducer } from './audioplayer' +import { albumViewReducer } from './album/albumState' const theme = createMuiTheme(DarkTheme) @@ -34,7 +35,10 @@ const App = () => { return ( ({ + root: { + margin: '5px' + }, + cover: { + display: 'inline-block', + maxWidth: '100%', + height: 'auto' + }, + tileBar: { + textAlign: 'center', + background: + 'linear-gradient(to top, rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.4) 70%,rgba(0,0,0,0) 100%)' + }, + albumArtistName: { + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', + textAlign: 'center', + fontSize: '1em' + } +})) + +const getColsForWidth = (width) => { + if (width === 'xs') return 2 + if (width === 'sm') return 4 + if (width === 'md') return 5 + if (width === 'lg') return 6 + return 7 +} + +const LoadedAlbumGrid = ({ ids, data, basePath, width }) => { + const classes = useStyles() + return ( +
+ + {ids.map((id) => ( + + {data[id].album} + +
+ {data[id].albumArtist} +
+ + } + /> +
+ ))} +
+
+ ) +} + +const AlbumGridView = ({ loading, ...props }) => + loading ? : + +export default withWidth()(AlbumGridView) diff --git a/ui/src/album/AlbumList.js b/ui/src/album/AlbumList.js index 8ece0d64..f081bce5 100644 --- a/ui/src/album/AlbumList.js +++ b/ui/src/album/AlbumList.js @@ -1,23 +1,21 @@ import React from 'react' +import { useSelector } from 'react-redux' import { - BooleanField, - Datagrid, - DateField, + AutocompleteInput, Filter, List, - NumberField, - FunctionField, - SearchInput, - NumberInput, NullableBooleanInput, - Show, - SimpleShowLayout, + NumberInput, ReferenceInput, - AutocompleteInput, - TextField + SearchInput, + Pagination } from 'react-admin' -import { DurationField, Pagination, Title, RangeField } from '../common' -import { useMediaQuery } from '@material-ui/core' +import { Title } from '../common' +import { withWidth } from '@material-ui/core' +import AlbumListActions from './AlbumListActions' +import AlbumListView from './AlbumListView' +import AlbumGridView from './AlbumGridView' +import { ALBUM_LIST_MODE } from './albumState' const AlbumFilter = (props) => ( @@ -35,21 +33,27 @@ const AlbumFilter = (props) => ( ) -const AlbumDetails = (props) => { - return ( - - - - - - - - - ) +const getPerPage = (width) => { + if (width === 'xs') return 12 + if (width === 'sm') return 12 + if (width === 'md') return 15 + if (width === 'lg') return 18 + return 21 +} + +const getPerPageOptions = (width) => { + const options = [3, 6, 12] + if (width === 'xs') return [12] + if (width === 'sm') return [12] + if (width === 'md') return options.map((v) => v * 5) + if (width === 'lg') return options.map((v) => v * 6) + return options.map((v) => v * 7) } const AlbumList = (props) => { - const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md')) + const { width } = props + const albumView = useSelector((state) => state.albumView) + return ( { sort={{ field: 'name', order: 'ASC' }} exporter={false} bulkActionButtons={false} + actions={} filters={} - perPage={15} - pagination={} + perPage={getPerPage(width)} + pagination={ + + } > - } rowClick={'show'}> - - (r.albumArtist ? r.albumArtist : r.artist)} - /> - {isDesktop && } - - {isDesktop && } - + {albumView.mode === ALBUM_LIST_MODE ? ( + + ) : ( + + )} ) } -export default AlbumList + +export default withWidth()(AlbumList) diff --git a/ui/src/album/AlbumListActions.js b/ui/src/album/AlbumListActions.js new file mode 100644 index 00000000..739706d5 --- /dev/null +++ b/ui/src/album/AlbumListActions.js @@ -0,0 +1,69 @@ +import React, { cloneElement } from 'react' +import { Button, sanitizeListRestProps, TopToolbar } from 'react-admin' +import { ButtonGroup } from '@material-ui/core' +import ViewHeadlineIcon from '@material-ui/icons/ViewHeadline' +import ViewModuleIcon from '@material-ui/icons/ViewModule' +import { useDispatch, useSelector } from 'react-redux' +import { ALBUM_GRID_MODE, ALBUM_LIST_MODE, selectViewMode } from './albumState' + +const AlbumListActions = ({ + currentSort, + className, + resource, + filters, + displayedFilters, + filterValues, + permanentFilter, + exporter, + basePath, + selectedIds, + onUnselectItems, + showFilter, + maxResults, + total, + fullWidth, + ...rest +}) => { + const dispatch = useDispatch() + const albumView = useSelector((state) => state.albumView) + + return ( + + {filters && + cloneElement(filters, { + resource, + showFilter, + displayedFilters, + filterValues, + context: 'button' + })} + + + + + + ) +} + +AlbumListActions.defaultProps = { + selectedIds: [], + onUnselectItems: () => null +} + +export default AlbumListActions diff --git a/ui/src/album/AlbumListView.js b/ui/src/album/AlbumListView.js new file mode 100644 index 00000000..d772a29a --- /dev/null +++ b/ui/src/album/AlbumListView.js @@ -0,0 +1,43 @@ +import React from 'react' +import { + BooleanField, + Datagrid, + DateField, + NumberField, + FunctionField, + Show, + SimpleShowLayout, + TextField +} from 'react-admin' +import { DurationField, RangeField } from '../common' +import { useMediaQuery } from '@material-ui/core' + +const AlbumDetails = (props) => { + return ( + + + + + + + + + ) +} + +const AlbumListView = (props) => { + const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md')) + return ( + } rowClick={'show'}> + + (r.albumArtist ? r.albumArtist : r.artist)} + /> + {isDesktop && } + + {isDesktop && } + + ) +} +export default AlbumListView diff --git a/ui/src/album/albumState.js b/ui/src/album/albumState.js new file mode 100644 index 00000000..f2ed109a --- /dev/null +++ b/ui/src/album/albumState.js @@ -0,0 +1,23 @@ +const ALBUM_GRID_MODE = 'ALBUM_GRID_MODE' +const ALBUM_LIST_MODE = 'ALBUM_LIST_MODE' + +const selectViewMode = (mode) => ({ type: mode }) + +const albumViewReducer = ( + previousState = { + mode: localStorage.getItem('albumViewMode') || ALBUM_LIST_MODE + }, + payload +) => { + const { type } = payload + switch (type) { + case ALBUM_GRID_MODE: + case ALBUM_LIST_MODE: + localStorage.setItem('albumViewMode', type) + return { mode: type } + default: + return previousState + } +} + +export { ALBUM_LIST_MODE, ALBUM_GRID_MODE, albumViewReducer, selectViewMode } diff --git a/ui/src/layout/AppBar.js b/ui/src/layout/AppBar.js index 729a1332..130db4e1 100644 --- a/ui/src/layout/AppBar.js +++ b/ui/src/layout/AppBar.js @@ -1,12 +1,12 @@ -import React, { forwardRef } from 'react'; +import React, { forwardRef } from 'react' import { AppBar as RAAppBar, UserMenu, MenuItemLink } from 'react-admin' -import InfoIcon from '@material-ui/icons/Info'; +import InfoIcon from '@material-ui/icons/Info' const ConfigurationMenu = forwardRef(({ onClick }, ref) => ( } onClick={onClick} />