diff --git a/src/js/bootstrap.js b/src/js/bootstrap.js
index 0e89943b..5901fe30 100755
--- a/src/js/bootstrap.js
+++ b/src/js/bootstrap.js
@@ -21,6 +21,10 @@ var initialState = {
mopidy: {
host: window.location.hostname,
port: 6680
+ },
+ spotify: {
+ country: 'NZ',
+ locale: 'en_NZ'
}
};
diff --git a/src/js/components/AlbumGrid.js b/src/js/components/AlbumGrid.js
new file mode 100755
index 00000000..019147d7
--- /dev/null
+++ b/src/js/components/AlbumGrid.js
@@ -0,0 +1,28 @@
+
+import React, { PropTypes } from 'react'
+import AlbumGridItem from './AlbumGridItem'
+
+export default class AlbumGrid extends React.Component{
+
+ constructor(props) {
+ super(props);
+ }
+
+ render(){
+ if( this.props.items ){
+ return (
+
+ {
+ this.props.items.items.map(
+ (album, index) => {
+ return
+ }
+ )
+ }
+
+ );
+ }
+ return null;
+ }
+}
+
diff --git a/src/js/components/AlbumGridItem.js b/src/js/components/AlbumGridItem.js
new file mode 100755
index 00000000..2118227c
--- /dev/null
+++ b/src/js/components/AlbumGridItem.js
@@ -0,0 +1,21 @@
+
+import React, { PropTypes } from 'react'
+import { Link } from 'react-router'
+import Thumbnail from './Thumbnail'
+
+export default class AlbumGridItem extends React.Component{
+
+ constructor(props) {
+ super(props);
+ }
+
+ render(){
+ var link = '/album/' + this.props.item.uri;
+ return (
+
+
+
+ );
+ }
+}
+
diff --git a/src/js/components/Thumbnail.js b/src/js/components/Thumbnail.js
new file mode 100755
index 00000000..30d7b06a
--- /dev/null
+++ b/src/js/components/Thumbnail.js
@@ -0,0 +1,26 @@
+
+import React, { PropTypes } from 'react'
+
+export default class Thumbnail extends React.Component{
+
+ constructor(props) {
+ super(props);
+ }
+
+ sizedImageURL(){
+ var images = this.props.images;
+ switch( this.props.size ){
+ case 'small':
+ break;
+
+ default:
+ return images[images.length-1].url
+ }
+ }
+
+ render(){
+ return (
+
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/js/services/localstorage/middleware.js b/src/js/services/localstorage/middleware.js
index 952f1572..87060bb7 100755
--- a/src/js/services/localstorage/middleware.js
+++ b/src/js/services/localstorage/middleware.js
@@ -14,12 +14,20 @@ const localstorageMiddleware = (function(){
case 'MOPIDY_SET_CONFIG':
var mopidy = {
- host: action.host,
- port: action.port
+ host: action.config.host,
+ port: action.config.port
};
localStorage.setItem('mopidy', JSON.stringify(mopidy));
break;
+ case 'SPOTIFY_SET_CONFIG':
+ var spotify = {
+ country: action.config.country,
+ locale: action.config.locale
+ };
+ localStorage.setItem('spotify', JSON.stringify(spotify));
+ break;
+
case 'SPOTIFY_COMPLETE_AUTHORIZATION':
var spotify = {
authorized: true,
diff --git a/src/js/services/mopidy/actions.js b/src/js/services/mopidy/actions.js
index 91766e58..e760311d 100755
--- a/src/js/services/mopidy/actions.js
+++ b/src/js/services/mopidy/actions.js
@@ -3,6 +3,13 @@
* Actions and Action Creators
**/
+export function setConfig( config ){
+ return {
+ type: 'MOPIDY_SET_CONFIG',
+ config: config
+ }
+}
+
export function connect(){
return {
type: 'MOPIDY_CONNECT'
@@ -15,14 +22,6 @@ export function disconnect(){
}
}
-export function setConfig( host, port ){
- return {
- type: 'MOPIDY_SET_CONFIG',
- host: host,
- port: port
- }
-}
-
export function changeTrack( tlid ){
return {
type: 'MOPIDY_CHANGE_TRACK',
diff --git a/src/js/services/spotify/actions.js b/src/js/services/spotify/actions.js
index c03182e6..4554c439 100755
--- a/src/js/services/spotify/actions.js
+++ b/src/js/services/spotify/actions.js
@@ -3,6 +3,13 @@
* Actions and Action Creators
**/
+export function setConfig( config ){
+ return {
+ type: 'SPOTIFY_SET_CONFIG',
+ config: config
+ }
+}
+
export function startAuthorization(){
return {
type: 'SPOTIFY_START_AUTHORIZATION'
diff --git a/src/js/services/spotify/middleware.js b/src/js/services/spotify/middleware.js
index 74d74269..63dd7e49 100755
--- a/src/js/services/spotify/middleware.js
+++ b/src/js/services/spotify/middleware.js
@@ -33,8 +33,10 @@ const SpotifyMiddleware = (function(){
* The actual middleware inteceptor
**/
return store => next => action => {
- switch(action.type) {
+ var state = store.getState();
+
+ switch(action.type){
case 'SPOTIFY_LOAD_ALBUM':
@@ -57,21 +59,32 @@ const SpotifyMiddleware = (function(){
case 'SPOTIFY_LOAD_ARTIST':
store.dispatch({ type: 'SPOTIFY_ARTIST_LOADED', data: false })
+ store.dispatch({ type: 'SPOTIFY_ARTIST_ALBUMS_LOADED', data: false })
+
var id = action.uri.replace('spotify:artist:','');
sendRequest( false, 'artists/'+id )
.then( (response) => {
store.dispatch({ type: 'SPOTIFY_ARTIST_LOADED', data: response })
});
+
+ sendRequest( false, 'artists/'+id+'/albums' )
+ .then( (response) => {
+ store.dispatch({ type: 'SPOTIFY_ARTIST_ALBUMS_LOADED', data: response })
+ });
+
+ sendRequest( false, 'artists/'+id+'/top-tracks?country='+state.spotify.country )
+ .then( (response) => {
+ store.dispatch({ type: 'SPOTIFY_ARTIST_TRACKS_LOADED', data: response })
+ });
break;
case 'SPOTIFY_LOAD_LIBRARY_ARTISTS':
store.dispatch({ type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED', data: false })
- var token = store.getState().spotify.access_token;
- sendRequest( token, 'me/following?type=artist' )
+ sendRequest( state.spotify.access_token, 'me/following?type=artist' )
.then( (response) => {
store.dispatch({ type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED', data: response })
});
diff --git a/src/js/services/spotify/reducer.js b/src/js/services/spotify/reducer.js
index ef72ab0d..6a1c6bd0 100755
--- a/src/js/services/spotify/reducer.js
+++ b/src/js/services/spotify/reducer.js
@@ -35,6 +35,12 @@ export default function reducer(spotify = {}, action){
case 'SPOTIFY_ARTIST_LOADED':
return Object.assign({}, spotify, { artist: action.data });
+ case 'SPOTIFY_ARTIST_ALBUMS_LOADED':
+ return Object.assign({}, spotify, { artist_albums: action.data });
+
+ case 'SPOTIFY_ARTIST_TRACKS_LOADED':
+ return Object.assign({}, spotify, { artist_top_tracks: action.data });
+
case 'SPOTIFY_LIBRARY_ARTISTS_LOADED':
return Object.assign({}, spotify, { libraryArtists: action.data });
diff --git a/src/js/views/Artist.js b/src/js/views/Artist.js
index 4939d039..a58b2d7a 100755
--- a/src/js/views/Artist.js
+++ b/src/js/views/Artist.js
@@ -4,6 +4,8 @@ import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import TrackList from '../components/TrackList'
+import AlbumGrid from '../components/AlbumGrid'
+
import * as spotifyActions from '../services/spotify/actions'
class Artist extends React.Component{
@@ -30,6 +32,8 @@ class Artist extends React.Component{
{ this.props.spotify.artist.name }
{ this.props.spotify.artist.followers.total.toLocaleString() } followers
+ { this.props.spotify.artist_top_tracks ?
: null }
+ { this.props.spotify.artist_albums ?
: null }
);
}
diff --git a/src/js/views/Settings.js b/src/js/views/Settings.js
index 4cb17766..e31c0843 100755
--- a/src/js/views/Settings.js
+++ b/src/js/views/Settings.js
@@ -17,7 +17,9 @@ class Settings extends React.Component{
this.state = {
mopidy_host: this.props.mopidy.host,
- mopidy_port: this.props.mopidy.port
+ mopidy_port: this.props.mopidy.port,
+ spotify_country: this.props.spotify.country,
+ spotify_locale: this.props.spotify.locale
};
}
@@ -26,17 +28,22 @@ class Settings extends React.Component{
window.location.reload(true);
}
- setConfig(){
- this.props.mopidyActions.setConfig( this.state.mopidy_host, this.state.mopidy_port );
+ setMopidyConfig(){
+ this.props.mopidyActions.setConfig({ host: this.state.mopidy_host, port: this.state.mopidy_port });
window.location.reload(true);
}
+ setSpotifyConfig(){
+ this.props.spotifyActions.setConfig({ country: this.state.spotify_country, locale: this.state.spotify_locale });
+ }
+
render(){
return (
Settings
+
Mopidy
-
+
Spotify
+
+
+
this.resetAllSettings()} />
);
diff --git a/src/scss/app.scss b/src/scss/app.scss
index 81b2d372..7aa20635 100755
--- a/src/scss/app.scss
+++ b/src/scss/app.scss
@@ -1,4 +1,8 @@
@import 'vendor/font-awesome/index';
+
+@import 'global/reset';
+@import 'global/forms';
+
@import 'components/track';
diff --git a/src/scss/global/_forms.scss b/src/scss/global/_forms.scss
new file mode 100755
index 00000000..8f82eb81
--- /dev/null
+++ b/src/scss/global/_forms.scss
@@ -0,0 +1,14 @@
+
+input {
+ padding: 5px 8px;
+ border: 1px solid #000000;
+}
+
+button,
+input[type="button"],
+input[type="submit"] {
+ padding: 5px 8px;
+ background: #000000;
+ color: #FFFFFF;
+ border: 0;
+}
\ No newline at end of file
diff --git a/src/scss/global/_reset.scss b/src/scss/global/_reset.scss
new file mode 100755
index 00000000..abae607e
--- /dev/null
+++ b/src/scss/global/_reset.scss
@@ -0,0 +1,7 @@
+
+* {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ outline: 0;
+}
\ No newline at end of file