Album and Artist grids with context menus

This commit is contained in:
James Barnsley
2017-01-27 13:24:36 +13:00
parent c22c93428d
commit 31472ae564
6 changed files with 100 additions and 16 deletions

View File

@ -1,13 +1,33 @@
import React, { PropTypes } from 'react' import React, { PropTypes } from 'react'
import GridItem from './GridItem' import { connect } from 'react-redux'
import { createStore, bindActionCreators } from 'redux'
import { hashHistory } from 'react-router'
import FontAwesome from 'react-fontawesome'
export default class AlbumGrid extends React.Component{ import Thumbnail from './Thumbnail'
import ArtistSentence from './ArtistSentence'
import * as uiActions from '../services/ui/actions'
class AlbumGrid extends React.Component{
constructor(props) { constructor(props) {
super(props); super(props);
} }
handleClick(e,link){
if( e.target.tagName.toLowerCase() !== 'a' ){
hashHistory.push(link)
}
}
handleContextMenu(e,uri){
e.preventDefault()
var data = { uris: [uri] }
this.props.uiActions.showContextMenu( e, data, 'album', 'click' )
}
render(){ render(){
if( this.props.albums ){ if( this.props.albums ){
var className = "grid album-grid" var className = "grid album-grid"
@ -17,7 +37,18 @@ export default class AlbumGrid extends React.Component{
{ {
this.props.albums.map( this.props.albums.map(
(album, index) => { (album, index) => {
return <GridItem item={album} key={index} link={global.baseURL+'album/'+album.uri} /> return (
<div className="grid-item"
key={index}
onClick={ (e) => this.handleClick(e,global.baseURL+'album/'+album.uri) }
onContextMenu={e => this.handleContextMenu(e,album.uri)}>
<Thumbnail size="medium" images={album.images} />
<div className="name">{ album.name }</div>
<div className="secondary">
{ album.artists ? <ArtistSentence artists={album.artists} /> : <span>-</span> }
</div>
</div>
)
} }
) )
} }
@ -28,3 +59,15 @@ export default class AlbumGrid extends React.Component{
} }
} }
const mapStateToProps = (state, ownProps) => {
return {}
}
const mapDispatchToProps = (dispatch) => {
return {
uiActions: bindActionCreators(uiActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(AlbumGrid)

View File

@ -1,13 +1,25 @@
import React, { PropTypes } from 'react' import React, { PropTypes } from 'react'
import GridItem from './GridItem' import { connect } from 'react-redux'
import { createStore, bindActionCreators } from 'redux'
import { Link } from 'react-router'
export default class ArtistGrid extends React.Component{ import Thumbnail from './Thumbnail'
import * as uiActions from '../services/ui/actions'
class ArtistGrid extends React.Component{
constructor(props) { constructor(props) {
super(props); super(props);
} }
handleContextMenu(e,uri){
e.preventDefault()
var data = { uris: [uri] }
this.props.uiActions.showContextMenu( e, data, 'artist', 'click' )
}
render(){ render(){
if( this.props.artists ){ if( this.props.artists ){
var className = "grid artist-grid" var className = "grid artist-grid"
@ -17,7 +29,19 @@ export default class ArtistGrid extends React.Component{
{ {
this.props.artists.map( this.props.artists.map(
(artist, index) => { (artist, index) => {
return <GridItem item={artist} key={index} link={global.baseURL+'artist/'+artist.uri} /> return (
<Link
className="grid-item"
to={global.baseURL+'artist/'+artist.uri}
key={index}
onContextMenu={e => this.handleContextMenu(e,artist.uri)}>
<Thumbnail size="medium" images={artist.images} />
<div className="name">{ artist.name }</div>
<div className="secondary">
{artist.followers ? artist.followers.total.toLocaleString()+' followers' : <span>0 followers</span>}
</div>
</Link>
)
} }
) )
} }
@ -28,3 +52,15 @@ export default class ArtistGrid extends React.Component{
} }
} }
const mapStateToProps = (state, ownProps) => {
return {}
}
const mapDispatchToProps = (dispatch) => {
return {
uiActions: bindActionCreators(uiActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ArtistGrid)

View File

@ -154,7 +154,15 @@ class ContextMenu extends React.Component{
{ handleClick: 'playURIs', label: 'Play', icon: 'play' }, { handleClick: 'playURIs', label: 'Play', icon: 'play' },
{ handleClick: 'playURIsNext', label: 'Play next', icon: 'play' }, { handleClick: 'playURIsNext', label: 'Play next', icon: 'play' },
{ handleClick: 'addToQueue', label: 'Add to queue', icon: 'plus' }, { handleClick: 'addToQueue', label: 'Add to queue', icon: 'plus' },
{ handleClick: 'copyURIs', label: 'Copy URIs', icon: 'copy' } { handleClick: 'copyURIs', label: 'Copy URI', icon: 'copy' }
]
break
case 'artist':
var items = [
{ handleClick: 'startRadio', label: 'Start radio', icon: 'spotify' },
{ handleClick: 'toggleFollow', label: 'Follow/unfollow', icon: 'toggle-on' },
{ handleClick: 'copyURIs', label: 'Copy URI', icon: 'copy' }
] ]
break break

View File

@ -39,13 +39,6 @@ class Thumbnail extends React.Component{
return false return false
} }
handleContextMenu(e){
if (this.props.handleContextMenu){
e.preventDefault()
this.props.handleContextMenu(e)
}
}
mapImageSizes( props = this.props ){ mapImageSizes( props = this.props ){
// no images // no images
@ -82,7 +75,7 @@ class Thumbnail extends React.Component{
} }
return ( return (
<div className={class_name} onContextMenu={ e => this.handleContextMenu(e) }> <div className={class_name}>
<div className="image" style={style}></div> <div className="image" style={style}></div>
{zoom_icon} {zoom_icon}
</div> </div>

View File

@ -268,7 +268,7 @@ const MopidyMiddleware = (function(){
// add the rest of our uris (if any) // add the rest of our uris (if any)
action.uris.shift(); action.uris.shift();
if( action.uris.length > 0 ){ if( action.uris.length > 0 ){
store.dispatch( mopidyActions.enqueueTracks( action.uris, 1 ) ) store.dispatch( mopidyActions.enqueueURIs( action.uris, 1 ) )
} }
}) })
break; break;

View File

@ -16,6 +16,10 @@
.grid { .grid {
.grid-item-wrapper {
display: inline-block;
}
.grid-item { .grid-item {
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;