Nicer context menus

This commit is contained in:
James Barnsley
2017-01-27 16:13:11 +13:00
parent 31472ae564
commit cd17467ced
8 changed files with 150 additions and 54 deletions

View File

@ -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 (
<div className="title" style={style}>
{image ? <img src={image} /> : null}
{this.props.context_menu.data.item.name}
</div>
)
}
renderItems(trigger){
var items = this.getItems(trigger)
@ -254,7 +277,8 @@ class ContextMenu extends React.Component{
return (
<div className={className} style={style}>
{ this.renderItems(trigger) }
{this.renderTitle()}
{this.renderItems(trigger)}
</div>
);
}

View File

@ -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 (
<div onClick={ e => this.handleClick(e, row.uri)} className={className} key={row_index}>
<div
onClick={e => 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{
</div>
);
}
}
}
const mapStateToProps = (state, ownProps) => {
return {}
}
const mapDispatchToProps = (dispatch) => {
return {
uiActions: bindActionCreators(uiActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(List)

View File

@ -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{
<div className={className}>
{
this.props.playlists.map(
(playlist, index) => {
return <GridItem item={playlist} key={index} link={global.baseURL+'playlist/'+playlist.uri} />
(playlist, index) => {
return (
<Link
className="grid-item"
to={global.baseURL+'playlist/'+playlist.uri}
key={index}
onContextMenu={e => this.handleContextMenu(e,playlist)}>
<Thumbnail size="medium" images={playlist.images} />
<div className="name">{ playlist.name }</div>
<div className="secondary">
{ playlist.tracks_total ? playlist.tracks_total+' tracks' : <span>0 tracks</span> }
{ playlist.can_edit ? <FontAwesome name="edit" /> : null }
</div>
</Link>
)
}
)
}
@ -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)

View File

@ -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 (
<Link to={global.baseURL+'user/'+this.props.item.owner.id}>
{ this.props.item.owner.id }
</Link>
);
}
render(){
if( !this.props.item ) return null
return (
<ListItem extraClasses="playlist" link={global.baseURL+'playlist/'+this.props.item.uri}>
<span className="col name">
{this.props.item.name}
</span>
<span className="col owner">
{ this.renderOwner() }
</span>
<span className="col source">
<ItemSource uri={this.props.item.uri} />
</span>
</ListItem>
);
}
}

View File

@ -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')

View File

@ -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 (
<section className="list-wrapper">
<List rows={albums} columns={columns} link_prefix={global.baseURL+"album/"} />
<List
handleContextMenu={(e,uri) => this.handleContextMenu(e,uri)}
rows={albums}
columns={columns}
link_prefix={global.baseURL+"album/"} />
</section>
)
}else if( this.props.view == 'thumbnails' ){
return (
<section className="grid-wrapper">
<AlbumGrid albums={albums} />
<AlbumGrid
handleContextMenu={(e,uri) => this.handleContextMenu(e,uri)}
albums={albums} />
</section>
)
}else{

View File

@ -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 (
<section className="list-wrapper">
<List rows={artists} columns={columns} link_prefix={global.baseURL+"artist/"} show_source_icon={true} />
<List
handleContextMenu={(e,uri) => this.handleContextMenu(e,uri)}
rows={artists}
columns={columns}
link_prefix={global.baseURL+"artist/"} show_source_icon={true} />
</section>
)
}else{
return (
<section className="grid-wrapper">
<ArtistGrid artists={artists} />
<ArtistGrid
handleContextMenu={(e,uri) => this.handleContextMenu(e,uri)}
artists={artists} />
</section>
)
}

View File

@ -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;