parent
e2a4d8bc24
commit
fba3d73484
10 changed files with 303 additions and 48 deletions
@ -0,0 +1,101 @@ |
||||
import React from 'react'; |
||||
import MuiAppBar from '@material-ui/core/AppBar'; |
||||
import Toolbar from '@material-ui/core/Toolbar'; |
||||
import IconButton from '@material-ui/core/IconButton'; |
||||
import Typography from '@material-ui/core/Typography'; |
||||
import InputBase from '@material-ui/core/InputBase'; |
||||
import { createStyles, fade, Theme, makeStyles } from '@material-ui/core/styles'; |
||||
import MenuIcon from '@material-ui/icons/Menu'; |
||||
import SearchIcon from '@material-ui/icons/Search'; |
||||
|
||||
const useStyles = makeStyles((theme: Theme) => |
||||
createStyles({ |
||||
root: { |
||||
flexGrow: 1, |
||||
}, |
||||
menuButton: { |
||||
marginRight: theme.spacing(2), |
||||
}, |
||||
title: { |
||||
flexGrow: 1, |
||||
display: 'none', |
||||
[theme.breakpoints.up('sm')]: { |
||||
display: 'block', |
||||
}, |
||||
}, |
||||
search: { |
||||
position: 'relative', |
||||
borderRadius: theme.shape.borderRadius, |
||||
backgroundColor: fade(theme.palette.common.white, 0.15), |
||||
'&:hover': { |
||||
backgroundColor: fade(theme.palette.common.white, 0.25), |
||||
}, |
||||
marginLeft: 0, |
||||
width: '100%', |
||||
[theme.breakpoints.up('sm')]: { |
||||
marginLeft: theme.spacing(1), |
||||
width: 'auto', |
||||
}, |
||||
}, |
||||
searchIcon: { |
||||
padding: theme.spacing(0, 2), |
||||
height: '100%', |
||||
position: 'absolute', |
||||
pointerEvents: 'none', |
||||
display: 'flex', |
||||
alignItems: 'center', |
||||
justifyContent: 'center', |
||||
}, |
||||
inputRoot: { |
||||
color: 'inherit', |
||||
}, |
||||
inputInput: { |
||||
padding: theme.spacing(1, 1, 1, 0), |
||||
// vertical padding + font size from searchIcon
|
||||
paddingLeft: `calc(1em + ${theme.spacing(4)}px)`, |
||||
transition: theme.transitions.create('width'), |
||||
width: '100%', |
||||
[theme.breakpoints.up('sm')]: { |
||||
width: '12ch', |
||||
'&:focus': { |
||||
width: '20ch', |
||||
}, |
||||
}, |
||||
}, |
||||
}), |
||||
); |
||||
|
||||
export default function AppBar() { |
||||
const classes = useStyles(); |
||||
|
||||
return ( |
||||
<div className={classes.root}> |
||||
<MuiAppBar position="static"> |
||||
<Toolbar> |
||||
<IconButton |
||||
edge="start" |
||||
className={classes.menuButton} |
||||
color="inherit" |
||||
aria-label="open drawer" |
||||
> |
||||
<MenuIcon /> |
||||
</IconButton> |
||||
<Typography className={classes.title} variant="h6" noWrap>MuDBase</Typography> |
||||
<div className={classes.search}> |
||||
<div className={classes.searchIcon}> |
||||
<SearchIcon /> |
||||
</div> |
||||
<InputBase |
||||
placeholder="Search…" |
||||
classes={{ |
||||
root: classes.inputRoot, |
||||
input: classes.inputInput, |
||||
}} |
||||
inputProps={{ 'aria-label': 'search' }} |
||||
/> |
||||
</div> |
||||
</Toolbar> |
||||
</MuiAppBar> |
||||
</div> |
||||
); |
||||
} |
@ -0,0 +1,24 @@ |
||||
import React from 'react'; |
||||
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'; |
||||
import List from '@material-ui/core/List'; |
||||
|
||||
const useStyles = makeStyles((theme: Theme) => |
||||
createStyles({ |
||||
root: { |
||||
flexGrow: 1, |
||||
maxWidth: 752, |
||||
}, |
||||
}), |
||||
); |
||||
|
||||
export default function ItemList(props:any) { |
||||
const classes = useStyles(); |
||||
|
||||
return ( |
||||
<div className={classes.root}> |
||||
<List dense={true}> |
||||
{props.children} |
||||
</List> |
||||
</div> |
||||
); |
||||
} |
@ -0,0 +1,15 @@ |
||||
import React from 'react'; |
||||
import { DisplayItem, isSong, isLoadingSong } from '../types/DisplayItem'; |
||||
import ItemListLoadedSongItem from './ItemListLoadedSongItem'; |
||||
import ItemListLoadingSongItem from './ItemListLoadingSongItem'; |
||||
|
||||
export interface IProps { |
||||
item: DisplayItem |
||||
} |
||||
|
||||
export default function ItemListItem(props: IProps) { |
||||
return <> |
||||
{isSong(props.item) && <ItemListLoadedSongItem item={props.item}/>} |
||||
{isLoadingSong(props.item) && <ItemListLoadingSongItem item={props.item}/>} |
||||
</> |
||||
} |
@ -0,0 +1,30 @@ |
||||
import React from 'react'; |
||||
import ListItem from '@material-ui/core/ListItem'; |
||||
import ListItemIcon from '@material-ui/core/ListItemIcon'; |
||||
import ListItemText from '@material-ui/core/ListItemText'; |
||||
import MusicNoteIcon from '@material-ui/icons/MusicNote'; |
||||
|
||||
import { SongDisplayItem } from '../types/DisplayItem'; |
||||
|
||||
export interface IProps { |
||||
item: SongDisplayItem |
||||
} |
||||
|
||||
export default function ItemListLoadedSongItem(props: IProps) { |
||||
var artists = props.item.artistNames.length ? props.item.artistNames[0] : "Unknown"; |
||||
for(var i:number=1; i<props.item.artistNames.length; i++) { |
||||
artists = artists.concat(", " + props.item.artistNames[i]); |
||||
} |
||||
|
||||
return ( |
||||
<ListItem> |
||||
<ListItemIcon> |
||||
<MusicNoteIcon /> |
||||
</ListItemIcon> |
||||
<ListItemText |
||||
primary={props.item.title} |
||||
secondary={artists} |
||||
/> |
||||
</ListItem> |
||||
); |
||||
} |
@ -0,0 +1,22 @@ |
||||
import React from 'react'; |
||||
import ListItem from '@material-ui/core/ListItem'; |
||||
import ListItemIcon from '@material-ui/core/ListItemIcon'; |
||||
import MusicNoteIcon from '@material-ui/icons/MusicNote'; |
||||
import CircularProgress from '@material-ui/core/CircularProgress'; |
||||
|
||||
import { LoadingSongDisplayItem } from '../types/DisplayItem'; |
||||
|
||||
export interface IProps { |
||||
item: LoadingSongDisplayItem |
||||
} |
||||
|
||||
export default function ItemListLoadingSongItem(props: IProps) { |
||||
return ( |
||||
<ListItem> |
||||
<ListItemIcon> |
||||
<MusicNoteIcon /> |
||||
</ListItemIcon> |
||||
<CircularProgress size={24}/> |
||||
</ListItem> |
||||
); |
||||
} |
@ -0,0 +1,18 @@ |
||||
import React, { useEffect } from 'react'; |
||||
import ItemListItem from './ItemListItem'; |
||||
import { SongDisplayItem, LoadingSongDisplayItem } from '../types/DisplayItem'; |
||||
|
||||
export interface IProps { |
||||
getDetails: () => Promise<SongDisplayItem> |
||||
} |
||||
|
||||
export default function ItemListSongItem(props: IProps) { |
||||
const [ song, setSong ] = React.useState<SongDisplayItem | LoadingSongDisplayItem>({ loadingSong: true }); |
||||
|
||||
useEffect(() => { |
||||
props.getDetails() |
||||
.then((details:SongDisplayItem) => { setSong(details); }); |
||||
}); |
||||
|
||||
return <ItemListItem item={song}/> |
||||
} |
@ -0,0 +1,18 @@ |
||||
export interface SongDisplayItem { |
||||
title:String, |
||||
artistNames:String[], |
||||
} |
||||
|
||||
export interface LoadingSongDisplayItem { |
||||
loadingSong: boolean, |
||||
} |
||||
|
||||
export type DisplayItem = SongDisplayItem | LoadingSongDisplayItem; |
||||
|
||||
export function isSong(item: DisplayItem): item is SongDisplayItem { |
||||
return "title" in item; |
||||
} |
||||
|
||||
export function isLoadingSong(item: DisplayItem): item is LoadingSongDisplayItem { |
||||
return "loadingSong" in item; |
||||
} |
Loading…
Reference in new issue