Context menus now at the view level
This commit is contained in:
@ -345,10 +345,10 @@ class ContextMenu extends React.Component{
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
<div id="context-menu" className={className} style={style}>
|
||||
<div className="liner">
|
||||
{this.renderTitle()}
|
||||
{this.renderItems()}
|
||||
{this.props.menu.context == 'custom' ? this.props.menu.options : this.renderItems()}
|
||||
</div>
|
||||
<div className="background" onClick={e => this.props.uiActions.hideContextMenu()}></div>
|
||||
</div>
|
||||
|
||||
@ -4,6 +4,7 @@ import FontAwesome from 'react-fontawesome'
|
||||
|
||||
import Icon from './Icon'
|
||||
import SidebarToggleButton from './SidebarToggleButton'
|
||||
import ContextMenuTrigger from './ContextMenuTrigger'
|
||||
|
||||
export default class Header extends React.Component{
|
||||
|
||||
@ -15,17 +16,25 @@ export default class Header extends React.Component{
|
||||
}
|
||||
}
|
||||
|
||||
renderActions(){
|
||||
if (!this.props.actions) return null
|
||||
handleContextMenuTrigger(e,options){
|
||||
e.preventDefault()
|
||||
var data = {
|
||||
e: e,
|
||||
context: 'custom',
|
||||
options: options
|
||||
}
|
||||
this.props.uiActions.showContextMenu(data)
|
||||
}
|
||||
|
||||
renderOptions(){
|
||||
if (!this.props.options) return null
|
||||
|
||||
return (
|
||||
<div className={this.state.expanded ? 'expanded actions' : 'actions'}>
|
||||
<button className="trigger" onClick={e => this.setState({expanded: !this.state.expanded})}>
|
||||
<FontAwesome name="ellipsis-v" />
|
||||
</button>
|
||||
<div className='options'>
|
||||
<ContextMenuTrigger onTrigger={e => this.handleContextMenuTrigger(e,this.props.options)} />
|
||||
<span className="items">
|
||||
<span className="liner">
|
||||
{ this.props.actions }
|
||||
{ this.props.options }
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@ -38,7 +47,7 @@ export default class Header extends React.Component{
|
||||
<Icon name={ this.props.icon } />
|
||||
<SidebarToggleButton />
|
||||
<h1>{ this.props.title }</h1>
|
||||
{this.renderActions()}
|
||||
{this.renderOptions()}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
@ -80,15 +80,6 @@ class List extends React.Component{
|
||||
var class_name = 'list-item'
|
||||
if( row.type ) class_name += ' '+row.type
|
||||
|
||||
var source_icon = null
|
||||
if (this.props.show_source_icon){
|
||||
if (row.source){
|
||||
source_icon = <FontAwesome className="source" name={helpers.sourceIcon(false,row.source)} />
|
||||
}else{
|
||||
source_icon = <FontAwesome className="source" name={helpers.sourceIcon(row.uri)} />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={e => this.handleClick(e, row.uri)}
|
||||
@ -104,7 +95,6 @@ class List extends React.Component{
|
||||
)
|
||||
})
|
||||
}
|
||||
{source_icon}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
@ -44,6 +44,7 @@ function handleUpdate() {
|
||||
ReactGA.set({ page: window.location.hash })
|
||||
ReactGA.pageview(window.location.hash)
|
||||
$(window).scrollTop(0)
|
||||
store.dispatch({type: 'HIDE_CONTEXT_MENU'})
|
||||
}
|
||||
|
||||
global.baseURL = '/'
|
||||
|
||||
@ -41,7 +41,7 @@ class Debug extends React.Component{
|
||||
|
||||
render(){
|
||||
|
||||
var actions = (
|
||||
var options = (
|
||||
<button onClick={e => hashHistory.push(global.baseURL+'settings')}>
|
||||
<FontAwesome name="reply" />
|
||||
Back
|
||||
@ -50,7 +50,7 @@ class Debug extends React.Component{
|
||||
|
||||
return (
|
||||
<div className="view debugger-view">
|
||||
<Header icon="cog" title="Debugger" actions={actions} />
|
||||
<Header icon="cog" title="Debugger" options={options} uiActions={this.props.uiActions} />
|
||||
|
||||
<section>
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ class Queue extends React.Component{
|
||||
}
|
||||
|
||||
render(){
|
||||
var actions = (
|
||||
var options = (
|
||||
<span>
|
||||
<button onClick={e => this.props.uiActions.openModal('kiosk_mode')}>
|
||||
<FontAwesome name="television" />
|
||||
@ -80,7 +80,7 @@ class Queue extends React.Component{
|
||||
|
||||
return (
|
||||
<div className="view queue-view">
|
||||
<Header icon="play" title="Now playing" actions={actions} />
|
||||
<Header icon="play" title="Now playing" options={options} uiActions={this.props.uiActions} />
|
||||
<FullPlayer />
|
||||
|
||||
<section className="list-wrapper">
|
||||
|
||||
@ -37,7 +37,7 @@ class QueueHistory extends React.Component{
|
||||
}
|
||||
|
||||
render(){
|
||||
var actions = (
|
||||
var options = (
|
||||
<span>
|
||||
<button onClick={e => hashHistory.push(global.baseURL+'queue')}>
|
||||
<FontAwesome name="reply" />
|
||||
@ -48,7 +48,7 @@ class QueueHistory extends React.Component{
|
||||
|
||||
return (
|
||||
<div className="view playback-history-view">
|
||||
<Header icon="play" title="Playback history" actions={actions} />
|
||||
<Header icon="play" title="Playback history" options={options} uiActions={this.props.uiActions} />
|
||||
|
||||
<section className="list-wrapper">
|
||||
<TrackList
|
||||
|
||||
@ -163,7 +163,7 @@ class Settings extends React.Component{
|
||||
|
||||
render(){
|
||||
|
||||
var actions = (
|
||||
var options = (
|
||||
<button onClick={e => hashHistory.push(global.baseURL+'debug')}>
|
||||
<FontAwesome name="flask" />
|
||||
Debug
|
||||
@ -172,7 +172,7 @@ class Settings extends React.Component{
|
||||
|
||||
return (
|
||||
<div className="view settings-view">
|
||||
<Header icon="cog" title="Settings" actions={actions} />
|
||||
<Header icon="cog" title="Settings" options={options} uiActions={this.props.uiActions} />
|
||||
|
||||
<section>
|
||||
|
||||
|
||||
@ -183,16 +183,16 @@ class LibraryAlbums extends React.Component{
|
||||
}
|
||||
]
|
||||
|
||||
var actions = (
|
||||
var options = (
|
||||
<span>
|
||||
<DropdownField icon="sort" name="Sort" value={this.props.sort} options={sort_options} reverse={this.props.sort_reverse} handleChange={val => this.setSort(val)} />
|
||||
<DropdownField icon="eye" name="View" value={this.props.view} options={view_options} handleChange={val => this.props.uiActions.set({ library_albums_view: val })} />
|
||||
<DropdownField icon="sort" name="Sort" value={this.props.sort} options={sort_options} reverse={this.props.sort_reverse} handleChange={val => {this.setSort(val); this.props.uiActions.hideContextMenu() }} />
|
||||
<DropdownField icon="eye" name="View" value={this.props.view} options={view_options} handleChange={val => {this.props.uiActions.set({ library_albums_view: val }); this.props.uiActions.hideContextMenu() }} />
|
||||
</span>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="view library-albums-view">
|
||||
<Header icon="cd" title="My albums" actions={actions} />
|
||||
<Header icon="cd" title="My albums" options={options} uiActions={this.props.uiActions} />
|
||||
{ this.renderView(albums) }
|
||||
<LazyLoadListener enabled={this.props.library_albums_more} loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
|
||||
@ -75,8 +75,7 @@ class LibraryArtists extends React.Component{
|
||||
handleContextMenu={(e,item) => this.handleContextMenu(e,item)}
|
||||
rows={artists}
|
||||
columns={columns}
|
||||
link_prefix={global.baseURL+"artist/"}
|
||||
show_source_icon={true} />
|
||||
link_prefix={global.baseURL+"artist/"} />
|
||||
</section>
|
||||
)
|
||||
}else{
|
||||
@ -132,16 +131,16 @@ class LibraryArtists extends React.Component{
|
||||
}
|
||||
]
|
||||
|
||||
var actions = (
|
||||
var options = (
|
||||
<span>
|
||||
<DropdownField icon="sort" name="Sort" value={ this.props.sort } options={sort_options} reverse={this.props.sort_reverse} handleChange={ value => this.setSort(value) } />
|
||||
<DropdownField icon="eye" name="View" value={ this.props.view } options={view_options} handleChange={ value => this.props.uiActions.set({ library_artists_view: value }) } />
|
||||
<DropdownField icon="sort" name="Sort" value={ this.props.sort } options={sort_options} reverse={this.props.sort_reverse} handleChange={value => {this.setSort(value); this.props.uiActions.hideContextMenu() }} />
|
||||
<DropdownField icon="eye" name="View" value={ this.props.view } options={view_options} handleChange={value => {this.props.uiActions.set({ library_artists_view: value }); this.props.uiActions.hideContextMenu()}} />
|
||||
</span>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="view library-artists-view">
|
||||
<Header icon="mic" title="My artists" actions={actions} />
|
||||
<Header icon="mic" title="My artists" options={options} uiActions={this.props.uiActions} />
|
||||
{ this.renderView(artists) }
|
||||
<LazyLoadListener enabled={this.props.library_artists_more} loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
|
||||
@ -141,16 +141,16 @@ class LibraryLocalAlbums extends React.Component{
|
||||
}
|
||||
]
|
||||
|
||||
var actions = (
|
||||
var options = (
|
||||
<span>
|
||||
<DropdownField icon="sort" name="Sort" value={this.props.sort} options={sort_options} reverse={this.props.sort_reverse} handleChange={val => this.setSort(val)} />
|
||||
<DropdownField icon="eye" name="View" value={this.props.view} options={view_options} handleChange={val => this.props.uiActions.set({ library_local_albums_view: val })} />
|
||||
<DropdownField icon="sort" name="Sort" value={this.props.sort} options={sort_options} reverse={this.props.sort_reverse} handleChange={val => {this.setSort(val); this.props.uiActions.hideContextMenu() }} />
|
||||
<DropdownField icon="eye" name="View" value={this.props.view} options={view_options} handleChange={val => {this.props.uiActions.set({ library_local_albums_view: val }); this.props.uiActions.hideContextMenu() }} />
|
||||
</span>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="view library-local-view">
|
||||
<Header icon="music" title="Local albums" actions={actions} />
|
||||
<Header icon="music" title="Local albums" options={options} uiActions={this.props.uiActions} />
|
||||
{this.renderView(albums)}
|
||||
<LazyLoadListener enabled={(this.moreURIsToLoad().length > 0)} loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
|
||||
@ -71,9 +71,9 @@ class LibraryLocalDirectory extends React.Component{
|
||||
|
||||
var items = this.arrange_directory( this.props.directory )
|
||||
|
||||
var actions = null
|
||||
var options = null
|
||||
if (this.props.params.uri != 'local:directory' ){
|
||||
actions = (
|
||||
options = (
|
||||
<button onClick={ () => window.history.back() }>
|
||||
<FontAwesome name="reply" />
|
||||
Back
|
||||
@ -83,7 +83,7 @@ class LibraryLocalDirectory extends React.Component{
|
||||
|
||||
return (
|
||||
<div className="view library-local-view">
|
||||
<Header icon="music" title="Local files" actions={actions} />
|
||||
<Header icon="music" title="Local files" options={options} uiActions={this.props.uiActions} />
|
||||
<section className="list-wrapper">
|
||||
<List
|
||||
columns={[{ name: 'name', width: '100'}]}
|
||||
|
||||
@ -69,6 +69,11 @@ class LibraryPlaylists extends React.Component{
|
||||
label: 'Owner',
|
||||
name: 'owner'
|
||||
},
|
||||
{
|
||||
width: 10,
|
||||
label: 'Source',
|
||||
name: 'source'
|
||||
},
|
||||
{
|
||||
width: 10,
|
||||
label: 'Tracks',
|
||||
@ -76,7 +81,7 @@ class LibraryPlaylists extends React.Component{
|
||||
},
|
||||
{
|
||||
width: 10,
|
||||
label: 'Can edit',
|
||||
label: 'Editable',
|
||||
name: 'can_edit'
|
||||
}
|
||||
]
|
||||
@ -86,8 +91,7 @@ class LibraryPlaylists extends React.Component{
|
||||
handleContextMenu={(e,item) => this.handleContextMenu(e,item)}
|
||||
rows={playlists}
|
||||
columns={columns}
|
||||
link_prefix={global.baseURL+"playlist/"}
|
||||
show_source_icon={true} />
|
||||
link_prefix={global.baseURL+"playlist/"} />
|
||||
</section>
|
||||
)
|
||||
}else{
|
||||
@ -137,20 +141,20 @@ class LibraryPlaylists extends React.Component{
|
||||
}
|
||||
]
|
||||
|
||||
var actions = (
|
||||
<div>
|
||||
<DropdownField icon="sort" name="Sort" value={this.props.sort} options={sort_options} reverse={this.props.sort_reverse} handleChange={val => this.setSort(val)} />
|
||||
<DropdownField icon="eye" name="View" value={this.props.view} options={view_options} handleChange={val => this.props.uiActions.set({ library_playlists_view: val}) } />
|
||||
var options = (
|
||||
<span>
|
||||
<DropdownField icon="sort" name="Sort" value={this.props.sort} options={sort_options} reverse={this.props.sort_reverse} handleChange={val => {this.setSort(val); this.props.uiActions.hideContextMenu() }} />
|
||||
<DropdownField icon="eye" name="View" value={this.props.view} options={view_options} handleChange={val => {this.props.uiActions.set({ library_playlists_view: val}); this.props.uiActions.hideContextMenu() }} />
|
||||
<button onClick={ () => this.props.uiActions.openModal('create_playlist', {} ) }>
|
||||
<FontAwesome name="plus" />
|
||||
New
|
||||
</button>
|
||||
</div>
|
||||
</span>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="view library-playlists-view">
|
||||
<Header icon="playlist" title="My playlists" actions={actions} />
|
||||
<Header icon="playlist" title="My playlists" options={options} uiActions={this.props.uiActions} />
|
||||
{ this.renderView() }
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
.context-menu {
|
||||
#context-menu {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
@ -135,6 +135,65 @@
|
||||
border-top: 1px solid lighten($dark_grey, 8%);
|
||||
}
|
||||
}
|
||||
|
||||
& > span {
|
||||
display: block;
|
||||
|
||||
button,
|
||||
.dropdown-field {
|
||||
display: block;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
min-width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
box-sizing: border-box;
|
||||
font-size: inherit;
|
||||
text-align: left;
|
||||
text-transform: none;
|
||||
font-weight: 300;
|
||||
color: inherit;
|
||||
border-top: 1px solid lighten($dark_grey, 8%);
|
||||
|
||||
.fa {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.notouch &:hover {
|
||||
background: lighten($dark_grey, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 16px 20px;
|
||||
min-width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.dropdown-field {
|
||||
padding: 0;
|
||||
|
||||
.label {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: block;
|
||||
position: static;
|
||||
background: lighten($dark_grey, 10%);
|
||||
|
||||
.option {
|
||||
padding: 16px 20px 16px 50px;
|
||||
border-top: 1px solid lighten($dark_grey, 8%);
|
||||
|
||||
.fa {
|
||||
display: inline-block;
|
||||
left: 25px;
|
||||
top: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( null, $bp_medium ){
|
||||
|
||||
@ -48,34 +48,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( $bp_medium ){
|
||||
&.expanded {
|
||||
background: none !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.label {
|
||||
background: none !important;
|
||||
color: inherit !important;
|
||||
|
||||
.fa {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
display: block;
|
||||
position: relative;
|
||||
top: 0;
|
||||
background: lighten($light_grey,5%);
|
||||
|
||||
.option {
|
||||
color: #000000;
|
||||
border-color: $light_grey;
|
||||
background: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,11 +23,17 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
.options {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
|
||||
.context-menu-trigger {
|
||||
display: none;
|
||||
font-size: 18px;
|
||||
padding: 16px 14px;
|
||||
}
|
||||
|
||||
button {
|
||||
background: transparent;
|
||||
font-size: 14px;
|
||||
@ -43,74 +49,20 @@ main {
|
||||
&:active {
|
||||
background: rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
&.trigger {
|
||||
display: none;
|
||||
font-size: 18px;
|
||||
padding: 16px 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( $bp_medium ){
|
||||
.actions {
|
||||
.options {
|
||||
right: 0;
|
||||
|
||||
button.trigger {
|
||||
display: inline-block;
|
||||
.context-menu-trigger {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.items {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
z-index: 98;
|
||||
|
||||
button.trigger {
|
||||
z-index: 99;
|
||||
color: #FFFFFF;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.items {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: rgba(0,0,0,0.9);
|
||||
overflow-y: scroll;
|
||||
|
||||
.liner {
|
||||
display: block;
|
||||
width: 200px;
|
||||
margin: 30px auto;
|
||||
background: $light_grey;
|
||||
}
|
||||
|
||||
button,
|
||||
.dropdown-field {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.1);
|
||||
|
||||
.fa {
|
||||
width: 1.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&.dropdown-field {
|
||||
.label {
|
||||
padding-left: 14px;
|
||||
padding-right: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user