local artists
This commit is contained in:
45
src/js/components/List.js
Executable file
45
src/js/components/List.js
Executable file
@ -0,0 +1,45 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { Link } from 'react-router'
|
||||
|
||||
export default class List extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
renderHeader(){
|
||||
if( !this.props.columns ) return null
|
||||
|
||||
return (
|
||||
<div className="list-item header cf">
|
||||
{
|
||||
this.props.columns.map( (col, col_index) => {
|
||||
return <div className={'col w'+col.width} key={col_index}>{ col.name }</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className="list">
|
||||
{ this.renderHeader() }
|
||||
{
|
||||
this.props.rows.map( (row, row_index) => {
|
||||
return (
|
||||
<Link to={ this.props.link_prefix + encodeURIComponent(row.uri)} className="list-item cf" key={row_index}>
|
||||
{
|
||||
this.props.columns.map( (col, col_index) => {
|
||||
return <div className={'col w'+col.width} key={col_index}>{ row[col.name] }</div>
|
||||
})
|
||||
}
|
||||
</Link>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,7 @@ export default class Parallax extends React.Component{
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
var url = helpers.SizedImages( this.props.images ).huge;
|
||||
var url = helpers.sizedImages( this.props.images ).huge;
|
||||
this.loadImage( url )
|
||||
.then(
|
||||
response => {
|
||||
|
||||
@ -34,7 +34,7 @@ export default class Thumbnail extends React.Component{
|
||||
huge: require('../../images/no-image.svg')
|
||||
}
|
||||
}else{
|
||||
state = helpers.SizedImages( images );
|
||||
state = helpers.sizedImages( images );
|
||||
}
|
||||
|
||||
this.setState( state );
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
export let SizedImages = function( images ){
|
||||
export let sizedImages = function( images ){
|
||||
|
||||
var sizes = {
|
||||
small: false,
|
||||
@ -14,7 +14,7 @@ export let SizedImages = function( images ){
|
||||
for( var i = 0; i < images.length; i++ ){
|
||||
|
||||
// spotify-styled images
|
||||
if( images[i].height ){
|
||||
if( typeof(images[i].height) !== 'undefined' ){
|
||||
if( images[i].height > 800 ){
|
||||
sizes.huge = images[i].url;
|
||||
}else if( images[i].height > 600 ){
|
||||
|
||||
@ -31,6 +31,7 @@ import LibraryTracks from './views/library/LibraryTracks'
|
||||
import LibraryPlaylists from './views/library/LibraryPlaylists'
|
||||
import LibraryLocal from './views/library/LibraryLocal'
|
||||
import LibraryLocalDirectory from './views/library/LibraryLocalDirectory'
|
||||
import LibraryLocalArtists from './views/library/LibraryLocalArtists'
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
@ -52,6 +53,7 @@ ReactDOM.render(
|
||||
<Route path="library/playlists" component={LibraryPlaylists} />
|
||||
<Route path="library/local" component={LibraryLocal} />
|
||||
<Route path="library/local/directory/:uri" component={LibraryLocalDirectory} />
|
||||
<Route path="library/local/artists" component={LibraryLocalArtists} />
|
||||
|
||||
<Route path="album/:uri" component={Album} />
|
||||
<Route path="artist/:uri" component={Artist} />
|
||||
|
||||
@ -124,3 +124,9 @@ export function getArtist( uri ){
|
||||
}
|
||||
}
|
||||
|
||||
export function getArtists(){
|
||||
return {
|
||||
type: 'MOPIDY_ARTISTS'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -155,6 +155,7 @@ const MopidyMiddleware = (function(){
|
||||
break;
|
||||
|
||||
case 'MOPIDY_PLAYLIST':
|
||||
store.dispatch({ type: 'MOPIDY_PLAYLIST_LOADED', data: false });
|
||||
instruct( socket, store, 'playlists.lookup', action.data )
|
||||
.then( response => {
|
||||
var playlist = response;
|
||||
@ -196,6 +197,7 @@ const MopidyMiddleware = (function(){
|
||||
break;
|
||||
|
||||
case 'MOPIDY_ALBUM':
|
||||
store.dispatch({ type: 'MOPIDY_ALBUM_LOADED', data: false });
|
||||
instruct( socket, store, 'library.lookup', action.data )
|
||||
.then( response => {
|
||||
var album = response[0].album;
|
||||
@ -238,14 +240,13 @@ const MopidyMiddleware = (function(){
|
||||
break;
|
||||
|
||||
case 'MOPIDY_ARTIST':
|
||||
store.dispatch({ type: 'MOPIDY_ARTIST_LOADED', data: false });
|
||||
instruct( socket, store, 'library.lookup', action.data )
|
||||
.then( response => {
|
||||
var artist = {
|
||||
name: 'yeah',
|
||||
images: [],
|
||||
albums: [],
|
||||
tracks: response.slice(0,10)
|
||||
}
|
||||
var artist = response[0].artists[0];
|
||||
artist.images = [];
|
||||
artist.albums = [];
|
||||
artist.tracks = response.slice(0,10);
|
||||
|
||||
for( var i = 0; i < response.length; i++ ){
|
||||
var album = response[i].album;
|
||||
@ -263,6 +264,16 @@ const MopidyMiddleware = (function(){
|
||||
})
|
||||
break;
|
||||
|
||||
case 'MOPIDY_ARTISTS':
|
||||
store.dispatch({ type: 'MOPIDY_ARTISTS_LOADED', data: false });
|
||||
instruct( socket, store, 'library.browse', { uri: 'local:directory?type=artist' } )
|
||||
.then( response => {
|
||||
var artists = response;
|
||||
|
||||
store.dispatch({ type: 'MOPIDY_ARTISTS_LOADED', data: artists });
|
||||
})
|
||||
break;
|
||||
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
default:
|
||||
return next(action);
|
||||
|
||||
@ -92,6 +92,11 @@ export default function reducer(mopidy = {}, action){
|
||||
artist: action.data
|
||||
});
|
||||
|
||||
case 'MOPIDY_ARTISTS_LOADED':
|
||||
return Object.assign({}, mopidy, {
|
||||
artists: action.data
|
||||
});
|
||||
|
||||
default:
|
||||
return mopidy
|
||||
}
|
||||
|
||||
@ -98,19 +98,8 @@ class Artist extends React.Component{
|
||||
<h1>{ artist.name }</h1>
|
||||
</div>
|
||||
|
||||
<div className="col w70">
|
||||
<h4 className="left-padding">Top tracks</h4>
|
||||
{ artist.tracks ? <TrackList tracks={ artist.tracks } /> : null }
|
||||
</div>
|
||||
|
||||
<div className="col w5"></div>
|
||||
|
||||
<div className="col w25">
|
||||
<h4>Related artists</h4>
|
||||
{ artist.related_artists ? <ArtistList artists={ artist.artist.related_artists.slice(0,6) } /> : null }
|
||||
</div>
|
||||
|
||||
<div className="cf"></div>
|
||||
<h4 className="left-padding">Top tracks</h4>
|
||||
{ artist.tracks ? <TrackList tracks={ artist.tracks } /> : null }
|
||||
|
||||
<h4 className="left-padding">Albums</h4>
|
||||
{ artist.albums ? <AlbumGrid className="no-top-padding" albums={ artist.albums } /> : null }
|
||||
|
||||
@ -17,6 +17,7 @@ export default class LibraryLocal extends React.Component{
|
||||
<div className="view library-local-view">
|
||||
<Header icon="folder" title="Local" />
|
||||
<Link to="/library/local/directory/local:directory">Folders</Link>
|
||||
<Link to="/library/local/artists">Artists</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
67
src/js/views/library/LibraryLocalArtists.js
Executable file
67
src/js/views/library/LibraryLocalArtists.js
Executable file
@ -0,0 +1,67 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
|
||||
import Header from '../../components/Header'
|
||||
import List from '../../components/List'
|
||||
|
||||
import * as mopidyActions from '../../services/mopidy/actions'
|
||||
import * as spotifyActions from '../../services/spotify/actions'
|
||||
|
||||
class LibraryLocalArtists extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
// on render
|
||||
componentDidMount(){
|
||||
this.loadArtists()
|
||||
}
|
||||
|
||||
componentWillReceiveProps( nextProps ){
|
||||
if( !this.props.mopidy.connected && nextProps.mopidy.connected ){
|
||||
this.loadArtists(nextProps);
|
||||
}
|
||||
}
|
||||
|
||||
loadArtists(props = this.props){
|
||||
if( props.mopidy.connected ){
|
||||
this.props.mopidyActions.getArtists();
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
if( !this.props.mopidy.artists ) return null
|
||||
|
||||
return (
|
||||
<div className="view library-local-view">
|
||||
<Header icon="music" title="Local" />
|
||||
<div>
|
||||
<List columns={[{ name: 'name', width: '100'}]} rows={this.props.mopidy.artists} link_prefix="/artist/" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export our component
|
||||
*
|
||||
* We also integrate our global store, using connect()
|
||||
**/
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return state;
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LibraryLocalArtists)
|
||||
@ -11,24 +11,19 @@
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 9px 10px 9px 40px;
|
||||
border-top: 1px solid #EEEEEE;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
border-top: 1px solid $faint_grey;
|
||||
border-bottom: 1px solid $faint_grey;
|
||||
margin-bottom: -1px;
|
||||
@include clearfix;
|
||||
|
||||
.col {
|
||||
width: 10%;
|
||||
min-height: 1px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background: #FFF39C !important;
|
||||
}
|
||||
|
||||
&:not(.header):hover {
|
||||
background: #EEEEEE;
|
||||
background: $faint_grey;
|
||||
cursor: pointer;
|
||||
border-color: $faint_grey;
|
||||
}
|
||||
|
||||
&.header {
|
||||
|
||||
@ -103,6 +103,7 @@ main {
|
||||
&.w85 { width: 85%; }
|
||||
&.w90 { width: 90%; }
|
||||
&.w95 { width: 95%; }
|
||||
&.w100 { width: 100%; }
|
||||
}
|
||||
|
||||
.cf{
|
||||
|
||||
Reference in New Issue
Block a user