Album and Artist grids with context menus
This commit is contained in:
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user