diff --git a/src/js/components/Dater.js b/src/js/components/Dater.js
index f2216c76..e7ce2704 100755
--- a/src/js/components/Dater.js
+++ b/src/js/components/Dater.js
@@ -87,8 +87,21 @@ export default class Dater extends React.Component{
case 'ago':
var date = new Date(this.props.data)
var diff = new Date() - date
- // todo: calculate nice diff
- return diff
+
+ var seconds = Math.floor(diff / 1000)
+ var minutes = Math.floor(diff / (1000 * 60))
+ var hours = Math.floor(diff / (1000 * 60 * 60))
+ var days = Math.floor(diff / (1000 * 60 * 60 * 24))
+
+ if (seconds < 60){
+ return seconds + " seconds";
+ }else if (minutes < 60){
+ return minutes + " minutes";
+ }else if (hours < 24){
+ return hours + " hours";
+ }else{
+ return days + " days"
+ }
break
default:
diff --git a/src/js/components/DropdownField.js b/src/js/components/DropdownField.js
new file mode 100755
index 00000000..8db73064
--- /dev/null
+++ b/src/js/components/DropdownField.js
@@ -0,0 +1,53 @@
+
+import React, { PropTypes } from 'react'
+import { connect } from 'react-redux'
+import { bindActionCreators } from 'redux'
+import FontAwesome from 'react-fontawesome'
+
+export default class DropdownField extends React.Component{
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ expanded: false
+ }
+ }
+
+ handleChange(value){
+ this.setState({ expanded: !this.state.expanded })
+ return this.props.handleChange( value )
+ }
+
+ handleToggle(){
+ this.setState({ expanded: !this.state.expanded })
+ }
+
+ render(){
+ if( !this.props.options ) return null
+
+ var classname = 'dropdown-field'
+ if( this.state.expanded ) classname += ' expanded'
+
+ return (
+
+
this.handleToggle() }>
+
+ { this.props.name }
+
+
+ {
+ this.props.options.map( option => {
+ return (
+
this.handleChange(option.value) }>
+ { option.value == this.props.value ? : null }
+ { option.label }
+
+ )
+ })
+ }
+
+
+ )
+ }
+}
\ No newline at end of file
diff --git a/src/js/services/spotify/reducer.js b/src/js/services/spotify/reducer.js
index 2e7305a4..b39d5c07 100755
--- a/src/js/services/spotify/reducer.js
+++ b/src/js/services/spotify/reducer.js
@@ -119,7 +119,7 @@ export default function reducer(spotify = {}, action){
)
}
return Object.assign({}, spotify, {
- library_tracks: tracks,
+ library_tracks: [...spotify.library_tracks, ...tracks],
library_tracks_more: action.data.next
});
diff --git a/src/js/services/ui/actions.js b/src/js/services/ui/actions.js
index ac025682..0da0ea5f 100755
--- a/src/js/services/ui/actions.js
+++ b/src/js/services/ui/actions.js
@@ -59,6 +59,13 @@ export function dragEnd(){
return { type: 'DRAG_END' }
}
+export function setView( view ){
+ return {
+ type: 'SET_VIEW',
+ view: view
+ }
+}
+
export function reorderPlaylistTracks( uri, indexes, insert_before, snapshot_id = false ){
var range = helpers.createRange( indexes );
switch( helpers.uriSource( uri ) ){
diff --git a/src/js/services/ui/reducer.js b/src/js/services/ui/reducer.js
index d8758145..df23d39d 100755
--- a/src/js/services/ui/reducer.js
+++ b/src/js/services/ui/reducer.js
@@ -7,6 +7,14 @@ export default function reducer(ui = {}, action){
case 'LAZY_LOADING':
return Object.assign({}, ui, { lazy_loading: action.start });
+
+ /**
+ * View views
+ **/
+ case 'SET_VIEW':
+ return Object.assign({}, ui, action.view)
+
+
/**
* Context menu
**/
@@ -286,6 +294,7 @@ export default function reducer(ui = {}, action){
var playlist = Object.assign({}, ui.playlist, { following: action.is_following })
return Object.assign({}, ui, { playlist: playlist, following_loading: false });
+
/**
* Library Playlists
**/
diff --git a/src/js/views/library/LibraryArtists.js b/src/js/views/library/LibraryArtists.js
index 428aa614..44581da0 100755
--- a/src/js/views/library/LibraryArtists.js
+++ b/src/js/views/library/LibraryArtists.js
@@ -7,7 +7,10 @@ import { Link } from 'react-router'
import LazyLoadListener from '../../components/LazyLoadListener'
import Header from '../../components/Header'
import ArtistGrid from '../../components/ArtistGrid'
+import List from '../../components/List'
+import DropdownField from '../../components/DropdownField'
+import * as uiActions from '../../services/ui/actions'
import * as mopidyActions from '../../services/mopidy/actions'
import * as spotifyActions from '../../services/spotify/actions'
@@ -27,13 +30,55 @@ class LibraryArtists extends React.Component{
this.props.spotifyActions.getURL( this.props.artists_more, 'SPOTIFY_LIBRARY_ARTISTS_LOADED_MORE' );
}
+ renderView(){
+ if( !this.props.artists ) return null
+
+ if( this.props.view == 'list' ){
+ var columns = [
+ {
+ width: 30,
+ name: 'name'
+ },
+ {
+ width: 10,
+ name: 'followers.total'
+ }
+ ]
+ return (
+
+ )
+ }else{
+ return (
+
+ )
+ }
+ }
+
render(){
+
+ var view_options = [
+ {
+ value: 'thumbnails',
+ label: 'Thumbnails'
+ },
+ {
+ value: 'list',
+ label: 'List'
+ }
+ ]
+
+ var actions = (
+ this.props.uiActions.setView({ library_artists_view: value }) } />
+ )
+
return (
-
-
- { this.props.artists ? : null }
-
+
+ { this.renderView() }
this.loadMore() }/>
);
@@ -49,6 +94,7 @@ class LibraryArtists extends React.Component{
const mapStateToProps = (state, ownProps) => {
return {
+ view: state.ui.library_artists_view,
artists: state.spotify.library_artists,
artists_more: state.spotify.library_artists_more
}
@@ -56,6 +102,7 @@ const mapStateToProps = (state, ownProps) => {
const mapDispatchToProps = (dispatch) => {
return {
+ uiActions: bindActionCreators(uiActions, dispatch),
mopidyActions: bindActionCreators(mopidyActions, dispatch),
spotifyActions: bindActionCreators(spotifyActions, dispatch)
}
diff --git a/src/js/views/library/LibraryTracks.js b/src/js/views/library/LibraryTracks.js
index 71ab13ac..e1f0c5aa 100755
--- a/src/js/views/library/LibraryTracks.js
+++ b/src/js/views/library/LibraryTracks.js
@@ -33,8 +33,8 @@ class LibraryTracks extends React.Component{
{ this.props.tracks ? : null }
+ this.loadMore() }/>
- this.loadMore() }/>
);
}
diff --git a/src/scss/app.scss b/src/scss/app.scss
index 2000d62d..2976536a 100755
--- a/src/scss/app.scss
+++ b/src/scss/app.scss
@@ -18,6 +18,7 @@
@import 'components/lists';
@import 'components/grid';
@import 'components/header';
+@import 'components/dropdown-field';
@import 'views/artist';
@import 'views/user';
diff --git a/src/scss/components/_dropdown-field.scss b/src/scss/components/_dropdown-field.scss
new file mode 100755
index 00000000..8d02aa2b
--- /dev/null
+++ b/src/scss/components/_dropdown-field.scss
@@ -0,0 +1,51 @@
+
+.dropdown-field {
+ font-size: 14px;
+ font-weight: 600;
+ text-transform: uppercase;
+ position: relative;
+
+ .label {
+ padding: 18px 10px;
+ cursor: pointer;
+ }
+
+ &.expanded {
+ .label {
+ background: $dark_grey;
+ color: #FFFFFF;
+ }
+ .options {
+ display: block;
+ }
+ }
+
+ .options {
+ color: #FFFFFF;
+ position: absolute;
+ top: 54px;
+ right: 0px;
+ z-index: 97;
+ background: $dark_grey;
+ display: none;
+
+ .option {
+ position: relative;
+ padding: 10px 16px 10px 34px;
+ border-top: 1px solid lighten($dark_grey, 10%);
+ cursor: pointer;
+
+ .fa {
+ position: absolute;
+ top: 13px;
+ left: 12px;
+ font-size: 12px;
+ }
+
+ &:hover {
+ background: lighten($dark_grey, 10%);
+ }
+ }
+ }
+}
+