diff --git a/src/js/components/ContextMenu.js b/src/js/components/ContextMenu.js index c30f9638..4a728f5c 100755 --- a/src/js/components/ContextMenu.js +++ b/src/js/components/ContextMenu.js @@ -166,6 +166,14 @@ class ContextMenu extends React.Component{ ] break + case 'playlist': + var items = [ + { handleClick: 'playURIs', label: 'Play', icon: 'play' }, + { handleClick: 'toggleFollow', label: 'Follow/unfollow', icon: 'toggle-on' }, + { handleClick: 'copyURIs', label: 'Copy URI', icon: 'copy' } + ] + break + default: var items = [ { handleClick: 'playURIs', label: 'Play', icon: 'play' }, @@ -180,6 +188,21 @@ class ContextMenu extends React.Component{ return items } + renderTitle(){ + var style = {} + var item = this.props.context_menu.data.item + var image = null + if (item && item.images){ + image = helpers.sizedImages(item.images).medium + } + return ( +
+ {image ? : null} + {this.props.context_menu.data.item.name} +
+ ) + } + renderItems(trigger){ var items = this.getItems(trigger) @@ -254,7 +277,8 @@ class ContextMenu extends React.Component{ return (
- { this.renderItems(trigger) } + {this.renderTitle()} + {this.renderItems(trigger)}
); } diff --git a/src/js/components/List.js b/src/js/components/List.js index a24303bc..88f2de74 100755 --- a/src/js/components/List.js +++ b/src/js/components/List.js @@ -1,14 +1,17 @@ import React, { PropTypes } from 'react' -import { Link, hashHistory } from 'react-router' +import { connect } from 'react-redux' +import { createStore, bindActionCreators } from 'redux' +import { hashHistory, Link } from 'react-router' import FontAwesome from 'react-fontawesome' import ArtistSentence from './ArtistSentence' import Dater from './Dater' import * as helpers from '../helpers' +import * as uiActions from '../services/ui/actions' -export default class List extends React.Component{ +class List extends React.Component{ constructor(props) { super(props); @@ -22,6 +25,12 @@ export default class List extends React.Component{ } } + handleContextMenu(e,uri){ + e.preventDefault() + var data = { uris: [uri] } + this.props.uiActions.showContextMenu(e, data, helpers.uriType(uri), 'click') + } + renderHeader(){ if (!this.props.columns || this.props.noheader) return null @@ -71,7 +80,11 @@ export default class List extends React.Component{ if( row.type ) className += ' '+row.type return ( -
this.handleClick(e, row.uri)} className={className} key={row_index}> +
this.handleClick(e, row.uri)} + onContextMenu={e => this.handleContextMenu(e,row.uri)} + className={className} + key={row_index}> { this.props.columns.map( (col, col_index) => { return ( @@ -89,4 +102,16 @@ export default class List extends React.Component{
); } -} \ No newline at end of file +} + +const mapStateToProps = (state, ownProps) => { + return {} +} + +const mapDispatchToProps = (dispatch) => { + return { + uiActions: bindActionCreators(uiActions, dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(List) diff --git a/src/js/components/PlaylistGrid.js b/src/js/components/PlaylistGrid.js index f8d703c3..6ce3924a 100755 --- a/src/js/components/PlaylistGrid.js +++ b/src/js/components/PlaylistGrid.js @@ -1,13 +1,29 @@ import React, { PropTypes } from 'react' -import GridItem from './GridItem' +import { connect } from 'react-redux' +import { createStore, bindActionCreators } from 'redux' +import { Link } from 'react-router' +import FontAwesome from 'react-fontawesome' -export default class PlaylistGrid extends React.Component{ +import Thumbnail from './Thumbnail' + +import * as uiActions from '../services/ui/actions' + +class PlaylistGrid extends React.Component{ constructor(props) { super(props); } + handleContextMenu(e,item){ + e.preventDefault() + var data = { + uris: [item.uri], + item: item + } + this.props.uiActions.showContextMenu( e, data, 'playlist', 'click' ) + } + render(){ if( !this.props.playlists ) return null @@ -17,8 +33,21 @@ export default class PlaylistGrid extends React.Component{
{ this.props.playlists.map( - (playlist, index) => { - return + (playlist, index) => { + return ( + this.handleContextMenu(e,playlist)}> + +
{ playlist.name }
+
+ { playlist.tracks_total ? playlist.tracks_total+' tracks' : 0 tracks } + { playlist.can_edit ? : null } +
+ + ) } ) } @@ -27,3 +56,15 @@ export default class PlaylistGrid extends React.Component{ } } +const mapStateToProps = (state, ownProps) => { + return {} +} + +const mapDispatchToProps = (dispatch) => { + return { + uiActions: bindActionCreators(uiActions, dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(PlaylistGrid) + diff --git a/src/js/components/PlaylistListItem.js b/src/js/components/PlaylistListItem.js deleted file mode 100755 index f9639176..00000000 --- a/src/js/components/PlaylistListItem.js +++ /dev/null @@ -1,41 +0,0 @@ - -import React, { PropTypes } from 'react' -import FontAwesome from 'react-fontawesome' -import { Link } from 'react-router' - -import ListItem from './ListItem' -import ItemSource from './ItemSource' - -export default class PlaylistListItem extends React.Component{ - - constructor(props) { - super(props); - } - - renderOwner(){ - if( !this.props.item.owner ) return null; - return ( - - { this.props.item.owner.id } - - ); - } - - render(){ - if( !this.props.item ) return null - - return ( - - - {this.props.item.name} - - - { this.renderOwner() } - - - - - - ); - } -} \ No newline at end of file diff --git a/src/js/services/mopidy/middleware.js b/src/js/services/mopidy/middleware.js index 7782d204..db0654c4 100755 --- a/src/js/services/mopidy/middleware.js +++ b/src/js/services/mopidy/middleware.js @@ -3,6 +3,7 @@ import Mopidy from 'mopidy' import * as helpers from '../../helpers' var mopidyActions = require('./actions.js') +var uiActions = require('../ui/actions.js') var lastfmActions = require('../lastfm/actions.js') var pusherActions = require('../pusher/actions.js') diff --git a/src/js/views/library/LibraryAlbums.js b/src/js/views/library/LibraryAlbums.js index e4b75dfd..ccbcb21b 100755 --- a/src/js/views/library/LibraryAlbums.js +++ b/src/js/views/library/LibraryAlbums.js @@ -28,6 +28,12 @@ class LibraryAlbums extends React.Component{ if (!this.props.library_albums) this.props.spotifyActions.getLibraryAlbums(); } + handleContextMenu(e,uri){ + e.preventDefault() + var data = { uris: [uri] } + this.props.uiActions.showContextMenu( e, data, 'album', 'click' ) + } + loadMore(){ this.props.spotifyActions.getURL( this.props.library_albums_more, 'SPOTIFY_LIBRARY_ALBUMS_LOADED' ); } @@ -76,13 +82,19 @@ class LibraryAlbums extends React.Component{ ] return (
- + this.handleContextMenu(e,uri)} + rows={albums} + columns={columns} + link_prefix={global.baseURL+"album/"} />
) }else if( this.props.view == 'thumbnails' ){ return (
- + this.handleContextMenu(e,uri)} + albums={albums} />
) }else{ diff --git a/src/js/views/library/LibraryArtists.js b/src/js/views/library/LibraryArtists.js index f1d8ec2f..3d994b1f 100755 --- a/src/js/views/library/LibraryArtists.js +++ b/src/js/views/library/LibraryArtists.js @@ -21,6 +21,12 @@ class LibraryArtists extends React.Component{ super(props); } + handleContextMenu(e,uri){ + e.preventDefault() + var data = { uris: [uri] } + this.props.uiActions.showContextMenu( e, data, 'artist', 'click' ) + } + componentDidMount(){ if (!this.props.library_artists) this.props.spotifyActions.getLibraryArtists(); } @@ -61,13 +67,19 @@ class LibraryArtists extends React.Component{ ] return (
- + this.handleContextMenu(e,uri)} + rows={artists} + columns={columns} + link_prefix={global.baseURL+"artist/"} show_source_icon={true} />
) }else{ return (
- + this.handleContextMenu(e,uri)} + artists={artists} />
) } diff --git a/src/scss/components/_context-menu.scss b/src/scss/components/_context-menu.scss index 7c4c6207..31142f8d 100755 --- a/src/scss/components/_context-menu.scss +++ b/src/scss/components/_context-menu.scss @@ -21,6 +21,28 @@ bottom: 0 !important; } + .title { + cursor: pointer; + display: block; + padding: 8px 12px; + width: 100%; + font-weight: bold; + box-sizing: border-box; + position: relative; + overflow: hidden; + + img { + @include blur(5px); + background-size: cover; + background-position: 50% 0%; + opacity: 0.2; + position: absolute; + top: 0; + left: 0; + right: 0; + } + } + .menu-item-wrapper { display: block; position: relative;