Editing playlist modal
This commit is contained in:
@ -13,6 +13,7 @@ export default class Header extends React.Component{
|
||||
<header>
|
||||
<Icon name={ this.props.icon } />
|
||||
<h1>{ this.props.title }</h1>
|
||||
{ this.props.actions ? <div className="actions">{ this.props.actions }</div> : null }
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,160 +0,0 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
|
||||
import Icon from './Icon'
|
||||
import * as helpers from '../helpers'
|
||||
|
||||
import * as uiActions from '../services/ui/actions'
|
||||
import * as mopidyActions from '../services/mopidy/actions'
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
|
||||
class Modal extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {
|
||||
playlist_name: '',
|
||||
playlist_scheme: 'spotify',
|
||||
playlist_private: true
|
||||
}
|
||||
}
|
||||
|
||||
playlistSelected( playlist_uri ){
|
||||
this.props.uiActions.addTracksToPlaylist( playlist_uri, this.props.modal.data.track_indexes )
|
||||
this.props.uiActions.closeModal()
|
||||
}
|
||||
|
||||
renderEditablePlaylists(){
|
||||
if( !this.props.playlists ) return <div className="empty">No editable playlists</div>
|
||||
var playlists = []
|
||||
for( var i = 0; i < this.props.playlists.length; i++ ){
|
||||
switch( helpers.uriSource( this.props.playlists[i].uri ) ){
|
||||
|
||||
case 'spotify':
|
||||
if( this.props.playlists[i].can_edit ) playlists.push( this.props.playlists[i] )
|
||||
break
|
||||
|
||||
case 'm3u':
|
||||
playlists.push( this.props.playlists[i] )
|
||||
break
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="playlists">
|
||||
{
|
||||
playlists.map( playlist => {
|
||||
return (
|
||||
<div className="playlist" key={playlist.uri} onClick={ () => this.playlistSelected(playlist.uri) }>
|
||||
{ playlist.name }
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
createPlaylist(e){
|
||||
e.preventDefault();
|
||||
this.props.uiActions.createPlaylist( this.state.playlist_scheme, this.state.playlist_name, this.state.playlist_public );
|
||||
return false;
|
||||
}
|
||||
|
||||
renderCreatePlaylist(){
|
||||
return (
|
||||
<div>
|
||||
<h1>Create playlist</h1>
|
||||
<form onSubmit={(e) => this.createPlaylist(e)}>
|
||||
<div className="field">
|
||||
<div className="name">Name</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={ e => this.setState({ playlist_name: e.target.value })}
|
||||
value={ this.state.playlist_name } />
|
||||
</div>
|
||||
</div>
|
||||
<div className="field radio white">
|
||||
<div className="name">Provider</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="playlist_scheme"
|
||||
value="spotify"
|
||||
checked={ this.state.playlist_scheme == 'spotify' }
|
||||
onChange={ e => this.setState({ playlist_scheme: e.target.value })} />
|
||||
<span className="label">Spotify</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="playlist_scheme"
|
||||
value="m3u"
|
||||
checked={ this.state.playlist_scheme == 'm3u' }
|
||||
onChange={ e => this.setState({ playlist_scheme: e.target.value })} />
|
||||
<span className="label">Local</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field checkbox white">
|
||||
<div className="name">Options</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="playlist_private"
|
||||
value={ this.state.playlist_private }
|
||||
onChange={ e => this.setState({ playlist_private: !this.state.playlist_private })} />
|
||||
<span className="label">Private</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" className="primary centered">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render(){
|
||||
if( !this.props.modal ) return null;
|
||||
|
||||
return (
|
||||
<div className="modal">
|
||||
<div className="close-modal" onClick={ () => this.props.uiActions.closeModal() }>
|
||||
<Icon name="close" className="white" />
|
||||
</div>
|
||||
<div className="content">
|
||||
|
||||
{ this.props.modal.name == 'add_to_playlist' ? this.renderEditablePlaylists() : null }
|
||||
{ this.props.modal.name == 'create_playlist' ? this.renderCreatePlaylist() : null }
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
modal: state.ui.modal,
|
||||
playlists: state.ui.playlists,
|
||||
context_menu: state.ui.context_menu,
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
spotify_authorized: state.spotify.authorized
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Modal)
|
||||
38
src/js/components/Modal/AddToPlaylistModal.js
Executable file
38
src/js/components/Modal/AddToPlaylistModal.js
Executable file
@ -0,0 +1,38 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import Icon from '../Icon'
|
||||
import * as helpers from '../../helpers'
|
||||
|
||||
class AddToPlaylistModal extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
}
|
||||
|
||||
playlistSelected( playlist_uri ){
|
||||
this.props.uiActions.addTracksToPlaylist( playlist_uri, this.props.data.track_indexes )
|
||||
this.props.uiActions.closeModal()
|
||||
}
|
||||
|
||||
render(){
|
||||
if( !this.props.playlists ) return <div className="empty">No editable playlists</div>
|
||||
var playlists = []
|
||||
for( var i = 0; i < this.props.playlists.length; i++ ){
|
||||
if( this.props.playlists[i].can_edit ) playlists.push( this.props.playlists[i] )
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="playlists">
|
||||
{
|
||||
playlists.map( playlist => {
|
||||
return (
|
||||
<div className="playlist" key={playlist.uri} onClick={ () => this.playlistSelected(playlist.uri) }>
|
||||
{ playlist.name }
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
82
src/js/components/Modal/CreatePlaylistModal.js
Executable file
82
src/js/components/Modal/CreatePlaylistModal.js
Executable file
@ -0,0 +1,82 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
|
||||
import Icon from '../Icon'
|
||||
import * as helpers from '../../helpers'
|
||||
|
||||
export default class CreatePlaylistModal extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {
|
||||
submit_enabled: false,
|
||||
name: '',
|
||||
scheme: 'spotify',
|
||||
is_public: true
|
||||
}
|
||||
}
|
||||
|
||||
createPlaylist(e){
|
||||
e.preventDefault();
|
||||
this.props.uiActions.createPlaylist( this.state.scheme, this.state.name, this.state.is_public )
|
||||
this.props.uiActions.closeModal()
|
||||
return false;
|
||||
}
|
||||
|
||||
setPlaylistName(name){
|
||||
var submit_enabled = false
|
||||
if( name && name != '' ) submit_enabled = true
|
||||
this.setState({
|
||||
name: name,
|
||||
submit_enabled: submit_enabled
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div>
|
||||
<h4>Create playlist</h4>
|
||||
<form onSubmit={(e) => this.createPlaylist(e)}>
|
||||
<div className="field">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Playlist name"
|
||||
onChange={ e => this.setPlaylistName( e.target.value )}
|
||||
value={ this.state.name } />
|
||||
</div>
|
||||
<div className="field radio white">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="scheme"
|
||||
value="spotify"
|
||||
checked={ this.state.scheme == 'spotify' }
|
||||
onChange={ e => this.setState({ scheme: e.target.value })} />
|
||||
<span className="label">Spotify</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="scheme"
|
||||
value="m3u"
|
||||
checked={ this.state.scheme == 'm3u' }
|
||||
onChange={ e => this.setState({ scheme: e.target.value })} />
|
||||
<span className="label">Local (m3u)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="field checkbox white">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="is_public"
|
||||
checked={ this.state.is_public }
|
||||
onChange={ e => this.setState({ is_public: !this.state.is_public })} />
|
||||
<span className="label">Public</span>
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" className="primary centered" disabled={!this.state.submit_enabled}>Save</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
61
src/js/components/Modal/EditPlaylistModal.js
Executable file
61
src/js/components/Modal/EditPlaylistModal.js
Executable file
@ -0,0 +1,61 @@
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import Icon from '../Icon'
|
||||
import * as helpers from '../../helpers'
|
||||
|
||||
export default class EditPlaylistModal extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {
|
||||
submit_enabled: true,
|
||||
name: this.props.data.name,
|
||||
is_public: this.props.data.is_public
|
||||
}
|
||||
}
|
||||
|
||||
setPlaylistName(name){
|
||||
var submit_enabled = false
|
||||
if( name && name != '' ) submit_enabled = true
|
||||
this.setState({
|
||||
name: name,
|
||||
submit_enabled: submit_enabled
|
||||
})
|
||||
}
|
||||
|
||||
savePlaylist(e){
|
||||
e.preventDefault();
|
||||
this.props.uiActions.savePlaylist( this.props.data.uri, this.state.name, this.state.is_public )
|
||||
this.props.uiActions.closeModal()
|
||||
return false;
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div>
|
||||
<h4>Edit playlist</h4>
|
||||
<form onSubmit={(e) => this.savePlaylist(e)}>
|
||||
<div className="field">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Playlist name"
|
||||
onChange={ e => this.setPlaylistName( e.target.value )}
|
||||
value={ this.state.name } />
|
||||
</div>
|
||||
<div className="field checkbox white">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="playlist_private"
|
||||
checked={ this.state.is_public }
|
||||
onChange={ e => this.setState({ is_public: !this.state.is_public })} />
|
||||
<span className="label">Public</span>
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" className="primary centered" disabled={!this.state.submit_enabled}>Save</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
60
src/js/components/Modal/Modal.js
Executable file
60
src/js/components/Modal/Modal.js
Executable file
@ -0,0 +1,60 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
|
||||
import * as helpers from '../../helpers'
|
||||
import Icon from '../Icon'
|
||||
import AddToPlaylistModal from './AddToPlaylistModal'
|
||||
import CreatePlaylistModal from './CreatePlaylistModal'
|
||||
import EditPlaylistModal from './EditPlaylistModal'
|
||||
|
||||
import * as uiActions from '../../services/ui/actions'
|
||||
import * as mopidyActions from '../../services/mopidy/actions'
|
||||
import * as spotifyActions from '../../services/spotify/actions'
|
||||
|
||||
class Modal extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
}
|
||||
|
||||
render(){
|
||||
if( !this.props.modal ) return null;
|
||||
|
||||
return (
|
||||
<div className="modal">
|
||||
<div className="close-modal" onClick={ () => this.props.uiActions.closeModal() }>
|
||||
<Icon name="close" className="white" />
|
||||
</div>
|
||||
<div className="content">
|
||||
|
||||
{ this.props.modal.name == 'add_to_playlist' ? <AddToPlaylistModal /> : null }
|
||||
{ this.props.modal.name == 'create_playlist' ? <CreatePlaylistModal /> : null }
|
||||
{ this.props.modal.name == 'edit_playlist' ? <EditPlaylistModal uiActions={this.props.uiActions} data={this.props.modal.data} /> : null }
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
modal: state.ui.modal,
|
||||
playlists: state.ui.playlists,
|
||||
context_menu: state.ui.context_menu,
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
spotify_authorized: state.spotify.authorized
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Modal)
|
||||
@ -280,7 +280,11 @@ const MopidyMiddleware = (function(){
|
||||
}
|
||||
|
||||
var playlist = Object.assign({}, response)
|
||||
playlist.tracks = [...playlist.tracks, ...tracks]
|
||||
if( playlist.tracks ){
|
||||
playlist.tracks = [...playlist.tracks, ...tracks]
|
||||
}else{
|
||||
playlist.tracks = tracks
|
||||
}
|
||||
|
||||
instruct( socket, store, 'playlists.save', { playlist: playlist } )
|
||||
.then( response => {
|
||||
@ -320,6 +324,21 @@ const MopidyMiddleware = (function(){
|
||||
});
|
||||
break
|
||||
|
||||
case 'MOPIDY_SAVE_PLAYLIST':
|
||||
instruct( socket, store, 'playlists.lookup', { uri: action.uri })
|
||||
.then( response => {
|
||||
var playlist = Object.assign({}, response, { name: action.name })
|
||||
instruct( socket, store, 'playlists.save', { playlist: playlist } )
|
||||
.then( response => {
|
||||
|
||||
// TODO: changing the name changes the URI, so essentially invalidates our url...
|
||||
// need to figure out how to handle this
|
||||
|
||||
store.dispatch({ type: 'PLAYLIST_UPDATED', playlist: playlist });
|
||||
})
|
||||
});
|
||||
break
|
||||
|
||||
case 'MOPIDY_DELETE_PLAYLIST':
|
||||
instruct( socket, store, 'playlists.delete', { uri: action.uri })
|
||||
.then( response => {
|
||||
|
||||
@ -503,16 +503,32 @@ export function getSearchResults( query, type = 'album,artist,playlist,track', l
|
||||
* Playlists
|
||||
**/
|
||||
|
||||
export function createPlaylist( name, is_private ){
|
||||
export function createPlaylist( name, is_public ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
sendRequest( dispatch, getState, 'users/'+ getState().spotify.me.id +'/playlists/', 'POST', { name: name, public: !is_private } )
|
||||
sendRequest( dispatch, getState, 'users/'+ getState().spotify.me.id +'/playlists/', 'POST', { name: name, public: is_public } )
|
||||
.then( response => {
|
||||
dispatch( getAllLibraryPlaylists() );
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function savePlaylist( uri, name, is_public ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
sendRequest( dispatch, getState, 'users/'+ getState().spotify.me.id +'/playlists/'+ helpers.getFromUri('playlistid',uri), 'PUT', { name: name, public: is_public } )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'PLAYLIST_UPDATED',
|
||||
playlist: {
|
||||
name: name,
|
||||
public: is_public
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function getPlaylist( uri ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
|
||||
@ -51,6 +51,16 @@ const SpotifyMiddleware = (function(){
|
||||
store.dispatch( actions.addTracksToPlaylist( action.playlist_uri, action.tracks_uris ))
|
||||
break
|
||||
|
||||
|
||||
case 'SPOTIFY_SAVE_PLAYLIST':
|
||||
|
||||
if( !store.getState().spotify.authorized ){
|
||||
alert('Must be logged in to Spotify to do this')
|
||||
return
|
||||
}
|
||||
store.dispatch( actions.savePlaylist( action.uri, action.name, action.is_public ))
|
||||
break
|
||||
|
||||
// when our mopidy server current track changes
|
||||
case 'MOPIDY_CURRENTTLTRACK':
|
||||
|
||||
|
||||
@ -66,14 +66,35 @@ export function dragEnd(){
|
||||
return { type: 'DRAG_END' }
|
||||
}
|
||||
|
||||
export function createPlaylist( scheme, name, is_private = false ){
|
||||
export function savePlaylist( uri, name, is_public = false ){
|
||||
switch( helpers.uriSource( uri ) ){
|
||||
|
||||
case 'spotify':
|
||||
return {
|
||||
type: 'SPOTIFY_SAVE_PLAYLIST',
|
||||
uri: uri,
|
||||
name: name,
|
||||
is_public: is_public
|
||||
}
|
||||
|
||||
case 'm3u':
|
||||
return {
|
||||
type: 'MOPIDY_SAVE_PLAYLIST',
|
||||
uri: uri,
|
||||
name: name
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function createPlaylist( scheme, name, is_public = false ){
|
||||
switch( scheme ){
|
||||
|
||||
case 'spotify':
|
||||
return {
|
||||
type: 'SPOTIFY_CREATE_PLAYLIST',
|
||||
name: name,
|
||||
is_private: is_private
|
||||
is_public: is_public
|
||||
}
|
||||
|
||||
case 'm3u':
|
||||
|
||||
@ -180,6 +180,10 @@ export default function reducer(ui = {}, action){
|
||||
* Playlists
|
||||
**/
|
||||
|
||||
case 'PLAYLIST_UPDATED':
|
||||
var playlist = Object.assign({}, ui.playlist, action.playlist)
|
||||
return Object.assign({}, ui, { playlist: playlist })
|
||||
|
||||
case 'MOPIDY_PLAYLIST_LOADED':
|
||||
if( !action.data ) return Object.assign({}, ui, { playlist: false })
|
||||
return Object.assign({}, ui, { playlist: action.data })
|
||||
|
||||
@ -8,7 +8,7 @@ import { connect } from 'react-redux'
|
||||
import Sidebar from '../components/Sidebar'
|
||||
import ContextMenu from '../components/ContextMenu'
|
||||
import Dragger from '../components/Dragger'
|
||||
import Modal from '../components/Modal'
|
||||
import Modal from '../components/Modal/Modal'
|
||||
|
||||
import * as uiActions from '../services/ui/actions'
|
||||
import * as pusherActions from '../services/pusher/actions'
|
||||
|
||||
@ -74,23 +74,30 @@ class Playlist extends React.Component{
|
||||
this.props.uiActions.removeTracksFromPlaylist( this.props.playlist.uri, track_indexes )
|
||||
}
|
||||
|
||||
renderFollowOrDeleteButton(){
|
||||
renderEditButtons(){
|
||||
switch( helpers.uriSource( this.props.params.uri ) ){
|
||||
|
||||
case 'm3u':
|
||||
return <ConfirmationButton className="large tertiary" content="Delete" confirmingContent="Are you sure?" onConfirm={ e => this.delete() } />
|
||||
break
|
||||
return (
|
||||
<span>
|
||||
<button className="large tertiary" onClick={ e => this.props.uiActions.openModal('edit_playlist', { uri: this.props.playlist.uri, name: this.props.playlist.name }) }>Edit</button>
|
||||
<ConfirmationButton className="large tertiary" content="Delete" confirmingContent="Are you sure?" onConfirm={ e => this.delete() } />
|
||||
</span>
|
||||
)
|
||||
|
||||
case 'spotify':
|
||||
if( !this.props.spotify_authorized ) return null
|
||||
if( this.props.playlist.owner && this.props.playlist.owner.id == this.props.spotify_userid ){
|
||||
return <ConfirmationButton className="large tertiary" content="Delete" confirmingContent="Are you sure?" onConfirm={ e => this.unfollow() } />
|
||||
return (
|
||||
<span>
|
||||
<button className="large tertiary" onClick={ e => this.props.uiActions.openModal('edit_playlist', { uri: this.props.playlist.uri, name: this.props.playlist.name, is_public: this.props.playlist.public }) }>Edit</button>
|
||||
<ConfirmationButton className="large tertiary" content="Delete" confirmingContent="Are you sure?" onConfirm={ e => this.unfollow() } />
|
||||
</span>
|
||||
)
|
||||
}else if( this.props.playlist.following ){
|
||||
return <button className="large tertiary" onClick={ e => this.unfollow() }>Unfollow</button>
|
||||
}else{
|
||||
return <button className="large tertiary" onClick={ e => this.follow() }>Follow</button>
|
||||
}
|
||||
break
|
||||
return <button className="large tertiary" onClick={ e => this.follow() }>Follow</button>
|
||||
|
||||
}
|
||||
}
|
||||
@ -107,7 +114,7 @@ class Playlist extends React.Component{
|
||||
|
||||
<div className="actions">
|
||||
<button className="large primary" onClick={ e => this.play() }>Play</button>
|
||||
{ this.renderFollowOrDeleteButton() }
|
||||
{ this.renderEditButtons() }
|
||||
</div>
|
||||
|
||||
<ul className="details">
|
||||
|
||||
@ -27,15 +27,17 @@ class LibraryPlaylists extends React.Component{
|
||||
{ name: 'uri', width: '40'}
|
||||
]
|
||||
|
||||
var actions = (
|
||||
<button onClick={ () => this.props.uiActions.openModal('create_playlist', {} ) }>
|
||||
<FontAwesome name="plus" />
|
||||
New
|
||||
</button>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="view library-playlists-view">
|
||||
|
||||
<Header icon="playlist" title="My playlists" />
|
||||
|
||||
<button onClick={ () => this.props.uiActions.openModal('create_playlist',false) }>
|
||||
<FontAwesome name="plus" />
|
||||
New playlist
|
||||
</button>
|
||||
<Header icon="playlist" title="My playlists" actions={actions} />
|
||||
|
||||
<section className="grid-wrapper">
|
||||
<PlaylistGrid playlists={this.props.playlists} />
|
||||
|
||||
@ -4,16 +4,30 @@ main {
|
||||
padding: 14px 20px;
|
||||
background: #EEEEEE;
|
||||
|
||||
h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 100;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-block;
|
||||
padding-right: 14px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 100;
|
||||
display: inline-block;
|
||||
.actions {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
|
||||
button {
|
||||
background: transparent;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
padding: 16px 10px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,18 +30,35 @@
|
||||
.content {
|
||||
padding: 100px;
|
||||
margin: 0 auto;
|
||||
width: 70%;
|
||||
width: 50%;
|
||||
color: #FFFFFF;
|
||||
|
||||
h1 {
|
||||
font-size: 30px;
|
||||
font-weight: 300;
|
||||
padding-bottom: 30px;
|
||||
h4 {
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
form {
|
||||
.field {
|
||||
padding-bottom: 20px;
|
||||
|
||||
input[type="text"]{
|
||||
background: transparent;
|
||||
font-size: 24px;
|
||||
border-bottom: 2px solid #FFFFFF;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
width: 100%;
|
||||
color: #FFFFFF;
|
||||
|
||||
&:focus,
|
||||
&:active {
|
||||
border-color: $turquoise;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
button[type="submit"]{
|
||||
|
||||
@ -39,49 +39,49 @@ main {
|
||||
section.list-wrapper {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 500;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: 500;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 14px;
|
||||
margin-bottom: 14px;
|
||||
text-transform: uppercase;
|
||||
|
||||
&.underline {
|
||||
padding-bottom: 4px;
|
||||
border-bottom: 1px solid #000000;
|
||||
}
|
||||
|
||||
&:not(:first-child){
|
||||
padding-top: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-top-padding { padding-top: 0 !important; }
|
||||
.no-bottom-padding { padding-bottom: 0 !important; }
|
||||
.no-right-padding { padding-right: 0 !important; }
|
||||
.no-left-padding { padding-left: 0 !important; }
|
||||
|
||||
.top-padding { padding-top: 20px; }
|
||||
.bottom-padding { padding-bottom: 20px; }
|
||||
.right-padding { padding-right: 40px; }
|
||||
.left-padding { padding-left: 40px; }
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 500;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: 500;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 14px;
|
||||
margin-bottom: 14px;
|
||||
text-transform: uppercase;
|
||||
|
||||
&.underline {
|
||||
padding-bottom: 4px;
|
||||
border-bottom: 1px solid #000000;
|
||||
}
|
||||
|
||||
&:not(:first-child){
|
||||
padding-top: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-top-padding { padding-top: 0 !important; }
|
||||
.no-bottom-padding { padding-bottom: 0 !important; }
|
||||
.no-right-padding { padding-right: 0 !important; }
|
||||
.no-left-padding { padding-left: 0 !important; }
|
||||
|
||||
.top-padding { padding-top: 20px; }
|
||||
.bottom-padding { padding-bottom: 20px; }
|
||||
.right-padding { padding-right: 40px; }
|
||||
.left-padding { padding-left: 40px; }
|
||||
|
||||
.col {
|
||||
min-height: 1px;
|
||||
float: left;
|
||||
|
||||
@ -99,7 +99,7 @@ input[type="submit"] {
|
||||
|
||||
&[disabled],
|
||||
&[disabled="disabled"] {
|
||||
background: $light_grey !important;
|
||||
background: rgba(200,200,200,0.4) !important;
|
||||
color: $mid_grey !important;
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user