Revamp context menu; Specialist touch menu
This commit is contained in:
3
src/js/bootstrap.js
vendored
3
src/js/bootstrap.js
vendored
@ -54,9 +54,6 @@ var initialState = {
|
|||||||
me: false
|
me: false
|
||||||
},
|
},
|
||||||
ui: {
|
ui: {
|
||||||
context_menu: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
current_tracklist: [],
|
current_tracklist: [],
|
||||||
current_tltrack: false,
|
current_tltrack: false,
|
||||||
notifications: []
|
notifications: []
|
||||||
|
|||||||
@ -31,25 +31,21 @@ class ContextMenu extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleScroll(){
|
handleScroll(){
|
||||||
if( this.props.context_menu.show && this.props.context_menu.trigger == 'click' ){
|
if (this.props.menu) this.props.uiActions.hideContextMenu()
|
||||||
this.props.uiActions.hideContextMenu();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClick(){
|
handleClick(){
|
||||||
if( this.props.context_menu.show && this.props.context_menu.trigger == 'click' ){
|
if (this.props.menu) this.props.uiActions.hideContextMenu()
|
||||||
this.props.uiActions.hideContextMenu();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
playQueueItem(){
|
playQueueItem(){
|
||||||
var tracks = this.props.context_menu.data.items;
|
var tracks = this.props.menu.items;
|
||||||
this.props.mopidyActions.changeTrack( tracks[0].tlid );
|
this.props.mopidyActions.changeTrack( tracks[0].tlid );
|
||||||
this.props.uiActions.hideContextMenu();
|
this.props.uiActions.hideContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFromQueue(){
|
removeFromQueue(){
|
||||||
var tracks = this.props.context_menu.data.items;
|
var tracks = this.props.menu.items;
|
||||||
var tracks_tlids = [];
|
var tracks_tlids = [];
|
||||||
for( var i = 0; i < tracks.length; i++ ){
|
for( var i = 0; i < tracks.length; i++ ){
|
||||||
tracks_tlids.push( tracks[i].tlid );
|
tracks_tlids.push( tracks[i].tlid );
|
||||||
@ -59,48 +55,48 @@ class ContextMenu extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
playURIs(){
|
playURIs(){
|
||||||
this.props.mopidyActions.playURIs(this.props.context_menu.data.uris);
|
this.props.mopidyActions.playURIs(this.props.menu.uris);
|
||||||
this.props.uiActions.hideContextMenu();
|
this.props.uiActions.hideContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
playURIsNext(){
|
playURIsNext(){
|
||||||
this.props.mopidyActions.enqueueURIsNext(this.props.context_menu.data.uris);
|
this.props.mopidyActions.enqueueURIsNext(this.props.menu.uris);
|
||||||
this.props.uiActions.hideContextMenu();
|
this.props.uiActions.hideContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
addToPlaylist(){
|
addToPlaylist(){
|
||||||
this.props.uiActions.openModal( 'add_to_playlist', { tracks_uris: this.props.context_menu.data.uris } )
|
this.props.uiActions.openModal('add_to_playlist', { tracks_uris: this.props.menu.uris })
|
||||||
this.props.uiActions.hideContextMenu();
|
this.props.uiActions.hideContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
addToQueue(){
|
addToQueue(){
|
||||||
this.props.mopidyActions.enqueueURIs(this.props.context_menu.data.uris)
|
this.props.mopidyActions.enqueueURIs(this.props.menu.uris)
|
||||||
this.props.uiActions.hideContextMenu()
|
this.props.uiActions.hideContextMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
addTracksToPlaylist( playlist_uri ){
|
addTracksToPlaylist(playlist_uri){
|
||||||
this.props.uiActions.addTracksToPlaylist( playlist_uri, this.props.context_menu.data.uris )
|
this.props.uiActions.addTracksToPlaylist(playlist_uri, this.props.menu.uris)
|
||||||
this.props.uiActions.hideContextMenu();
|
this.props.uiActions.hideContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFromPlaylist(){
|
removeFromPlaylist(){
|
||||||
this.props.uiActions.removeTracksFromPlaylist( this.props.playlist.uri, this.props.context_menu.data.indexes )
|
this.props.uiActions.removeTracksFromPlaylist(this.props.menu.tracklist_uri, this.props.menu.indexes)
|
||||||
this.props.uiActions.hideContextMenu();
|
this.props.uiActions.hideContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
startRadio(){
|
startRadio(){
|
||||||
this.props.pusherActions.startRadio(this.props.context_menu.data.uris)
|
this.props.pusherActions.startRadio(this.props.menu.uris)
|
||||||
this.props.uiActions.hideContextMenu();
|
this.props.uiActions.hideContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
copyURIs(e){
|
copyURIs(e){
|
||||||
var temp = $("<input>");
|
var temp = $("<input>");
|
||||||
$("body").append(temp);
|
$("body").append(temp);
|
||||||
temp.val(this.props.context_menu.data.uris.join(',')).select();
|
temp.val(this.props.menu.uris.join(',')).select();
|
||||||
document.execCommand("copy");
|
document.execCommand("copy");
|
||||||
temp.remove();
|
temp.remove();
|
||||||
|
|
||||||
this.props.uiActions.createNotification( "Copied "+this.props.context_menu.data.uris.length+" URIs" )
|
this.props.uiActions.createNotification( "Copied "+this.props.menu.uris.length+" URIs" )
|
||||||
this.props.uiActions.hideContextMenu()
|
this.props.uiActions.hideContextMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,63 +130,63 @@ class ContextMenu extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
getItems(){
|
getItems(){
|
||||||
switch (this.props.context_menu.context) {
|
switch (this.props.menu.context) {
|
||||||
|
|
||||||
case 'queue':
|
|
||||||
var items = [
|
|
||||||
{ handleClick: 'playQueueItem', label: 'Play', icon: 'play' },
|
|
||||||
{ handleClick: 'addToPlaylist', label: 'Add to playlist', icon: 'plus', playlists: true },
|
|
||||||
{ handleClick: 'copyURIs', label: 'Copy URIs', icon: 'copy' },
|
|
||||||
{ handleClick: 'removeFromQueue', label: 'Remove', icon: 'trash' }
|
|
||||||
]
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'album':
|
case 'album':
|
||||||
var items = [
|
var items = [
|
||||||
{ handleClick: 'playURIs', label: 'Play', icon: 'play' },
|
{ handleClick: 'playURIs', label: 'Play' },
|
||||||
{ handleClick: 'playURIsNext', label: 'Play next', icon: 'play' },
|
{ handleClick: 'playURIsNext', label: 'Play next' },
|
||||||
{ handleClick: 'addToQueue', label: 'Add to queue', icon: 'plus' },
|
{ handleClick: 'addToQueue', label: 'Add to queue' },
|
||||||
{ handleClick: 'startRadio', label: 'Start radio', icon: 'spotify' },
|
{ handleClick: 'startRadio', label: 'Start radio' },
|
||||||
{ handleClick: 'copyURIs', label: 'Copy URI', icon: 'copy' }
|
{ handleClick: 'copyURIs', label: 'Copy URI' }
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'artist':
|
case 'artist':
|
||||||
var items = [
|
var items = [
|
||||||
{ handleClick: 'startRadio', label: 'Start radio', icon: 'spotify' },
|
{ handleClick: 'startRadio', label: 'Start radio' },
|
||||||
{ handleClick: 'toggleFollow', label: 'Follow/unfollow', icon: 'toggle-on' },
|
{ handleClick: 'toggleFollow', label: 'Follow/unfollow' },
|
||||||
{ handleClick: 'copyURIs', label: 'Copy URI', icon: 'copy' }
|
{ handleClick: 'copyURIs', label: 'Copy URI' }
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'playlist':
|
case 'playlist':
|
||||||
var items = [
|
var items = [
|
||||||
{ handleClick: 'playURIs', label: 'Play', icon: 'play' },
|
{ handleClick: 'playURIs', label: 'Play' },
|
||||||
{ handleClick: 'toggleFollow', label: 'Follow/unfollow', icon: 'toggle-on' },
|
{ handleClick: 'toggleFollow', label: 'Follow/unfollow' },
|
||||||
{ handleClick: 'copyURIs', label: 'Copy URI', icon: 'copy' }
|
{ handleClick: 'copyURIs', label: 'Copy URI' }
|
||||||
|
]
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'queue-track':
|
||||||
|
var items = [
|
||||||
|
{ handleClick: 'playQueueItem', label: 'Play' },
|
||||||
|
{ handleClick: 'addToPlaylist', label: 'Add to playlist' },
|
||||||
|
{ handleClick: 'copyURIs', label: 'Copy URIs' },
|
||||||
|
{ handleClick: 'removeFromQueue', label: 'Remove' }
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'editable-playlist-track':
|
case 'editable-playlist-track':
|
||||||
var items = [
|
var items = [
|
||||||
{ handleClick: 'playURIs', label: 'Play', icon: 'play' },
|
{ handleClick: 'playURIs', label: 'Play' },
|
||||||
{ handleClick: 'playURIsNext', label: 'Play next', icon: 'play' },
|
{ handleClick: 'playURIsNext', label: 'Play next' },
|
||||||
{ handleClick: 'addToQueue', label: 'Add to queue', icon: 'plus' },
|
{ handleClick: 'addToQueue', label: 'Add to queue' },
|
||||||
{ handleClick: 'addToPlaylist', label: 'Add to playlist', icon: 'plus', playlists: true },
|
{ handleClick: 'addToPlaylist', label: 'Add to playlist' },
|
||||||
{ handleClick: 'startRadio', label: 'Start radio', icon: 'spotify' },
|
{ handleClick: 'startRadio', label: 'Start radio' },
|
||||||
{ handleClick: 'copyURIs', label: 'Copy URIs', icon: 'copy' },
|
{ handleClick: 'copyURIs', label: 'Copy URIs' },
|
||||||
{ handleClick: 'removeFromPlaylist', label: 'Remove', icon: 'trash' }
|
{ handleClick: 'removeFromPlaylist', label: 'Remove' }
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var items = [
|
var items = [
|
||||||
{ handleClick: 'playURIs', label: 'Play', icon: 'play' },
|
{ handleClick: 'playURIs', label: 'Play' },
|
||||||
{ handleClick: 'playURIsNext', label: 'Play next', icon: 'play' },
|
{ handleClick: 'playURIsNext', label: 'Play next' },
|
||||||
{ handleClick: 'addToQueue', label: 'Add to queue', icon: 'plus' },
|
{ handleClick: 'addToQueue', label: 'Add to queue' },
|
||||||
{ handleClick: 'addToPlaylist', label: 'Add to playlist', icon: 'plus', playlists: true },
|
{ handleClick: 'addToPlaylist', label: 'Add to playlist' },
|
||||||
{ handleClick: 'startRadio', label: 'Start radio', icon: 'spotify' },
|
{ handleClick: 'startRadio', label: 'Start radio' },
|
||||||
{ handleClick: 'copyURIs', label: 'Copy URIs', icon: 'copy' }
|
{ handleClick: 'copyURIs', label: 'Copy URIs' }
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -199,7 +195,7 @@ class ContextMenu extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderTitle(){
|
renderTitle(){
|
||||||
var item = this.props.context_menu.data.item
|
var item = this.props.menu.item
|
||||||
var style = null
|
var style = null
|
||||||
if (item && item.images){
|
if (item && item.images){
|
||||||
style = {
|
style = {
|
||||||
@ -221,11 +217,10 @@ class ContextMenu extends React.Component{
|
|||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
items.map((item, index) => {
|
items.map((item, index) => {
|
||||||
if( item.playlists ){
|
if (item.handleClick == 'addToPlaylist'){
|
||||||
return (
|
return (
|
||||||
<span key={item.handleClick} className="menu-item-wrapper has-submenu">
|
<span key={item.handleClick} className="menu-item-wrapper has-submenu">
|
||||||
<a className="menu-item" onClick={e => this[item.handleClick](e)}>
|
<a className="menu-item" onClick={e => this[item.handleClick](e)}>
|
||||||
<FontAwesome className="icon" fixedWidth name={item.icon} />
|
|
||||||
<span className="label">{ item.label }</span>
|
<span className="label">{ item.label }</span>
|
||||||
<FontAwesome className="submenu-icon" name="caret-right" />
|
<FontAwesome className="submenu-icon" name="caret-right" />
|
||||||
</a>
|
</a>
|
||||||
@ -236,7 +231,6 @@ class ContextMenu extends React.Component{
|
|||||||
return (
|
return (
|
||||||
<span className="menu-item-wrapper" key={item.handleClick}>
|
<span className="menu-item-wrapper" key={item.handleClick}>
|
||||||
<a className="menu-item" onClick={e => this[item.handleClick](e)}>
|
<a className="menu-item" onClick={e => this[item.handleClick](e)}>
|
||||||
<FontAwesome className="icon" fixedWidth name={item.icon} />
|
|
||||||
<span className="label">{ item.label }</span>
|
<span className="label">{ item.label }</span>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
@ -249,37 +243,28 @@ class ContextMenu extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
if( !this.props.context_menu.show ) return null;
|
if (!this.props.menu) return null;
|
||||||
|
|
||||||
var style = {
|
var style = {
|
||||||
left: this.props.context_menu.position_x,
|
left: this.props.menu.position_x,
|
||||||
top: this.props.context_menu.position_y,
|
top: this.props.menu.position_y,
|
||||||
}
|
}
|
||||||
|
|
||||||
var className = 'context-menu'
|
var items = this.getItems()
|
||||||
if (this.props.emulate_touch) {
|
|
||||||
className += ' touch'
|
|
||||||
var trigger = 'touch'
|
|
||||||
} else {
|
|
||||||
className += ' '+this.props.context_menu.trigger
|
|
||||||
var trigger = this.props.context_menu.trigger
|
|
||||||
}
|
|
||||||
|
|
||||||
var items = this.getItems(trigger)
|
|
||||||
var height = 0
|
var height = 0
|
||||||
if (items) height = items.length * 34 // this is an approximation of how tall each menu item is
|
if (items) height = items.length * 34 // this is an approximation of how tall each menu item is
|
||||||
|
|
||||||
if (this.props.context_menu.position_x > (window.innerWidth - 154)) className += ' right-align'
|
if (this.props.menu.position_x > (window.innerWidth - 154)) className += ' right-align'
|
||||||
if (this.props.context_menu.position_x > (window.innerWidth - 308)) className += ' right-align-submenu'
|
if (this.props.menu.position_x > (window.innerWidth - 308)) className += ' right-align-submenu'
|
||||||
if (this.props.context_menu.position_y > (window.innerHeight - height)){
|
if (this.props.menu.position_y > (window.innerHeight - height)){
|
||||||
style.top = style.top - height
|
style.top = style.top - height
|
||||||
className += ' bottom-align-submenu'
|
className += ' bottom-align-submenu'
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className} style={style}>
|
<div className="context-menu" style={style}>
|
||||||
{this.props.context_menu.data.item ? this.renderTitle() : null}
|
{this.props.menu.item ? this.renderTitle() : null}
|
||||||
{this.renderItems(trigger)}
|
{this.renderItems()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -287,11 +272,9 @@ class ContextMenu extends React.Component{
|
|||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
return {
|
return {
|
||||||
emulate_touch: state.ui.emulate_touch,
|
menu: state.ui.context_menu,
|
||||||
context_menu: state.ui.context_menu,
|
|
||||||
current_track: state.ui.current_track,
|
current_track: state.ui.current_track,
|
||||||
current_tracklist: state.ui.current_tracklist,
|
current_tracklist: state.ui.current_tracklist,
|
||||||
playlist: state.ui.playlist,
|
|
||||||
playlists: state.ui.playlists
|
playlists: state.ui.playlists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { connect } from 'react-redux'
|
|||||||
import { Link } from 'react-router'
|
import { Link } from 'react-router'
|
||||||
import { createStore, bindActionCreators } from 'redux'
|
import { createStore, bindActionCreators } from 'redux'
|
||||||
|
|
||||||
|
import * as helpers from '../helpers'
|
||||||
import * as uiActions from '../services/ui/actions'
|
import * as uiActions from '../services/ui/actions'
|
||||||
|
|
||||||
class DebugInfo extends React.Component{
|
class DebugInfo extends React.Component{
|
||||||
@ -13,6 +14,13 @@ class DebugInfo extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
|
var touch_state = 'no touch'
|
||||||
|
if (this.props.ui.emulate_touch){
|
||||||
|
touch_state = 'emulated touch'
|
||||||
|
} else if (helpers.isTouchDevice()){
|
||||||
|
touch_state = 'touch device'
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="debug-info">
|
<div className="debug-info">
|
||||||
<div className="item">
|
<div className="item">
|
||||||
@ -28,7 +36,7 @@ class DebugInfo extends React.Component{
|
|||||||
{this.props.ui.users ? Object.keys(this.props.ui.users).length : '0'} users
|
{this.props.ui.users ? Object.keys(this.props.ui.users).length : '0'} users
|
||||||
</div>
|
</div>
|
||||||
<div className="item">
|
<div className="item">
|
||||||
{'ontouchstart' in document.documentElement ? 'can touch' : 'no touch'}
|
{touch_state}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
164
src/js/components/TouchContextMenu.js
Executable file
164
src/js/components/TouchContextMenu.js
Executable file
@ -0,0 +1,164 @@
|
|||||||
|
|
||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import { Link } from 'react-router'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { bindActionCreators } from 'redux'
|
||||||
|
import FontAwesome from 'react-fontawesome'
|
||||||
|
|
||||||
|
import TrackList from './TrackList'
|
||||||
|
import * as helpers from '../helpers'
|
||||||
|
import * as uiActions from '../services/ui/actions'
|
||||||
|
import * as pusherActions from '../services/pusher/actions'
|
||||||
|
import * as mopidyActions from '../services/mopidy/actions'
|
||||||
|
import * as spotifyActions from '../services/spotify/actions'
|
||||||
|
|
||||||
|
class TouchContextMenu extends React.Component{
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(){
|
||||||
|
this.props.uiActions.hideTouchContextMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
playQueueItem(){
|
||||||
|
var tracks = this.props.menu.items
|
||||||
|
this.props.mopidyActions.changeTrack( tracks[0].tlid )
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFromQueue(e){
|
||||||
|
var tracks = this.props.menu.items
|
||||||
|
var tracks_tlids = []
|
||||||
|
for( var i = 0; i < tracks.length; i++ ){
|
||||||
|
tracks_tlids.push( tracks[i].tlid );
|
||||||
|
}
|
||||||
|
this.props.mopidyActions.removeTracks( tracks_tlids )
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
playURIs(e){
|
||||||
|
this.props.mopidyActions.playURIs(this.props.menu.uris)
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
playURIsNext(e){
|
||||||
|
this.props.mopidyActions.enqueueURIsNext(this.props.menu.uris)
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
addToPlaylist(e){
|
||||||
|
this.props.uiActions.openModal('add_to_playlist', { tracks_uris: this.props.menu.uris })
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
addToQueue(e){
|
||||||
|
this.props.mopidyActions.enqueueURIs(this.props.menu.uris)
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFromPlaylist(e){
|
||||||
|
this.props.uiActions.removeTracksFromPlaylist(this.props.menu.tracklist_uri, this.props.menu.indexes)
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
startRadio(e){
|
||||||
|
this.props.pusherActions.startRadio(this.props.menu.uris)
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
getItems(){
|
||||||
|
switch (this.props.menu.context) {
|
||||||
|
|
||||||
|
case 'queue-track':
|
||||||
|
var items = [
|
||||||
|
{ handleClick: 'playQueueItem', label: 'Play', icon: 'play' },
|
||||||
|
{ handleClick: 'addToPlaylist', label: 'Playlist', icon: 'plus' },
|
||||||
|
{ handleClick: 'removeFromQueue', label: 'Remove', icon: 'trash' }
|
||||||
|
]
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'editable-playlist-track':
|
||||||
|
var items = [
|
||||||
|
{ handleClick: 'playURIs', label: 'Play', icon: 'play' },
|
||||||
|
{ handleClick: 'playURIsNext', label: 'Next', icon: 'play' },
|
||||||
|
{ handleClick: 'addToQueue', label: 'Queue', icon: 'plus' },
|
||||||
|
{ handleClick: 'addToPlaylist', label: 'Playlist', icon: 'plus' },
|
||||||
|
{ handleClick: 'startRadio', label: 'Start radio', icon: 'spotify' },
|
||||||
|
{ handleClick: 'removeFromPlaylist', label: 'Remove', icon: 'trash' }
|
||||||
|
]
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
var items = [
|
||||||
|
{ handleClick: 'playURIs', label: 'Play', icon: 'play' },
|
||||||
|
{ handleClick: 'playURIsNext', label: 'Next', icon: 'play' },
|
||||||
|
{ handleClick: 'addToQueue', label: 'Queue', icon: 'plus' },
|
||||||
|
{ handleClick: 'addToPlaylist', label: 'Playlist', icon: 'plus' },
|
||||||
|
{ handleClick: 'startRadio', label: 'Start radio', icon: 'spotify' }
|
||||||
|
]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
renderItems(){
|
||||||
|
var items = this.getItems()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
items.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<span className="menu-item-wrapper" key={item.handleClick}>
|
||||||
|
<a className="menu-item" onClick={e => this[item.handleClick]()}>
|
||||||
|
<FontAwesome className="icon" fixedWidth name={item.icon} />
|
||||||
|
<span className="label">{ item.label }</span>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
<span className="menu-item-wrapper cancel" key="cancel">
|
||||||
|
<a className="menu-item" onClick={e => this.close()}>
|
||||||
|
<FontAwesome className="icon" fixedWidth name="close" />
|
||||||
|
<span className="label">Cancel</span>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render(){
|
||||||
|
if( !this.props.menu ) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="touch-context-menu">
|
||||||
|
{this.renderItems()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => {
|
||||||
|
return {
|
||||||
|
menu: state.ui.touch_context_menu,
|
||||||
|
current_track: state.ui.current_track,
|
||||||
|
current_tracklist: state.ui.current_tracklist,
|
||||||
|
playlist: state.ui.playlist,
|
||||||
|
playlists: state.ui.playlists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
return {
|
||||||
|
uiActions: bindActionCreators(uiActions, dispatch),
|
||||||
|
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||||
|
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
||||||
|
mopidyActions: bindActionCreators(mopidyActions, dispatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(TouchContextMenu)
|
||||||
@ -20,6 +20,13 @@ export default class Track extends React.Component{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleTouchStart(e){
|
||||||
|
var target = $(e.target);
|
||||||
|
if( !target.is('a') && target.closest('a').length <= 0 ){
|
||||||
|
this.props.handleTouchStart(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleTouchEnd(e){
|
handleTouchEnd(e){
|
||||||
var target = $(e.target);
|
var target = $(e.target);
|
||||||
if( !target.is('a') && target.closest('a').length <= 0 ){
|
if( !target.is('a') && target.closest('a').length <= 0 ){
|
||||||
|
|||||||
@ -34,7 +34,7 @@ class TrackList extends React.Component{
|
|||||||
window.removeEventListener("keyup", this.handleKeyUp, false);
|
window.removeEventListener("keyup", this.handleKeyUp, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps( nextProps ){
|
componentWillReceiveProps(nextProps){
|
||||||
this.setState({ tracks: this.keyifyTracks(nextProps.tracks) });
|
this.setState({ tracks: this.keyifyTracks(nextProps.tracks) });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,12 +53,12 @@ class TrackList extends React.Component{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTouchStart(e, index){
|
handleTouchStart(e,index){
|
||||||
this._touch_x = Math.round(e.changedTouches[0].pageX)
|
this._touch_x = Math.round(e.changedTouches[0].pageX)
|
||||||
this._touch_y = Math.round(e.changedTouches[0].pageY)
|
this._touch_y = Math.round(e.changedTouches[0].pageY)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTouchEnd(e, index){
|
handleTouchEnd(e,index){
|
||||||
var pageX = Math.round(e.changedTouches[0].pageX)
|
var pageX = Math.round(e.changedTouches[0].pageX)
|
||||||
var pageY = Math.round(e.changedTouches[0].pageY)
|
var pageY = Math.round(e.changedTouches[0].pageY)
|
||||||
|
|
||||||
@ -69,45 +69,30 @@ class TrackList extends React.Component{
|
|||||||
this._touch_x > ( pageX - this._touch_threshold ) &&
|
this._touch_x > ( pageX - this._touch_threshold ) &&
|
||||||
this._touch_y < ( pageY + this._touch_threshold ) &&
|
this._touch_y < ( pageY + this._touch_threshold ) &&
|
||||||
this._touch_y > ( pageY - this._touch_threshold ) ){
|
this._touch_y > ( pageY - this._touch_threshold ) ){
|
||||||
|
this.handleTouchContextMenu(e,index)
|
||||||
// toggle selection
|
|
||||||
var tracks = this.state.tracks
|
|
||||||
tracks[index].selected = !tracks[index].selected
|
|
||||||
this.setState({ tracks: tracks, lastSelectedTrack: index })
|
|
||||||
|
|
||||||
// update our context menu to hide/show
|
|
||||||
var selected_tracks = this.selectedTracks()
|
|
||||||
if( selected_tracks.length > 0 ){
|
|
||||||
var data = {
|
|
||||||
items: selected_tracks,
|
|
||||||
uris: helpers.asURIs(selected_tracks),
|
|
||||||
indexes: this.tracksIndexes(selected_tracks)
|
|
||||||
}
|
|
||||||
this.props.uiActions.showContextMenu( e, data, this.props.context, 'touch' )
|
|
||||||
}else{
|
|
||||||
this.props.uiActions.hideContextMenu()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDoubleClick(e, index){
|
handleDoubleClick(e,index){
|
||||||
if( this.props.context_menu.show ) this.props.uiActions.hideContextMenu()
|
if (this.props.context_menu) this.props.uiActions.hideContextMenu()
|
||||||
this.playTracks()
|
this.playTracks()
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseDown(e, index){
|
handleMouseDown(e,index){
|
||||||
|
if (this.props.emulate_touch){
|
||||||
|
this.handleTouchContextMenu(e,index)
|
||||||
|
}else{
|
||||||
|
if (this.props.context_menu) this.props.uiActions.hideContextMenu()
|
||||||
|
if (!this.state.tracks[index].selected && !this.isRightClick(e) && !e.ctrlKey) this.toggleTrackSelections(e, index)
|
||||||
|
|
||||||
if( this.props.context_menu.show ) this.props.uiActions.hideContextMenu()
|
var selected_tracks = this.selectedTracks()
|
||||||
|
this.props.uiActions.dragStart( e, this.props.context, selected_tracks, this.tracksIndexes(selected_tracks) )
|
||||||
if( !this.state.tracks[index].selected && !this.isRightClick(e) && !e.ctrlKey ) this.toggleTrackSelections(e, index)
|
}
|
||||||
|
|
||||||
var selected_tracks = this.selectedTracks()
|
|
||||||
this.props.uiActions.dragStart( e, this.props.context, selected_tracks, this.tracksIndexes(selected_tracks) )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseUp(e, index){
|
handleMouseUp(e,index){
|
||||||
|
|
||||||
// right-clicking on an un-highlighted track
|
// right-clicking on an un-highlighted track
|
||||||
if( !this.state.tracks[index].selected && this.isRightClick(e) ){
|
if( !this.state.tracks[index].selected && this.isRightClick(e) ){
|
||||||
@ -132,14 +117,40 @@ class TrackList extends React.Component{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleContextMenu(e, index){
|
handleContextMenu(e,index){
|
||||||
var selected_tracks = this.selectedTracks()
|
var selected_tracks = this.selectedTracks()
|
||||||
var data = {
|
var data = {
|
||||||
|
e: e,
|
||||||
|
context: (this.props.context ? this.props.context : 'track'),
|
||||||
|
tracklist_uri: (this.props.tracklist_uri ? this.props.tracklist_uri : null),
|
||||||
items: selected_tracks,
|
items: selected_tracks,
|
||||||
uris: helpers.asURIs(selected_tracks),
|
uris: helpers.asURIs(selected_tracks),
|
||||||
indexes: this.tracksIndexes(selected_tracks)
|
indexes: this.tracksIndexes(selected_tracks)
|
||||||
}
|
}
|
||||||
this.props.uiActions.showContextMenu( e, data, this.props.context, 'click' )
|
this.props.uiActions.showContextMenu(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTouchContextMenu(e,index){
|
||||||
|
|
||||||
|
// toggle selection
|
||||||
|
var tracks = this.state.tracks
|
||||||
|
tracks[index].selected = !tracks[index].selected
|
||||||
|
this.setState({ tracks: tracks, lastSelectedTrack: index })
|
||||||
|
|
||||||
|
// update our context menu to hide/show
|
||||||
|
var selected_tracks = this.selectedTracks()
|
||||||
|
if( selected_tracks.length > 0 ){
|
||||||
|
var data = {
|
||||||
|
context: (this.props.context ? this.props.context : 'track'),
|
||||||
|
tracklist_uri: (this.props.tracklist_uri ? this.props.tracklist_uri : null),
|
||||||
|
items: selected_tracks,
|
||||||
|
uris: helpers.asURIs(selected_tracks),
|
||||||
|
indexes: this.tracksIndexes(selected_tracks)
|
||||||
|
}
|
||||||
|
this.props.uiActions.showTouchContextMenu(data)
|
||||||
|
}else{
|
||||||
|
this.props.uiActions.hideTouchContextMenu()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleTrackSelections(e, index){
|
toggleTrackSelections(e, index){
|
||||||
@ -285,6 +296,7 @@ class TrackList extends React.Component{
|
|||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
return {
|
return {
|
||||||
dragger: state.ui.dragger,
|
dragger: state.ui.dragger,
|
||||||
|
emulate_touch: state.ui.emulate_touch,
|
||||||
current_track: state.ui.current_track,
|
current_track: state.ui.current_track,
|
||||||
context_menu: state.ui.context_menu
|
context_menu: state.ui.context_menu
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
export let isTouchDevice = function(){
|
||||||
|
return 'ontouchstart' in document.documentElement
|
||||||
|
}
|
||||||
|
|
||||||
export let sizedImages = function( images ){
|
export let sizedImages = function( images ){
|
||||||
|
|
||||||
var sizes = {
|
var sizes = {
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
|
|
||||||
import * as helpers from '../../helpers'
|
import * as helpers from '../../helpers'
|
||||||
|
|
||||||
export function showContextMenu( e, data, context = false, trigger = 'click' ){
|
export function showContextMenu(data){
|
||||||
|
data.position_x = data.e.clientX
|
||||||
|
data.position_y = data.e.clientY
|
||||||
return {
|
return {
|
||||||
type: 'SHOW_CONTEXT_MENU',
|
type: 'SHOW_CONTEXT_MENU',
|
||||||
position_x: e.clientX,
|
|
||||||
position_y: e.clientY,
|
|
||||||
context: context,
|
|
||||||
trigger: trigger,
|
|
||||||
data: data
|
data: data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -18,6 +16,19 @@ export function hideContextMenu(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function showTouchContextMenu(data){
|
||||||
|
return {
|
||||||
|
type: 'SHOW_TOUCH_CONTEXT_MENU',
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hideTouchContextMenu(){
|
||||||
|
return {
|
||||||
|
type: 'HIDE_TOUCH_CONTEXT_MENU'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function startSearch( query ){
|
export function startSearch( query ){
|
||||||
return {
|
return {
|
||||||
type: 'SEARCH_STARTED',
|
type: 'SEARCH_STARTED',
|
||||||
|
|||||||
@ -22,20 +22,22 @@ export default function reducer(ui = {}, action){
|
|||||||
/**
|
/**
|
||||||
* Context menu
|
* Context menu
|
||||||
**/
|
**/
|
||||||
|
|
||||||
case 'SHOW_CONTEXT_MENU':
|
case 'SHOW_CONTEXT_MENU':
|
||||||
return Object.assign({}, ui, {
|
return Object.assign({}, ui, {
|
||||||
context_menu: {
|
context_menu: action.data
|
||||||
show: true,
|
|
||||||
position_x: action.position_x,
|
|
||||||
position_y: action.position_y,
|
|
||||||
context: action.context,
|
|
||||||
trigger: action.trigger,
|
|
||||||
data: action.data
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
case 'HIDE_CONTEXT_MENU':
|
case 'HIDE_CONTEXT_MENU':
|
||||||
return Object.assign({}, ui, { context_menu: { show: false } });
|
return Object.assign({}, ui, {context_menu: null});
|
||||||
|
|
||||||
|
case 'SHOW_TOUCH_CONTEXT_MENU':
|
||||||
|
return Object.assign({}, ui, {
|
||||||
|
touch_context_menu: action.data
|
||||||
|
});
|
||||||
|
|
||||||
|
case 'HIDE_TOUCH_CONTEXT_MENU':
|
||||||
|
return Object.assign({}, ui, {touch_context_menu: null});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -9,11 +9,13 @@ import Sidebar from '../components/Sidebar'
|
|||||||
import MiniPlayer from '../components/MiniPlayer'
|
import MiniPlayer from '../components/MiniPlayer'
|
||||||
import SidebarToggleButton from '../components/SidebarToggleButton'
|
import SidebarToggleButton from '../components/SidebarToggleButton'
|
||||||
import ContextMenu from '../components/ContextMenu'
|
import ContextMenu from '../components/ContextMenu'
|
||||||
|
import TouchContextMenu from '../components/TouchContextMenu'
|
||||||
import Dragger from '../components/Dragger'
|
import Dragger from '../components/Dragger'
|
||||||
import Modal from '../components/Modal/Modal'
|
import Modal from '../components/Modal/Modal'
|
||||||
import Notifications from '../components/Notifications'
|
import Notifications from '../components/Notifications'
|
||||||
import DebugInfo from '../components/DebugInfo'
|
import DebugInfo from '../components/DebugInfo'
|
||||||
|
|
||||||
|
import * as helpers from '../helpers'
|
||||||
import * as uiActions from '../services/ui/actions'
|
import * as uiActions from '../services/ui/actions'
|
||||||
import * as pusherActions from '../services/pusher/actions'
|
import * as pusherActions from '../services/pusher/actions'
|
||||||
import * as mopidyActions from '../services/mopidy/actions'
|
import * as mopidyActions from '../services/mopidy/actions'
|
||||||
@ -117,10 +119,10 @@ class App extends React.Component{
|
|||||||
|
|
||||||
render(){
|
render(){
|
||||||
var className = '';
|
var className = '';
|
||||||
if( this.props.dragger && this.props.dragger.active ) className += ' dragging'
|
if (this.props.dragger && this.props.dragger.active) className += ' dragging'
|
||||||
if( this.props.sidebar_open ) className += ' sidebar-open'
|
if (this.props.sidebar_open) className += ' sidebar-open'
|
||||||
if( this.props.modal ) className += ' modal-open'
|
if (this.props.modal) className += ' modal-open'
|
||||||
if( 'ontouchstart' in document.documentElement ) className += ' has-touch-events'
|
if (helpers.isTouchDevice() || this.props.emulate_touch) className += ' can-touch'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
@ -129,7 +131,8 @@ class App extends React.Component{
|
|||||||
<main>
|
<main>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</main>
|
</main>
|
||||||
<ContextMenu state={this.props.context_menu} />
|
<ContextMenu />
|
||||||
|
<TouchContextMenu />
|
||||||
<Dragger />
|
<Dragger />
|
||||||
<Modal />
|
<Modal />
|
||||||
<Notifications />
|
<Notifications />
|
||||||
|
|||||||
@ -151,7 +151,7 @@ class Artist extends React.Component{
|
|||||||
<div className="body overview">
|
<div className="body overview">
|
||||||
<div className={related_artists.length > 0 ? "col w70" : "col w100"}>
|
<div className={related_artists.length > 0 ? "col w70" : "col w100"}>
|
||||||
<h4 className="left-padding">Top tracks</h4>
|
<h4 className="left-padding">Top tracks</h4>
|
||||||
{ this.props.artist.tracks ? <TrackList tracks={ this.props.artist.tracks } /> : null }
|
{ this.props.artist.tracks ? <TrackList tracks={this.props.artist.tracks} /> : null }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col w5"></div>
|
<div className="col w5"></div>
|
||||||
|
|||||||
@ -115,8 +115,11 @@ class Playlist extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
if( !this.props.playlist || !this.props.playlist.name ) return null;
|
if( !this.props.playlist || !this.props.playlist.name ) return null
|
||||||
var scheme = helpers.uriSource( this.props.playlist.uri );
|
var scheme = helpers.uriSource( this.props.playlist.uri )
|
||||||
|
|
||||||
|
var context = 'playlist-track'
|
||||||
|
if (this.props.playlist.can_edit) context = 'editable-playlist-track'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="view playlist-view">
|
<div className="view playlist-view">
|
||||||
@ -153,7 +156,7 @@ class Playlist extends React.Component{
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section className="list-wrapper">
|
<section className="list-wrapper">
|
||||||
{ this.props.playlist.tracks ? <TrackList context={ this.props.playlist.can_edit ? 'editable-playlist-track' : 'playlist-track'} tracks={ this.props.playlist.tracks } removeTracks={ tracks_indexes => this.removeTracks(tracks_indexes) } reorderTracks={ (indexes, index) => this.reorderTracks(indexes, index) } /> : null }
|
{ this.props.playlist.tracks ? <TrackList tracklist_uri={this.props.params.uri} context={context} tracks={this.props.playlist.tracks} removeTracks={ tracks_indexes => this.removeTracks(tracks_indexes) } reorderTracks={ (indexes, index) => this.reorderTracks(indexes, index) } /> : null }
|
||||||
<LazyLoadListener enabled={this.props.playlist.tracks_more} loadMore={ () => this.loadMore() }/>
|
<LazyLoadListener enabled={this.props.playlist.tracks_more} loadMore={ () => this.loadMore() }/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@ -98,7 +98,7 @@ class Queue extends React.Component{
|
|||||||
|
|
||||||
<TrackList
|
<TrackList
|
||||||
show_source_icon={true}
|
show_source_icon={true}
|
||||||
context="queue"
|
context="queue-track"
|
||||||
tracks={this.props.current_tracklist}
|
tracks={this.props.current_tracklist}
|
||||||
removeTracks={ tracks => this.removeTracks( tracks ) }
|
removeTracks={ tracks => this.removeTracks( tracks ) }
|
||||||
playTracks={ tracks => this.playTracks( tracks ) }
|
playTracks={ tracks => this.playTracks( tracks ) }
|
||||||
|
|||||||
@ -99,11 +99,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.cancel {
|
|
||||||
float: right;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
border-top: 1px solid lighten($dark_grey, 8%);
|
border-top: 1px solid lighten($dark_grey, 8%);
|
||||||
}
|
}
|
||||||
@ -117,57 +112,61 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.touch{
|
.touch-context-menu {
|
||||||
|
position: fixed;
|
||||||
bottom: 0 !important;
|
z-index: 99;
|
||||||
left: 0 !important;
|
bottom: 0;
|
||||||
right: 0 !important;
|
left: 0;
|
||||||
top: auto !important;
|
right: 0;
|
||||||
background: $blue;
|
top: auto;
|
||||||
|
background: $blue;
|
||||||
|
color: #FFFFFF;
|
||||||
|
|
||||||
.menu-item-wrapper {
|
.menu-item-wrapper {
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
.menu-item {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
width: 50px;
|
||||||
|
height: 44px;
|
||||||
|
padding-top: 6px;
|
||||||
|
border: 0;
|
||||||
|
vertical-align: top;
|
||||||
|
|
||||||
.menu-item {
|
&:hover {
|
||||||
display: inline-block;
|
background: inherit;
|
||||||
text-align: center;
|
|
||||||
width: 56px;
|
|
||||||
height: 56px;
|
|
||||||
border: 0 !important;
|
|
||||||
vertical-align: top;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
background: rgba(255,255,255,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
padding: 5px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
display: block;
|
|
||||||
font-size: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submenu-icon {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.submenu {
|
&:active,
|
||||||
|
&:focus {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
padding: 5px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: block;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submenu-icon {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:not(:first-child) .menu-item {
|
&.cancel {
|
||||||
border-left: 1px solid rgba(255,255,255,0.2) !important;
|
float: right;
|
||||||
}
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:first-child) .menu-item {
|
||||||
|
border-left: 1px solid rgba(255,255,255,0.2) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user