diff --git a/package.json b/package.json index 8204e836..d0d99530 100755 --- a/package.json +++ b/package.json @@ -10,39 +10,34 @@ }, "main": "app.js", "dependencies": { - "webpack": "2.2.1", - "webpack-strip": "*", - "sass-loader": "6.0.2", - "style-loader": "0.13.2", - "css-loader": "0.26.2", - "url-loader": "0.5.8", - "file-loader": "0.10.1", - "expose-loader": "0.7.3", - - "node-sass": "4.5.0", - "extract-text-webpack-plugin": "2.0.0", - "babel-core": "^6.23.1", - "babel-loader": "^6.3.0", + "babel-loader": "^7.1.1", "babel-preset-es2015": "^6.22.0", "babel-preset-react": "^6.22.0", "babel-preset-stage-0": "^6.22.0", "babel-preset-stage-2": "^6.22.0", - - "flux": "^2.1.1", - "redux": "*", - "react": "*", - "react-dom": "*", - "react-router": "3.0.2", - "redux": "*", - "react-redux": "*", - "redux-devtools": "*", - "redux-thunk": "*", - + "css-loader": "0.28.4", + "expose-loader": "0.7.3", + "extract-text-webpack-plugin": "3.0.0", + "file-loader": "^0.11.2", + "flux": "^3.1.2", "jquery": "3.1.1", - "mopidy": "^0.5.0", + "mopidy": "^0.5.0", + "node-sass": "4.5.0", + "react": "15.6.1", + "react-dom": "15.6.1", "react-fontawesome": "*", - "react-ga": "2.1.2" + "react-ga": "2.1.2", + "react-redux": "5.0.5", + "react-router": "^3.0.5", + "redux": "3.7.2", + "redux-devtools": "3.4.0", + "redux-thunk": "2.2.0", + "sass-loader": "6.0.2", + "style-loader": "0.13.2", + "url-loader": "0.5.8", + "webpack": "3.3.0", + "webpack-strip": "0.1.0" }, "scripts": { "dev": "./build.sh && NODE_ENV=development webpack --watch", diff --git a/src/js/App.js b/src/js/App.js index 5c769576..f661585e 100755 --- a/src/js/App.js +++ b/src/js/App.js @@ -30,11 +30,19 @@ class App extends React.Component{ super(props); this.handleKeyUp = this.handleKeyUp.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); + this.handleWindowResize = this.handleWindowResize.bind(this); } componentWillMount(){ window.addEventListener("keyup", this.handleKeyUp, false); window.addEventListener("keydown", this.handleKeyDown, false); + window.addEventListener("resize", this.handleWindowResize, false); + } + + componentWillUnmount(){ + window.removeEventListener("keyup", this.handleKeyUp, false); + window.removeEventListener("keydown", this.handleKeyDown, false); + window.removeEventListener("resize", this.handleWindowResize, false); } componentDidMount(){ @@ -56,6 +64,9 @@ class App extends React.Component{ // hide our sidebar this.props.uiActions.toggleSidebar( false ) }); + + // Check our slim_mode + this.handleWindowResize(null) } componentWillReceiveProps(nextProps){ @@ -76,11 +87,6 @@ class App extends React.Component{ } } - componentWillUnmount(){ - window.removeEventListener("keyup", this.handleKeyUp, false); - window.removeEventListener("keydown", this.handleKeyDown, false); - } - shouldTriggerShortcut(e){ var ignoreNodes = ['INPUT', 'TEXTAREA'] var keyCodes = [32,27,191,37,38,39,40,70] @@ -95,6 +101,21 @@ class App extends React.Component{ } } + handleWindowResize(e){ + var width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0) + var height = Math.max(document.documentElement.clientHeight, window.innerHeight || 0) + + if (width <= 800){ + if (!this.props.slim_mode){ + this.props.uiActions.setSlimMode(true) + } + } else { + if (this.props.slim_mode){ + this.props.uiActions.setSlimMode(false) + } + } + } + handleKeyDown(e){ this.shouldTriggerShortcut(e) } @@ -197,6 +218,8 @@ class App extends React.Component{ if (this.props.dragger && this.props.dragger.active) className += ' dragging' if (this.props.sidebar_open) className += ' sidebar-open' if (this.props.modal) className += ' modal-open' + if (this.props.touch_dragging) className += ' touch-dragging' + if (this.props.slim_mode) className += ' slim-mode' if (helpers.isTouchDevice()){ className += ' touch' } else { @@ -236,6 +259,8 @@ class App extends React.Component{ const mapStateToProps = (state, ownProps) => { return { + touch_dragging: state.ui.touch_dragging, + slim_mode: state.ui.slim_mode, broadcasts: (state.ui.broadcasts ? state.ui.broadcasts : []), volume: (state.mopidy.volume ? state.mopidy.volume : false), notifications: (state.ui.notifications ? state.ui.notifications : []), diff --git a/src/js/bootstrap.js b/src/js/bootstrap.js index 8d749e94..2594daef 100755 --- a/src/js/bootstrap.js +++ b/src/js/bootstrap.js @@ -53,6 +53,7 @@ var initialState = { autocomplete_results: {} }, ui: { + slim_mode: false, current_tracklist: [], current_tltrack: false, notifications: [], diff --git a/src/js/components/ContextMenu.js b/src/js/components/ContextMenu.js index e351e4dd..94327e14 100755 --- a/src/js/components/ContextMenu.js +++ b/src/js/components/ContextMenu.js @@ -174,6 +174,11 @@ class ContextMenu extends React.Component{ this.props.mopidyActions.playPlaylist(this.props.menu.uris[0]) } + playArtistTopTracks(e){ + this.props.uiActions.hideContextMenu() + this.props.spotifyActions.playArtistTopTracks(this.props.menu.uris[0]) + } + addToQueue(e, next = false){ this.props.uiActions.hideContextMenu() this.props.mopidyActions.enqueueURIs(this.props.menu.uris, this.props.menu.tracklist_uri, next) @@ -361,6 +366,14 @@ class ContextMenu extends React.Component{ ) + var play_artist_top_tracks = ( + + this.playArtistTopTracks(e)}> + Play top tracks + + + ) + var add_to_queue = ( this.addToQueue(e)}> @@ -463,6 +476,7 @@ class ContextMenu extends React.Component{ case 'artist': return ( + {context.source == 'spotify' ? play_artist_top_tracks : null} {start_radio} {context.source == 'spotify' ? go_to_recommendations : null} {copy_uris} diff --git a/src/js/components/DebugInfo.js b/src/js/components/DebugInfo.js index 1c2d8564..41ff9e96 100755 --- a/src/js/components/DebugInfo.js +++ b/src/js/components/DebugInfo.js @@ -81,6 +81,9 @@ class DebugInfo extends React.Component{ Enqueue batches: {this.props.mopidy.enqueue_uris_batches ? this.props.mopidy.enqueue_uris_batches.length : '0'} + + Slim mode: {this.props.ui.slim_mode ? 'on' : 'off'} + _testMode: {window._testMode ? 'on' : 'off'} diff --git a/src/js/components/Header.js b/src/js/components/Header.js index ca5fb39a..a233350e 100755 --- a/src/js/components/Header.js +++ b/src/js/components/Header.js @@ -16,26 +16,32 @@ export default class Header extends React.Component{ } } - handleContextMenuTrigger(e,options){ - e.preventDefault() - var data = { - e: e, - context: 'custom', - title: this.props.title, - options: options + handleContextMenuTrigger(e,options){ + + // We have an override trigger (eg Album, Playlist) + if (this.props.handleContextMenuTrigger){ + return this.props.handleContextMenuTrigger(e) + } else { + e.preventDefault() + var data = { + e: e, + context: 'custom', + title: this.props.title, + options: options + } + this.props.uiActions.showContextMenu(data) } - this.props.uiActions.showContextMenu(data) } renderOptions(){ - if (!this.props.options) return null + if (!this.props.options && !this.props.handleContextMenuTrigger) return null return ( this.handleContextMenuTrigger(e,this.props.options)} /> - { this.props.options } + {this.props.options ? this.props.options : null} diff --git a/src/js/components/PlaybackControls.js b/src/js/components/PlaybackControls.js index 32acfd33..44f04690 100755 --- a/src/js/components/PlaybackControls.js +++ b/src/js/components/PlaybackControls.js @@ -62,7 +62,7 @@ class PlaybackControls extends React.Component{ } render(){ - var images = [] + var images = false if (this.props.current_track && this.props.current_track.album && this.props.current_track.album.images){ images = this.props.current_track.album.images } diff --git a/src/js/components/Track.js b/src/js/components/Track.js index 48aaa2a6..4b44b725 100755 --- a/src/js/components/Track.js +++ b/src/js/components/Track.js @@ -59,6 +59,9 @@ export default class Track extends React.Component{ var track_columns = ( + + {this.props.track.selected ? : null} + {track.name ? track.name : {track.uri}} @@ -89,8 +92,16 @@ export default class Track extends React.Component{ var added = '-' } + className+= ' has-drag-zone' + var track_columns = ( + + {this.props.track.selected ? : null} + + + + {track.name ? track.name : {track.uri}} {track.explicit ? EXPLICIT : null} @@ -116,6 +127,9 @@ export default class Track extends React.Component{ var track_columns = ( + + {this.props.track.selected ? : null} + {track.name ? track.name : {track.uri}} {track.explicit ? EXPLICIT : null} @@ -146,9 +160,6 @@ export default class Track extends React.Component{ onMouseUp={ e => this.props.handleMouseUp(e) } onDoubleClick={ e => this.props.handleDoubleClick(e) } onContextMenu={ e => this.handleContextMenu(e) }> - - {this.props.track.selected ? : null} - { track_columns } ); diff --git a/src/js/components/TrackList.js b/src/js/components/TrackList.js index ecddb44c..cccd014e 100755 --- a/src/js/components/TrackList.js +++ b/src/js/components/TrackList.js @@ -21,16 +21,19 @@ class TrackList extends React.Component{ last_selected_track: false } - this._touching = false + this.touch_dragging = false this.handleKeyUp = this.handleKeyUp.bind(this) + this.handleTouchMove = this.handleTouchMove.bind(this) } componentWillMount(){ - window.addEventListener("keyup", this.handleKeyUp, false); + window.addEventListener("keyup", this.handleKeyUp, false) + window.addEventListener("touchmove", this.handleTouchMove, false) } componentWillUnmount(){ - window.removeEventListener("keyup", this.handleKeyUp, false); + window.removeEventListener("keyup", this.handleKeyUp, false) + window.removeEventListener("touchmove", this.handleTouchMove, false) } componentDidMount(){ @@ -51,9 +54,9 @@ class TrackList extends React.Component{ var target = $(e.target) // Wide screen, so no worries - if ($(window).width() > 800){ + if (!this.props.slim_mode){ return 'default' - } else if (target.is('.state-icon') || target.closest('.state-icon').length > 0){ + } else if (target.is('.select-zone') || target.closest('.select-zone').length > 0){ return 'mobile' } @@ -76,12 +79,52 @@ class TrackList extends React.Component{ } handleTouchStart(e,index){ - this._touching = true + var target = $(e.target) + if (target.hasClass('drag-zone')){ + $('body').addClass('touch-dragging') + this.touch_dragging = true + e.preventDefault() + } + } + + handleTouchMove(e){ + if (this.touch_dragging){ + e.preventDefault() + let touch = e.touches[0] + let over = $(document.elementFromPoint(touch.clientX, touch.clientY)) + if (!over.is('.track')){ + over = over.closest('.track') + } + $(document).find('.touch-drag-hover').removeClass('touch-drag-hover') + if (over.length > 0){ + over.addClass('touch-drag-hover') + } + } } handleTouchEnd(e,index){ - this._touching = false - this.handleMouseDown(e,index) + if (this.touch_dragging){ + let touch = e.changedTouches[0] + let over = $(document.elementFromPoint(touch.clientX, touch.clientY)) + if (!over.is('.track')){ + over = over.closest('.track') + } + if (over.length > 0){ + let siblings = over.parent().children('.track') + let dropped_at = siblings.index(over) - 1 + + if (typeof(this.props.reorderTracks) !== 'undefined'){ + this.props.reorderTracks([index],dropped_at) + this.render() + } + } + + $(document).find('.touch-drag-hover').removeClass('touch-drag-hover') + $('body').removeClass('touch-dragging') + this.touch_dragging = false + } else { + this.handleMouseDown(e,index) + } // Prevent any event bubbling. This prevents clicks and mouse events // from also being fired @@ -348,7 +391,8 @@ class TrackList extends React.Component{ { this.state.tracks.map( (track, index) => { - return self.handleMouseDown(e, index)} handleTouchStart={e => self.handleTouchStart(e, index)} handleTouchEnd={e => self.handleTouchEnd(e, index)} - handleContextMenu={e => self.handleContextMenu(e)} /> + handleContextMenu={e => self.handleContextMenu(e)} + /> + ) } ) } @@ -377,8 +423,8 @@ class TrackList extends React.Component{ const mapStateToProps = (state, ownProps) => { return { + slim_mode: state.ui.slim_mode, dragger: state.ui.dragger, - emulate_touch: state.ui.emulate_touch, current_track: state.ui.current_track, context_menu: state.ui.context_menu } diff --git a/src/js/services/spotify/actions.js b/src/js/services/spotify/actions.js index d03e1766..9a0faf5c 100755 --- a/src/js/services/spotify/actions.js +++ b/src/js/services/spotify/actions.js @@ -1,5 +1,6 @@ var uiActions = require('../../services/ui/actions') +var mopidyActions = require('../../services/mopidy/actions') var lastfmActions = require('../../services/lastfm/actions') var helpers = require('../../helpers') @@ -912,6 +913,27 @@ export function getLibraryArtists(){ } +export function playArtistTopTracks(uri){ + return (dispatch, getState) => { + const artists = getState().ui.artists + + // Do we have this artist (and their tracks) in our index already? + if (typeof(artists[uri]) !== 'undefined' && typeof(artists[uri].tracks) !== 'undefined'){ + const uris = helpers.asURIs(artists[uri].tracks) + dispatch(mopidyActions.playURIs(uris, uri)) + + // We need to load the artist's top tracks first + } else { + sendRequest( dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/top-tracks?country='+getState().spotify.country ) + .then( response => { + const uris = helpers.asURIs(response.tracks) + dispatch(mopidyActions.playURIs(uris, uri)) + }) + } + } +} + + /** * =============================================================== USER(S) ============== diff --git a/src/js/services/ui/actions.js b/src/js/services/ui/actions.js index 89df0ffe..5a7c8c75 100755 --- a/src/js/services/ui/actions.js +++ b/src/js/services/ui/actions.js @@ -30,6 +30,13 @@ export function showContextMenu(data){ } } +export function setSlimMode(slim_mode){ + return { + type: 'SET_SLIM_MODE', + slim_mode: slim_mode + } +} + export function hideContextMenu(){ return { type: 'HIDE_CONTEXT_MENU' diff --git a/src/js/services/ui/middleware.js b/src/js/services/ui/middleware.js index 3e1a821c..4218771a 100755 --- a/src/js/services/ui/middleware.js +++ b/src/js/services/ui/middleware.js @@ -263,6 +263,8 @@ const UIMiddleware = (function(){ case 'OPEN_MODAL': ReactGA.event({ category: 'Modal', action: 'Opened', label: action.modal.name }) $('body').addClass('modal-open') + store.dispatch(uiActions.hideContextMenu()) + store.dispatch(uiActions.hideTouchContextMenu()) next(action) break diff --git a/src/js/services/ui/reducer.js b/src/js/services/ui/reducer.js index 9012205e..1aedd621 100755 --- a/src/js/services/ui/reducer.js +++ b/src/js/services/ui/reducer.js @@ -7,6 +7,9 @@ export default function reducer(ui = {}, action){ case 'LAZY_LOADING': return Object.assign({}, ui, { lazy_loading: action.start }); + case 'SET_SLIM_MODE': + return Object.assign({}, ui, { slim_mode: action.slim_mode }); + case 'DEBUG': return Object.assign({}, ui, { debug_response: action.response }) diff --git a/src/js/views/Album.js b/src/js/views/Album.js index e3738c51..cf82040a 100755 --- a/src/js/views/Album.js +++ b/src/js/views/Album.js @@ -4,6 +4,7 @@ import { connect } from 'react-redux' import { bindActionCreators } from 'redux' import FontAwesome from 'react-fontawesome' +import Header from '../components/Header' import TrackList from '../components/TrackList' import Thumbnail from '../components/Thumbnail' import Parallax from '../components/Parallax' @@ -12,7 +13,6 @@ import ArtistGrid from '../components/ArtistGrid' import FollowButton from '../components/FollowButton' import Dater from '../components/Dater' import LazyLoadListener from '../components/LazyLoadListener' -import SidebarToggleButton from '../components/SidebarToggleButton' import ContextMenuTrigger from '../components/ContextMenuTrigger' import * as helpers from '../helpers' @@ -121,7 +121,7 @@ class Album extends React.Component{ return ( - + {this.props.slim_mode ? this.handleContextMenu(e)} uiActions={this.props.uiActions} /> : null} @@ -132,13 +132,8 @@ class Album extends React.Component{ { this.props.album.name } - - - - {helpers.uriSource( this.props.params.uri )} {this.props.album.album_type ? this.props.album.album_type : 'album'} - - - { artists.length > 0 ? : null } + { !this.props.slim_mode ? {helpers.uriSource( this.props.params.uri )} {this.props.album.album_type ? this.props.album.album_type : 'album'} : null } + { !this.props.slim_mode && artists.length > 0 ? : null } { this.props.album.release_date ? : null } { this.props.album.tracks_total ? this.props.album.tracks_total : '0' } tracks, @@ -150,7 +145,7 @@ class Album extends React.Component{ this.play()}>Play { helpers.uriSource(this.props.params.uri) == 'spotify' ? : null } - this.handleContextMenu(e)} /> + {this.props.slim_mode ? null : this.handleContextMenu(e)} />} @@ -172,6 +167,7 @@ class Album extends React.Component{ const mapStateToProps = (state, ownProps) => { return { + slim_mode: state.ui.slim_mode, load_queue: state.ui.load_queue, artists: state.ui.artists, album: (state.ui.albums && typeof(state.ui.albums[ownProps.params.uri]) !== 'undefined' ? state.ui.albums[ownProps.params.uri] : false ), diff --git a/src/js/views/Artist.js b/src/js/views/Artist.js index 0edc933a..0de694db 100755 --- a/src/js/views/Artist.js +++ b/src/js/views/Artist.js @@ -31,7 +31,7 @@ class Artist extends React.Component{ } componentDidMount(){ - this.loadArtist(); + this.loadArtist() } componentWillReceiveProps( nextProps ){ @@ -201,7 +201,7 @@ class Artist extends React.Component{ return ( - + {this.props.slim_mode ? this.handleContextMenu(e)} uiActions={this.props.uiActions} /> : null} @@ -213,7 +213,7 @@ class Artist extends React.Component{ { can_play_radio ? this.props.pusherActions.startRadio([this.props.artist.uri])}>Start radio : this.props.mopidyActions.playURIs(this.props.artist.albums_uris, this.props.artist.uri)}>Play all} { can_follow ? : null} - this.handleContextMenu(e)} /> + {this.props.slim_mode ? null : this.handleContextMenu(e)} />} { this.renderSubViewMenu() } @@ -260,6 +260,7 @@ class Artist extends React.Component{ const mapStateToProps = (state, ownProps) => { return { + slim_mode: state.ui.slim_mode, load_queue: state.ui.load_queue, artist: (state.ui.artists && typeof(state.ui.artists[ownProps.params.uri]) !== 'undefined' ? state.ui.artists[ownProps.params.uri] : false ), artists: (state.ui.artists ? state.ui.artists : []), diff --git a/src/js/views/Debug.js b/src/js/views/Debug.js index 9b78e2eb..296b5119 100755 --- a/src/js/views/Debug.js +++ b/src/js/views/Debug.js @@ -43,7 +43,7 @@ class Debug extends React.Component{ var options = ( - hashHistory.push(global.baseURL+'settings')}> + hashHistory.push(global.baseURL+'settings')}> Back diff --git a/src/js/views/Playlist.js b/src/js/views/Playlist.js index 4d79ce2a..55bd3b51 100755 --- a/src/js/views/Playlist.js +++ b/src/js/views/Playlist.js @@ -12,7 +12,7 @@ import Dater from '../components/Dater' import ConfirmationButton from '../components/ConfirmationButton' import LazyLoadListener from '../components/LazyLoadListener' import FollowButton from '../components/FollowButton' -import SidebarToggleButton from '../components/SidebarToggleButton' +import Header from '../components/Header' import ContextMenuTrigger from '../components/ContextMenuTrigger' import * as helpers from '../helpers' @@ -115,7 +115,7 @@ class Playlist extends React.Component{ this.play() }>Play this.props.uiActions.openModal('edit_playlist', { uri: this.props.playlist.uri, name: this.props.playlist.name }) }>Edit - this.handleContextMenu(e)} /> + {this.props.slim_mode ? null : this.handleContextMenu(e)} />} ) @@ -125,7 +125,7 @@ class Playlist extends React.Component{ this.play() }>Play this.props.uiActions.openModal('edit_playlist', { uri: this.props.playlist.uri, name: this.props.playlist.name, is_public: this.props.playlist.public, description: this.props.playlist.description }) }>Edit - this.handleContextMenu(e)} /> + {this.props.slim_mode ? null : this.handleContextMenu(e)} />} ) } @@ -133,7 +133,7 @@ class Playlist extends React.Component{ this.play() }>Play - this.handleContextMenu(e)} /> + {this.props.slim_mode ? null : this.handleContextMenu(e)} />} ) @@ -141,7 +141,7 @@ class Playlist extends React.Component{ return ( this.play() }>Play - this.handleContextMenu(e)} /> + {this.props.slim_mode ? null : this.handleContextMenu(e)} />} ) } @@ -166,8 +166,8 @@ class Playlist extends React.Component{ return ( - - + + {this.props.slim_mode ? this.handleContextMenu(e)} uiActions={this.props.uiActions} /> : null} @@ -178,13 +178,8 @@ class Playlist extends React.Component{ { this.props.playlist.description ? : null } - - - - {helpers.uriSource( this.props.params.uri )} playlist - - - { this.props.playlist.owner ? {this.props.playlist.owner.id} : null } + { !this.props.slim_mode ? {helpers.uriSource( this.props.params.uri )} playlist : null } + { this.props.playlist.owner && !this.props.slim_mode ? {this.props.playlist.owner.id} : null } { this.props.playlist.followers ? {this.props.playlist.followers.total.toLocaleString()} followers : null } { this.props.playlist.last_modified ? : null } @@ -216,6 +211,7 @@ const mapStateToProps = (state, ownProps) => { var uri = ownProps.params.uri uri = uri.replace(' ','%20') return { + slim_mode: state.ui.slim_mode, load_queue: state.ui.load_queue, playlist: (state.ui.playlists && typeof(state.ui.playlists[uri]) !== 'undefined' ? state.ui.playlists[uri] : false ), library_playlists: state.ui.library_playlists, diff --git a/src/js/views/QueueHistory.js b/src/js/views/QueueHistory.js index cdb4e9c2..e0ffcd1c 100755 --- a/src/js/views/QueueHistory.js +++ b/src/js/views/QueueHistory.js @@ -39,7 +39,7 @@ class QueueHistory extends React.Component{ render(){ var options = ( - hashHistory.push(global.baseURL+'queue')}> + hashHistory.push(global.baseURL+'queue')}> Back @@ -47,7 +47,7 @@ class QueueHistory extends React.Component{ ) return ( - + diff --git a/src/js/views/Settings.js b/src/js/views/Settings.js index d2ed2441..ba656358 100755 --- a/src/js/views/Settings.js +++ b/src/js/views/Settings.js @@ -213,11 +213,11 @@ class Settings extends React.Component{ var options = ( - hashHistory.push(global.baseURL+'settings/debug')}> + hashHistory.push(global.baseURL+'settings/debug')}> Debug - + Help diff --git a/src/js/views/library/LibraryPlaylists.js b/src/js/views/library/LibraryPlaylists.js index 06e90864..3288c6fe 100755 --- a/src/js/views/library/LibraryPlaylists.js +++ b/src/js/views/library/LibraryPlaylists.js @@ -88,28 +88,44 @@ class LibraryPlaylists extends React.Component{ } if( this.props.view == 'list' ){ - var columns = [ - { - label: 'Name', - name: 'name' - }, - { - label: 'Owner', - name: 'owner' - }, - { - label: 'Source', - name: 'source' - }, - { - label: 'Tracks', - name: 'tracks_total' - }, - { - label: 'Editable', - name: 'can_edit' - } - ] + if (this.props.slim_mode){ + var columns = [ + { + label: 'Name', + name: 'name' + }, + { + label: 'Tracks', + name: 'tracks_total' + } + ] + } else { + var columns = [ + { + label: 'Name', + name: 'name' + }, + { + label: 'Owner', + name: 'owner' + }, + { + label: 'Source', + name: 'source' + }, + { + label: 'Tracks', + name: 'tracks_total' + }, + { + label: 'Editable', + name: 'can_edit' + } + ] + } + + console.log(columns) + return ( { return { + slim_mode: state.ui.slim_mode, load_queue: state.ui.load_queue, me_id: (state.spotify.me ? state.spotify.me.id : (state.ui.config && state.ui.config.spotify_username ? state.ui.config.spotify_username : false)), view: state.ui.library_playlists_view, diff --git a/src/scss/components/_context-menu.scss b/src/scss/components/_context-menu.scss index 7c215f10..affd523e 100755 --- a/src/scss/components/_context-menu.scss +++ b/src/scss/components/_context-menu.scss @@ -1,4 +1,12 @@ +@include responsive( $bp_medium ){ + body.context-menu-open { + .body { + @include blur(10px); + } + } +} + #context-menu { position: fixed; z-index: 99; @@ -228,7 +236,7 @@ right: 0; bottom: 0; left: 0; - background: $overlay_dark; + background: $overlay_light; z-index: 1; } diff --git a/src/scss/components/_header.scss b/src/scss/components/_header.scss index 03f799cb..b6d64506 100755 --- a/src/scss/components/_header.scss +++ b/src/scss/components/_header.scss @@ -64,6 +64,12 @@ main { -moz-filter: invert(1); filter: invert(1); } + + .context-menu-trigger { + .dot { + background: $white; + } + } } @include responsive( $bp_medium ){ diff --git a/src/scss/components/_lists.scss b/src/scss/components/_lists.scss index 514564c8..1eb82e27 100755 --- a/src/scss/components/_lists.scss +++ b/src/scss/components/_lists.scss @@ -22,13 +22,21 @@ &.selected { background: $yellow !important; border-color: darken($yellow,10%); + + .select-zone { + &::after { + background: $dark_grey; + border-color: $dark_grey; + } + } } &.playing { font-weight: bold; } - .state-icon { + .select-zone, + .drag-zone { display: none; } @@ -79,7 +87,8 @@ } } - :root .dragging &.hover { + :root .dragging &.hover, + &.touch-drag-hover { border-top: 3px solid $blue; margin-top: -3px; background: transparent; @@ -211,30 +220,51 @@ float: none; } - .state-icon { + .select-zone { position: absolute; top: 0; left: 0; height: 100%; - width: 48px; - font-size: 10px; + width: 38px; + font-size: 8px; display: block; .fa { position: absolute; - top: 19px; - left: 17px; + top: 20px; + left: 13px; + pointer-events: none; + color: $white; + z-index: 1; } &:after { display: block; content: ''; border: 1px solid $darkest_grey; - width: 15px; - height: 15px; + border-radius: 50%; + width: 14px; + height: 14px; position: absolute; - top: 15px; - left: 15px; + top: 16px; + left: 10px; + } + } + + .drag-zone { + position: absolute; + top: 0; + left: 38px; + height: 100%; + width: 38px; + font-size: 14px; + display: block; + + .fa { + position: absolute; + top: 17px; + left: 8px; + pointer-events: none; } } @@ -253,7 +283,7 @@ text-align: right; } - &:not(.name):not(.duration){ + &:not(.name):not(.duration):not(.album){ color: $mid_grey; display: inline; width: auto !important; @@ -261,10 +291,6 @@ word-wrap: break-word; } - &:not(.name):not(.duration):not(:nth-child(2)){ - @include bullet(); - } - &.followers_total:after { content: ' followers'; } @@ -277,6 +303,7 @@ content: '% popularity'; } + &.album, &.can_edit, &.release_date { display: none; @@ -306,8 +333,11 @@ } &.track-list { - .list-item { - padding: 7px 30px 7px 48px !important; + .list-item.has-drag-zone { + padding: 8px 30px 8px 78px !important; + } + .list-item:not(.has-drag-zone){ + padding: 8px 30px 8px 38px !important; } } } diff --git a/src/scss/global/_core.scss b/src/scss/global/_core.scss index 2bd2e950..80057362 100755 --- a/src/scss/global/_core.scss +++ b/src/scss/global/_core.scss @@ -14,6 +14,7 @@ body { overflow-y: scroll; overflow-x: hidden; + &.touch-dragging, &.modal-open { overflow-y: hidden; } diff --git a/src/scss/global/_variables.scss b/src/scss/global/_variables.scss index 31a17a5a..f79bbfe3 100755 --- a/src/scss/global/_variables.scss +++ b/src/scss/global/_variables.scss @@ -16,6 +16,7 @@ $blue: #32b5f2; $yellow: #FFF39C; $orange: #f16f19; $overlay_dark: rgba(0, 0, 0, 0.88); +$overlay_light: rgba(255, 255, 255, 0.70); $bp_wide: 1000px; $bp_medium: 800px; diff --git a/src/scss/views/_artist.scss b/src/scss/views/_artist.scss index 99447b25..9a92da30 100755 --- a/src/scss/views/_artist.scss +++ b/src/scss/views/_artist.scss @@ -139,8 +139,6 @@ } &.about { - padding: 0 20px 20px 20px; - .col.w40, .col.w60 { @include clearfix();