Splitting submenu outside of menu__item
This commit is contained in:
@ -3784,6 +3784,14 @@ input[type="submit"] {
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
text-transform: capitalize; }
|
text-transform: capitalize; }
|
||||||
|
.context-menu__items {
|
||||||
|
-webkit-transition: all 0.2s ease-in-out;
|
||||||
|
-moz-transition: all 0.2s ease-in-out;
|
||||||
|
-o-transition: all 0.2s ease-in-out;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
opacity: 1;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2; }
|
||||||
.context-menu__item {
|
.context-menu__item {
|
||||||
display: block;
|
display: block;
|
||||||
overflow-x: hidden; }
|
overflow-x: hidden; }
|
||||||
@ -3841,22 +3849,28 @@ input[type="submit"] {
|
|||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
width: 0;
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
background: #52514d;
|
background: #52514d;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
transform: translateX(100%); }
|
transform: translateX(100%);
|
||||||
|
opacity: 0; }
|
||||||
.context-menu__submenu .context-menu__item {
|
.context-menu__submenu .context-menu__item {
|
||||||
width: 100%; }
|
width: 100%; }
|
||||||
.context-menu__submenu .context-menu__item.close-submenu {
|
.context-menu__submenu .context-menu__item--close-submenu {
|
||||||
color: #a3a19f; }
|
opacity: 0.5; }
|
||||||
.context-menu__submenu .context-menu__item__label .icon {
|
.context-menu__submenu .context-menu__item__label .icon {
|
||||||
margin-bottom: 0.4em;
|
margin-bottom: 0.4em;
|
||||||
padding-right: 6px; }
|
padding-right: 6px; }
|
||||||
|
.context-menu--submenu-expanded .context-menu__items {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
opacity: 0; }
|
||||||
|
.context-menu--submenu-expanded .context-menu__submenu {
|
||||||
|
transform: translateX(0);
|
||||||
|
opacity: 1; }
|
||||||
@media (max-width: 800px) {
|
@media (max-width: 800px) {
|
||||||
.context-menu {
|
.context-menu {
|
||||||
top: 0 !important;
|
top: 0 !important;
|
||||||
@ -3918,16 +3932,15 @@ input[type="submit"] {
|
|||||||
border-radius: 3px 3px 0 0; }
|
border-radius: 3px 3px 0 0; }
|
||||||
.context-menu__divider {
|
.context-menu__divider {
|
||||||
display: none; }
|
display: none; }
|
||||||
.context-menu__items {
|
.context-menu__item {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 800;
|
||||||
|
opacity: 1; }
|
||||||
|
.context-menu__item__link {
|
||||||
-webkit-transition: all 0.2s ease-in-out;
|
-webkit-transition: all 0.2s ease-in-out;
|
||||||
-moz-transition: all 0.2s ease-in-out;
|
-moz-transition: all 0.2s ease-in-out;
|
||||||
-o-transition: all 0.2s ease-in-out;
|
-o-transition: all 0.2s ease-in-out;
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
opacity: 1; }
|
|
||||||
.context-menu__item {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
font-weight: 800; }
|
|
||||||
.context-menu__item__link {
|
|
||||||
padding: 16px 22px;
|
padding: 16px 22px;
|
||||||
box-sizing: border-box; }
|
box-sizing: border-box; }
|
||||||
.context-menu__item__link:before {
|
.context-menu__item__link:before {
|
||||||
@ -3935,16 +3948,12 @@ input[type="submit"] {
|
|||||||
.context-menu__item__link:focus, .context-menu__item__link:active {
|
.context-menu__item__link:focus, .context-menu__item__link:active {
|
||||||
background: #08d58f !important; }
|
background: #08d58f !important; }
|
||||||
.context-menu__submenu {
|
.context-menu__submenu {
|
||||||
width: 100%;
|
width: 250px;
|
||||||
|
margin: 30px auto;
|
||||||
|
max-width: 90vw;
|
||||||
background: none;
|
background: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
opacity: 0; }
|
opacity: 0; } }
|
||||||
.context-menu--submenu-expanded .context-menu__items {
|
|
||||||
transform: translateX(-100%);
|
|
||||||
opacity: 0; }
|
|
||||||
.context-menu--submenu-expanded .context-menu__submenu {
|
|
||||||
transform: translateX(0%);
|
|
||||||
opacity: 1; } }
|
|
||||||
|
|
||||||
.context-menu-trigger {
|
.context-menu-trigger {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -98,7 +98,7 @@
|
|||||||
|
|
||||||
// Release details
|
// Release details
|
||||||
// These are automatically injected to built HTML
|
// These are automatically injected to built HTML
|
||||||
var build = "1542004237";
|
var build = "1542050679";
|
||||||
var version = "3.30.0";
|
var version = "3.30.0";
|
||||||
|
|
||||||
// Construct the script tag
|
// Construct the script tag
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class ContextMenu extends React.Component{
|
|||||||
constructor(props){
|
constructor(props){
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
submenu_expanded: false
|
submenu: null
|
||||||
}
|
}
|
||||||
this.handleScroll = this.handleScroll.bind(this);
|
this.handleScroll = this.handleScroll.bind(this);
|
||||||
this.handleMouseDown = this.handleMouseDown.bind(this);
|
this.handleMouseDown = this.handleMouseDown.bind(this);
|
||||||
@ -44,7 +44,7 @@ class ContextMenu extends React.Component{
|
|||||||
|
|
||||||
// if we've been given a menu object (ie activated) when we didn't have one prior
|
// if we've been given a menu object (ie activated) when we didn't have one prior
|
||||||
if (nextProps.menu && !this.props.menu){
|
if (nextProps.menu && !this.props.menu){
|
||||||
this.setState({ submenu_expanded: false });
|
this.setState({ submenu: null });
|
||||||
|
|
||||||
var context = this.getContext(nextProps);
|
var context = this.getContext(nextProps);
|
||||||
|
|
||||||
@ -320,53 +320,6 @@ class ContextMenu extends React.Component{
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPlaylistSubmenu(){
|
|
||||||
var playlists = []
|
|
||||||
for (var uri in this.props.playlists){
|
|
||||||
if (this.props.playlists[uri].can_edit) playlists.push(this.props.playlists[uri])
|
|
||||||
}
|
|
||||||
|
|
||||||
playlists = helpers.sortItems(playlists, 'name')
|
|
||||||
|
|
||||||
var loader = null
|
|
||||||
if (this.props.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR && this.props.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR.status == 'running'){
|
|
||||||
loader = (
|
|
||||||
<div className="context-menu__item">
|
|
||||||
<div className="context-menu__item mini-loader loading">
|
|
||||||
<div className="loader"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
var list = <span className="context-menu__item"><span className="context-menu__item mid_grey-text">No writable playlists</span></span>
|
|
||||||
if (playlists.length > 0){
|
|
||||||
list = playlists.map(playlist => {
|
|
||||||
return (
|
|
||||||
<span className="context-menu__item" key={playlist.uri}>
|
|
||||||
<a className="context-menu__item__link" onClick={e => this.addTracksToPlaylist(e,playlist.uri) }>
|
|
||||||
<span className="context-menu__item__label">{ playlist.name }</span>
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={'context-menu__submenu' + (this.state.submenu_expanded ? ' context-menu__submenu--expanded' : '')}>
|
|
||||||
<div className="context-menu__item">
|
|
||||||
<a className="context-menu__item__link context-menu__item__link--close-submenu" onClick={e => this.setState({submenu_expanded: false})}>
|
|
||||||
<span className="context-menu__item__label">
|
|
||||||
<Icon name="arrow_back" />Back
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{list}
|
|
||||||
{loader}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTitle(){
|
renderTitle(){
|
||||||
var context = this.getContext()
|
var context = this.getContext()
|
||||||
|
|
||||||
@ -420,10 +373,9 @@ class ContextMenu extends React.Component{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPlaylistSubmenu(expanded = !this.state.submenu_expanded){
|
setSubmenu(name){
|
||||||
this.setState({submenu_expanded: expanded})
|
|
||||||
|
|
||||||
if (expanded){
|
if (this.state.submenu !== name && name == 'add-to-playlist'){
|
||||||
if (!this.props.spotify_library_playlists_loaded_all){
|
if (!this.props.spotify_library_playlists_loaded_all){
|
||||||
this.props.spotifyActions.getLibraryPlaylists()
|
this.props.spotifyActions.getLibraryPlaylists()
|
||||||
}
|
}
|
||||||
@ -431,6 +383,63 @@ class ContextMenu extends React.Component{
|
|||||||
this.props.mopidyActions.getLibraryPlaylists()
|
this.props.mopidyActions.getLibraryPlaylists()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setState({submenu: name});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSubmenu(){
|
||||||
|
var list = null;
|
||||||
|
var loader = null;
|
||||||
|
|
||||||
|
switch (this.state.submenu){
|
||||||
|
|
||||||
|
case 'add-to-playlist':
|
||||||
|
|
||||||
|
var playlists = []
|
||||||
|
for (var uri in this.props.playlists){
|
||||||
|
if (this.props.playlists[uri].can_edit) playlists.push(this.props.playlists[uri])
|
||||||
|
}
|
||||||
|
|
||||||
|
playlists = helpers.sortItems(playlists, 'name')
|
||||||
|
|
||||||
|
if (this.props.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR && this.props.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR.status == 'running'){
|
||||||
|
loader = (
|
||||||
|
<div className="context-menu__item">
|
||||||
|
<div className="context-menu__item mini-loader loading">
|
||||||
|
<div className="loader"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
list = <span className="context-menu__item"><span className="context-menu__item mid_grey-text">No writable playlists</span></span>
|
||||||
|
if (playlists.length > 0){
|
||||||
|
list = playlists.map(playlist => {
|
||||||
|
return (
|
||||||
|
<span className="context-menu__item" key={playlist.uri}>
|
||||||
|
<a className="context-menu__item__link" onClick={e => this.addTracksToPlaylist(e,playlist.uri) }>
|
||||||
|
<span className="context-menu__item__label">{ playlist.name }</span>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='context-menu__submenu'>
|
||||||
|
<div className="context-menu__item">
|
||||||
|
<a className="context-menu__item__link context-menu__item__link--close-submenu" onClick={e => this.setState({submenu: null})}>
|
||||||
|
<span className="context-menu__item__label">
|
||||||
|
<Icon name="arrow_back" /> Back
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{list}
|
||||||
|
{loader}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderItems(){
|
renderItems(){
|
||||||
@ -494,11 +503,10 @@ class ContextMenu extends React.Component{
|
|||||||
|
|
||||||
var add_to_playlist = (
|
var add_to_playlist = (
|
||||||
<div className="context-menu__item context-menu__item--has-submenu">
|
<div className="context-menu__item context-menu__item--has-submenu">
|
||||||
<a className="context-menu__item__link" onClick={e => this.setPlaylistSubmenu()}>
|
<a className="context-menu__item__link" onClick={e => this.setSubmenu('add-to-playlist')}>
|
||||||
<span className="context-menu__item__label">Add to playlist</span>
|
<span className="context-menu__item__label">Add to playlist</span>
|
||||||
<Icon className="submenu-icon" name="arrow_forward" />
|
<Icon className="submenu-icon" name="arrow_forward" />
|
||||||
</a>
|
</a>
|
||||||
{this.renderPlaylistSubmenu()}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -737,7 +745,9 @@ class ContextMenu extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
if (!this.props.menu) return null;
|
if (!this.props.menu){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var style = {
|
var style = {
|
||||||
left: this.props.menu.position_x,
|
left: this.props.menu.position_x,
|
||||||
@ -745,14 +755,15 @@ class ContextMenu extends React.Component{
|
|||||||
}
|
}
|
||||||
var height = 200 // TODO: use jquery to detect height
|
var height = 200 // TODO: use jquery to detect height
|
||||||
var className = "context-menu "+this.props.menu.context
|
var className = "context-menu "+this.props.menu.context
|
||||||
if (this.state.submenu_expanded){
|
if (this.state.submenu){
|
||||||
className += ' context-menu--submenu-expanded'
|
className += ' context-menu--submenu-expanded';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.menu.position_x > (window.innerWidth - 174)){
|
if (this.props.menu.position_x > (window.innerWidth - 174)){
|
||||||
style.left = 'auto';
|
style.left = 'auto';
|
||||||
style.right = 10;
|
style.right = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.menu.position_y > (window.innerHeight - height)){
|
if (this.props.menu.position_y > (window.innerHeight - height)){
|
||||||
style.top = 'auto';
|
style.top = 'auto';
|
||||||
style.bottom = 10;
|
style.bottom = 10;
|
||||||
@ -763,6 +774,7 @@ class ContextMenu extends React.Component{
|
|||||||
<div className="context-menu__inner">
|
<div className="context-menu__inner">
|
||||||
{this.renderTitle()}
|
{this.renderTitle()}
|
||||||
{this.props.menu.context == 'custom' ? this.props.menu.options : this.renderItems()}
|
{this.props.menu.context == 'custom' ? this.props.menu.options : this.renderItems()}
|
||||||
|
{this.renderSubmenu()}
|
||||||
</div>
|
</div>
|
||||||
<div className="context-menu__background" onClick={e => this.props.uiActions.hideContextMenu()}></div>
|
<div className="context-menu__background" onClick={e => this.props.uiActions.hideContextMenu()}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -169,6 +169,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__items {
|
||||||
|
@include animate();
|
||||||
|
opacity: 1;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
&__item {
|
&__item {
|
||||||
display: block;
|
display: block;
|
||||||
@ -219,22 +225,22 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
width: 0;
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
background: lighten(colour(grey), 10%);
|
background: lighten(colour(grey), 10%);
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
.context-menu {
|
.context-menu {
|
||||||
&__item {
|
&__item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
&.close-submenu {
|
&--close-submenu {
|
||||||
color: colour(mid_grey);
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__label {
|
&__label {
|
||||||
@ -247,6 +253,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--submenu-expanded {
|
||||||
|
.context-menu {
|
||||||
|
|
||||||
|
&__items {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__submenu {
|
||||||
|
transform: translateX(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@include responsive($bp_medium){
|
@include responsive($bp_medium){
|
||||||
top: 0 !important;
|
top: 0 !important;
|
||||||
@ -268,7 +289,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__inner {
|
&__inner {
|
||||||
@include animate(0.2s);
|
@include animate();
|
||||||
width: 250px;
|
width: 250px;
|
||||||
margin: 30px auto;
|
margin: 30px auto;
|
||||||
max-width: 90vw;
|
max-width: 90vw;
|
||||||
@ -312,16 +333,13 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__items {
|
|
||||||
@include animate();
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item {
|
&__item {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
&__link {
|
&__link {
|
||||||
|
@include animate();
|
||||||
padding: 16px 22px;
|
padding: 16px 22px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
@ -337,25 +355,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__submenu {
|
&__submenu {
|
||||||
width: 100%;
|
width: 250px;
|
||||||
|
margin: 30px auto;
|
||||||
|
max-width: 90vw;
|
||||||
background: none;
|
background: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--submenu-expanded {
|
|
||||||
.context-menu {
|
|
||||||
&__items {
|
|
||||||
transform: translateX(-100%);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__submenu {
|
|
||||||
transform: translateX(0%);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user