diff --git a/src/js/components/ContextMenu.js b/src/js/components/ContextMenu.js
index 207b019f..537afee6 100755
--- a/src/js/components/ContextMenu.js
+++ b/src/js/components/ContextMenu.js
@@ -1,6 +1,6 @@
import React, { PropTypes } from 'react'
-import { Link } from 'react-router'
+import { Link, hashHistory } from 'react-router'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import FontAwesome from 'react-fontawesome'
@@ -30,12 +30,17 @@ class ContextMenu extends React.Component{
window.removeEventListener("click", this.handleClick, false)
}
- handleScroll(){
- if (this.props.menu) this.props.uiActions.hideContextMenu()
+ handleScroll(e){
+ if (this.props.menu){
+ this.props.uiActions.hideContextMenu()
+ }
}
- handleClick(){
- if (this.props.menu) this.props.uiActions.hideContextMenu()
+ handleClick(e){
+ var target = e.target
+ if (this.props.menu && !target.classList.contains('context-menu-trigger')){
+ this.props.uiActions.hideContextMenu()
+ }
}
playQueueItem(){
@@ -89,6 +94,10 @@ class ContextMenu extends React.Component{
this.props.uiActions.hideContextMenu();
}
+ goToUser(){
+ hashHistory.push( global.baseURL +'user/'+ this.props.menu.item.owner.uri );
+ }
+
copyURIs(e){
var temp = $("");
$("body").append(temp);
@@ -100,6 +109,17 @@ class ContextMenu extends React.Component{
this.props.uiActions.hideContextMenu()
}
+ copyLinks(e){
+ var temp = $("");
+ $("body").append(temp);
+ temp.val(this.props.menu.item.external_urls.spotify).select();
+ document.execCommand("copy");
+ temp.remove();
+
+ this.props.uiActions.createNotification( "Copied link" )
+ this.props.uiActions.hideContextMenu()
+ }
+
closeAndDeselectTracks(){
this.props.uiActions.hideContextMenu();
}
@@ -137,8 +157,10 @@ class ContextMenu extends React.Component{
{ handleClick: 'playURIs', label: 'Play' },
{ handleClick: 'playURIsNext', label: 'Play next' },
{ handleClick: 'addToQueue', label: 'Add to queue' },
+ { handleClick: 'goToArtist', label: 'Go to artist' },
// { handleClick: 'toggleFollow', label: 'Follow/unfollow' }, TODO
- { handleClick: 'copyURIs', label: 'Copy URI' }
+ { handleClick: 'copyURIs', label: 'Copy URI' },
+ { handleClick: 'copyLinks', label: 'Copy link' }
]
break
@@ -146,15 +168,18 @@ class ContextMenu extends React.Component{
var items = [
//{ handleClick: 'toggleFollow', label: 'Follow/unfollow' }, TODO
{ handleClick: 'startRadio', label: 'Start radio' },
- { handleClick: 'copyURIs', label: 'Copy URI' }
+ { handleClick: 'copyURIs', label: 'Copy URI' },
+ { handleClick: 'copyLinks', label: 'Copy link' }
]
break
case 'playlist':
var items = [
{ handleClick: 'playURIs', label: 'Play' },
+ { handleClick: 'goToUser', label: 'Go to user' },
// { handleClick: 'toggleFollow', label: 'Follow/unfollow' }, TODO
- { handleClick: 'copyURIs', label: 'Copy URI' }
+ { handleClick: 'copyURIs', label: 'Copy URI' },
+ { handleClick: 'copyLinks', label: 'Copy link' }
]
break
@@ -205,6 +230,11 @@ class ContextMenu extends React.Component{
return (
{style ?
: null}
+
+ {helpers.uriSource(item.uri)}
+
+ {this.props.menu.context}
+
{item.name}
)
@@ -264,8 +294,10 @@ class ContextMenu extends React.Component{
return (
- {this.props.menu.item ? this.renderTitle() : null}
- {this.renderItems()}
+
+ {this.props.menu.item ? this.renderTitle() : null}
+ {this.renderItems()}
+
);
}
diff --git a/src/js/views/Album.js b/src/js/views/Album.js
index 640d0eee..ebfe8d3a 100755
--- a/src/js/views/Album.js
+++ b/src/js/views/Album.js
@@ -49,6 +49,16 @@ class Album extends React.Component{
}
}
+ handleContextMenu(e){
+ var data = {
+ e: e,
+ context: 'album',
+ item: this.props.album,
+ uris: [this.props.params.uri]
+ }
+ this.props.uiActions.showContextMenu(data)
+ }
+
loadAlbum( props = this.props ){
switch( helpers.uriSource( props.params.uri ) ){
@@ -119,6 +129,7 @@ class Album extends React.Component{
{ helpers.uriSource(this.props.params.uri) == 'spotify' ? : null }
+
diff --git a/src/js/views/App.js b/src/js/views/App.js
index 44f9b279..0c49d208 100755
--- a/src/js/views/App.js
+++ b/src/js/views/App.js
@@ -122,7 +122,11 @@ 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 (helpers.isTouchDevice() || this.props.emulate_touch) className += ' can-touch'
+ if (helpers.isTouchDevice() || this.props.emulate_touch){
+ className += ' touch'
+ } else {
+ className += ' notouch'
+ }
return (
diff --git a/src/js/views/Artist.js b/src/js/views/Artist.js
index aea04edc..0a4b32ac 100755
--- a/src/js/views/Artist.js
+++ b/src/js/views/Artist.js
@@ -54,6 +54,16 @@ class Artist extends React.Component{
}
}
+ handleContextMenu(e){
+ var data = {
+ e: e,
+ context: 'artist',
+ item: this.props.artist,
+ uris: [this.props.params.uri]
+ }
+ this.props.uiActions.showContextMenu(data)
+ }
+
loadArtist( props = this.props ){
switch( helpers.uriSource( props.params.uri ) ){
@@ -204,7 +214,7 @@ class Artist extends React.Component{
{ can_play_radio ? : null}
{ can_follow ? : null}
-
+
{ this.renderSubViewMenu() }
diff --git a/src/js/views/Playlist.js b/src/js/views/Playlist.js
index fef4e085..a7191e3d 100755
--- a/src/js/views/Playlist.js
+++ b/src/js/views/Playlist.js
@@ -39,6 +39,16 @@ class Playlist extends React.Component{
}
}
+ handleContextMenu(e){
+ var data = {
+ e: e,
+ context: (this.props.playlist.can_edit ? 'editable-playlist' : 'playlist'),
+ item: this.props.playlist,
+ uris: [this.props.params.uri]
+ }
+ this.props.uiActions.showContextMenu(data)
+ }
+
loadPlaylist( props = this.props ){
switch( helpers.uriSource( props.params.uri ) ){
@@ -97,7 +107,7 @@ class Playlist extends React.Component{
- this.delete() } />
+
)
@@ -107,7 +117,7 @@ class Playlist extends React.Component{
- this.unfollow() } />
+
)
}
@@ -115,6 +125,7 @@ class Playlist extends React.Component{
+
)
@@ -122,6 +133,7 @@ class Playlist extends React.Component{
return (
+
)
}
diff --git a/src/scss/components/_context-menu.scss b/src/scss/components/_context-menu.scss
index 1b634625..e327c6a2 100755
--- a/src/scss/components/_context-menu.scss
+++ b/src/scss/components/_context-menu.scss
@@ -4,169 +4,154 @@
left: 0;
top: 0;
z-index: 99;
- background: $dark_grey;
- color: #FFFFFF;
- &.right-align {
- margin-left: -140px;
- }
+ .liner {
+ background: $dark_grey;
+ color: #FFFFFF;
- &.right-align-submenu .submenu {
- left: auto !important;
- right: 140px !important;
- }
-
- &.bottom-align-submenu .submenu {
- top: auto !important;
- bottom: 0 !important;
- }
-
- .title {
- cursor: pointer;
- display: block;
- padding: 8px 12px;
- width: 140px;
- font-weight: bold;
- box-sizing: border-box;
- position: relative;
- overflow: hidden;
- text-decoration: none;
- background: $darkest_grey;
-
- .background {
- @include blur(5px);
- background-size: cover;
- background-position: 50% 20%;
- opacity: 0.5;
- position: absolute;
- top: -10px;
- left: -10px;
- bottom: -10px;
- right: -10px;
- z-index: 1;
+ &.right-align {
+ margin-left: -140px;
}
- .text {
- @include one_line_text();
- position: relative;
- z-index: 2;
- color: #FFFFFF;
+ &.right-align-submenu .submenu {
+ left: auto !important;
+ right: 140px !important;
}
- &:hover{
- .background {
- opacity: 0.7;
- }
+ &.bottom-align-submenu .submenu {
+ top: auto !important;
+ bottom: 0 !important;
}
- }
- .menu-item-wrapper {
- display: block;
- position: relative;
-
- .menu-item {
+ .title {
cursor: pointer;
display: block;
padding: 8px 12px;
width: 140px;
- box-sizing: border-box;
- }
+ font-weight: bold;
+ box-sizing: border-box;
+ position: relative;
+ overflow: hidden;
+ text-decoration: none;
+ background: $darkest_grey;
- .icon {
- display: none;
- }
+ .background {
+ @include blur(5px);
+ background-size: cover;
+ background-position: 50% 20%;
+ opacity: 0.5;
+ position: absolute;
+ top: -10px;
+ left: -10px;
+ bottom: -10px;
+ right: -10px;
+ z-index: 1;
+ }
- .submenu-icon {
- font-size: 10px;
- float: right;
- padding-top: 4px;
- }
+ .text {
+ @include one_line_text();
+ position: relative;
+ z-index: 2;
+ color: #FFFFFF;
+ }
- .submenu {
- display: none;
- position: absolute;
- left: 140px;
- top: 0;
- max-height: 200px;
- overflow-y: scroll;
- background: lighten($dark_grey, 5%);
+ .type {
+ position: relative;
+ z-index: 2;
+ color: #FFFFFF;
+ opacity: 0.5;
+ font-weight: 200;
+ text-transform: capitalize;
+ }
- .menu-item {
- width: 140px;
- &:hover {
- background: lighten($dark_grey, 10%);
+ &:hover{
+ .background {
+ opacity: 0.7;
}
}
}
- .menu-item {
- border-top: 1px solid lighten($dark_grey, 8%);
- }
+ .menu-item-wrapper {
+ display: block;
+ position: relative;
- &:hover {
.menu-item {
- background: lighten($dark_grey, 5%);
- }
- .submenu {
+ cursor: pointer;
display: block;
+ padding: 8px 12px;
+ width: 140px;
+ box-sizing: border-box;
+ }
+
+ .icon {
+ display: none;
+ }
+
+ .submenu-icon {
+ font-size: 10px;
+ float: right;
+ padding-top: 4px;
+ }
+
+ .submenu {
+ display: none;
+ position: absolute;
+ left: 140px;
+ top: 0;
+ max-height: 200px;
+ overflow-y: scroll;
+ background: lighten($dark_grey, 5%);
+
+ .menu-item {
+ width: 140px;
+ &:hover {
+ background: lighten($dark_grey, 10%);
+ }
+ }
+ }
+
+ .menu-item {
+ border-top: 1px solid lighten($dark_grey, 8%);
+ }
+
+ &:hover {
+ .menu-item {
+ background: lighten($dark_grey, 5%);
+ }
+ .submenu {
+ display: block;
+ }
+ }
+ }
+ }
+
+ @include responsive( $bp_medium ){
+ top: 0 !important;
+ right: 0 !important;
+ bottom: 0 !important;
+ left: 0 !important;
+ margin: 0 !important;
+ background: rgba(10, 10, 10, 0.95);
+ overflow-y: scroll;
+
+ .liner {
+ width: 250px;
+ margin: 30px auto;
+ max-width: 90vw;
+
+ .title {
+ padding: 16px 20px;
+ width: 100%;
+ box-sizing: border-box;
+ }
+
+ .menu-item-wrapper {
+ .menu-item {
+ padding: 16px 20px;
+ width: 100%;
+ box-sizing: border-box;
+ }
}
}
}
}
-
-.touch-context-menu {
- position: fixed;
- z-index: 99;
- bottom: 0;
- left: 0;
- right: 0;
- top: auto;
- background: $blue;
- color: #FFFFFF;
-
- .menu-item-wrapper {
- display: inline-block;
-
- .menu-item {
- display: inline-block;
- text-align: center;
- width: 50px;
- height: 44px;
- padding-top: 6px;
- border: 0;
- 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;
- }
- }
-
- &.cancel {
- float: right;
- opacity: 0.5;
- }
-
- &:not(:first-child) .menu-item {
- border-left: 1px solid rgba(255,255,255,0.2) !important;
- }
- }
-}
\ No newline at end of file
diff --git a/src/scss/global/_forms.scss b/src/scss/global/_forms.scss
index 1f4c80e9..729bf5a2 100755
--- a/src/scss/global/_forms.scss
+++ b/src/scss/global/_forms.scss
@@ -144,6 +144,39 @@ input[type="submit"] {
}
}
+ &.context-menu-trigger {
+ border-color: transparent;
+ padding: 6px;
+ font-size: 20px;
+ min-width: 0;
+ line-height: 20px;
+ color: #000000;
+
+ &:hover {
+ border-color: transparent;
+ background: rgba(0,0,0,0.1);
+ }
+
+ &:active {
+ color: #FFFFFF;
+ background: #000000;
+ }
+
+ &.white {
+ color: #FFFFFF;
+
+ &:hover {
+ border-color: transparent;
+ background: rgba(255,255,255,0.1);
+ }
+
+ &:active {
+ color: #000000;
+ background: #FFFFFF;
+ }
+ }
+ }
+
&[disabled],
&[disabled="disabled"]{
opacity: 0.5;