Splitting submenu outside of menu__item

This commit is contained in:
James Barnsley
2018-11-13 16:44:51 +13:00
parent 1ab70f7edd
commit 6b75a01127
6 changed files with 13949 additions and 10637 deletions

View File

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

View File

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

View File

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

View File

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