Initial support for album browsing from UI

This commit is contained in:
Deluan 2020-01-22 12:46:09 -05:00
parent ea30b4c2d9
commit b23175e32b
6 changed files with 159 additions and 5 deletions

View file

@ -3,7 +3,7 @@ import React from 'react'
import { Admin, Resource } from 'react-admin'
import dataProvider from './dataProvider'
import authProvider from './authProvider'
import { Login } from './layout'
import { Login, Layout } from './layout'
import user from './user'
import song from './song'
import album from './album'
@ -12,10 +12,11 @@ const App = () => (
<Admin
dataProvider={dataProvider}
authProvider={authProvider}
layout={Layout}
loginPage={Login}
>
<Resource name="song" {...song} />
<Resource name="album" {...album} />
<Resource name="song" {...song} options={{ subMenu: 'library' }} />
<Resource name="album" {...album} options={{ subMenu: 'library' }} />
<Resource name="user" {...user} />
</Admin>
)

View file

@ -12,7 +12,7 @@ import {
SimpleShowLayout,
TextField
} from 'react-admin'
import { BitrateField, DurationField, Title } from '../common'
import { DurationField, Title } from '../common'
const AlbumFilter = (props) => (
<Filter {...props}>

5
ui/src/layout/Layout.js Normal file
View file

@ -0,0 +1,5 @@
import React from 'react'
import { Layout } from 'react-admin'
import Menu from './Menu'
export default (props) => <Layout {...props} menu={Menu} />

73
ui/src/layout/Menu.js Normal file
View file

@ -0,0 +1,73 @@
// in src/Menu.js
import React, { useState, createElement } from 'react'
import { useSelector } from 'react-redux'
import { useMediaQuery } from '@material-ui/core'
import { useTranslate, MenuItemLink, getResources } from 'react-admin'
import { withRouter } from 'react-router-dom'
import LibraryMusicIcon from '@material-ui/icons/LibraryMusic'
import ViewListIcon from '@material-ui/icons/ViewList'
import SubMenu from './SubMenu'
import inflection from 'inflection'
const translatedResourceName = (resource, translate) =>
translate(`resources.${resource.name}.name`, {
smart_count: 2,
_:
resource.options && resource.options.label
? translate(resource.options.label, {
smart_count: 2,
_: resource.options.label
})
: inflection.humanize(inflection.pluralize(resource.name))
})
const Menu = ({ onMenuClick, dense, logout }) => {
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
const open = useSelector((state) => state.admin.ui.sidebarOpen)
const translate = useTranslate()
const resources = useSelector(getResources)
const [state, setState] = useState({
menuLibrary: true
})
const handleToggle = (menu) => {
setState((state) => ({ ...state, [menu]: !state[menu] }))
}
const renderMenuItemLink = (resource) => (
<MenuItemLink
key={resource.name}
to={`/${resource.name}`}
primaryText={translatedResourceName(resource, translate)}
leftIcon={
(resource.icon && createElement(resource.icon)) || <ViewListIcon />
}
onClick={onMenuClick}
sidebarIsOpen={open}
dense={dense}
/>
)
const subItems = (subMenu) => (resource) =>
resource.hasList && resource.options && resource.options.subMenu === subMenu
return (
<div>
<SubMenu
handleToggle={() => handleToggle('menuLibrary')}
isOpen={state.menuLibrary}
sidebarIsOpen={open}
name="Library"
icon={<LibraryMusicIcon />}
dense={dense}
>
{resources.filter(subItems('library')).map(renderMenuItemLink)}
</SubMenu>
{resources.filter(subItems(undefined)).map(renderMenuItemLink)}
{isXsmall && logout}
</div>
)
}
export default withRouter(Menu)

74
ui/src/layout/SubMenu.js Normal file
View file

@ -0,0 +1,74 @@
import React, { Fragment } from 'react'
import ExpandMore from '@material-ui/icons/ExpandMore'
import List from '@material-ui/core/List'
import MenuItem from '@material-ui/core/MenuItem'
import ListItemIcon from '@material-ui/core/ListItemIcon'
import Typography from '@material-ui/core/Typography'
import Divider from '@material-ui/core/Divider'
import Collapse from '@material-ui/core/Collapse'
import Tooltip from '@material-ui/core/Tooltip'
import { makeStyles } from '@material-ui/core/styles'
import { useTranslate } from 'react-admin'
const useStyles = makeStyles((theme) => ({
icon: { minWidth: theme.spacing(5) },
sidebarIsOpen: {
paddingLeft: 25,
transition: 'padding-left 195ms cubic-bezier(0.4, 0, 0.6, 1) 0ms'
},
sidebarIsClosed: {
paddingLeft: 0,
transition: 'padding-left 195ms cubic-bezier(0.4, 0, 0.6, 1) 0ms'
}
}))
const SubMenu = ({
handleToggle,
sidebarIsOpen,
isOpen,
name,
icon,
children,
dense
}) => {
const translate = useTranslate()
const classes = useStyles()
const header = (
<MenuItem dense={dense} button onClick={handleToggle}>
<ListItemIcon className={classes.icon}>
{isOpen ? <ExpandMore /> : icon}
</ListItemIcon>
<Typography variant="inherit" color="textSecondary">
{translate(name)}
</Typography>
</MenuItem>
)
return (
<Fragment>
{sidebarIsOpen || isOpen ? (
header
) : (
<Tooltip title={translate(name)} placement="right">
{header}
</Tooltip>
)}
<Collapse in={isOpen} timeout="auto" unmountOnExit>
<List
dense={dense}
component="div"
disablePadding
className={
sidebarIsOpen ? classes.sidebarIsOpen : classes.sidebarIsClosed
}
>
{children}
</List>
<Divider />
</Collapse>
</Fragment>
)
}
export default SubMenu

View file

@ -1,3 +1,4 @@
import Login from './Login'
import Layout from './Layout'
export { Login }
export { Layout, Login }