local artists
This commit is contained in:
@ -3066,6 +3066,10 @@ main .left-padding {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.col.w100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cf::after {
|
||||
content: '';
|
||||
clear: both;
|
||||
@ -3497,12 +3501,6 @@ aside .player .controls a:hover {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.list-item .col {
|
||||
width: 10%;
|
||||
min-height: 1px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.list-item.selected {
|
||||
background: #FFF39C !important;
|
||||
}
|
||||
@ -3510,6 +3508,7 @@ aside .player .controls a:hover {
|
||||
.list-item:not(.header):hover {
|
||||
background: #EEEEEE;
|
||||
cursor: pointer;
|
||||
border-color: #EEEEEE;
|
||||
}
|
||||
|
||||
.list-item.header {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
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