Track template with extra info; Context menu to get to tracks
This commit is contained in:
@ -229,6 +229,15 @@ class ContextMenu extends React.Component{
|
||||
}
|
||||
}
|
||||
|
||||
goToTrack(e){
|
||||
if (!this.props.menu.items || this.props.menu.items.length <= 0){
|
||||
return null
|
||||
} else {
|
||||
this.props.uiActions.hideContextMenu()
|
||||
hashHistory.push( global.baseURL +'track/'+ encodeURIComponent(this.props.menu.items[0].uri))
|
||||
}
|
||||
}
|
||||
|
||||
copyURIs(e){
|
||||
var temp = $("<input>");
|
||||
$("body").append(temp);
|
||||
@ -452,6 +461,14 @@ class ContextMenu extends React.Component{
|
||||
</span>
|
||||
)
|
||||
|
||||
var go_to_track = (
|
||||
<span className="menu-item-wrapper">
|
||||
<a className="menu-item" onClick={e => this.goToTrack(e)}>
|
||||
<span className="label">Track info</span>
|
||||
</a>
|
||||
</span>
|
||||
)
|
||||
|
||||
var go_to_recommendations = (
|
||||
<span className="menu-item-wrapper">
|
||||
<a className="menu-item" onClick={e => this.goToRecommendations(e)}>
|
||||
@ -555,8 +572,9 @@ class ContextMenu extends React.Component{
|
||||
<div>
|
||||
{play_queue_item}
|
||||
{add_to_playlist}
|
||||
{context.source == 'spotify' ? go_to_recommendations : null}
|
||||
{context.source == 'spotify' && context.items_count == 1 ? go_to_recommendations : null}
|
||||
{copy_uris}
|
||||
{context.items_count == 1 ? go_to_track : null}
|
||||
{remove_from_queue}
|
||||
</div>
|
||||
)
|
||||
@ -569,8 +587,9 @@ class ContextMenu extends React.Component{
|
||||
{play_uris_next}
|
||||
{add_to_queue}
|
||||
{add_to_playlist}
|
||||
{start_radio}
|
||||
{context.source == 'spotify' && context.items_count == 1 ? start_radio : null}
|
||||
{copy_uris}
|
||||
{context.items_count == 1 ? go_to_track : null}
|
||||
{remove_from_playlist}
|
||||
</div>
|
||||
)
|
||||
@ -583,8 +602,9 @@ class ContextMenu extends React.Component{
|
||||
{play_uris_next}
|
||||
{add_to_queue}
|
||||
{add_to_playlist}
|
||||
{context.source == 'spotify' ? start_radio : null}
|
||||
{context.source == 'spotify' ? go_to_recommendations : null}
|
||||
{context.source == 'spotify' && context.items_count == 1 ? start_radio : null}
|
||||
{context.source == 'spotify' && context.items_count == 1 ? go_to_recommendations : null}
|
||||
{context.items_count == 1 ? go_to_track : null}
|
||||
{copy_uris}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -111,6 +111,10 @@ export default class Dater extends React.Component{
|
||||
}
|
||||
|
||||
render(){
|
||||
return <span className="dater">{ this.calculate() }</span>
|
||||
if (!this.props.data){
|
||||
return null;
|
||||
} else {
|
||||
return <span className="dater">{ this.calculate() }</span>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,7 +59,7 @@ const CoreMiddleware = (function(){
|
||||
}
|
||||
);
|
||||
|
||||
if (action.data.xhr){
|
||||
if (action.data.xhr && action.data.xhr.responseText){
|
||||
var xhr_response = JSON.parse(action.data.xhr.responseText);
|
||||
if (xhr_response.error && xhr_response.error.message){
|
||||
message = message+'<p class="description">'+xhr_response.error.message+'</p>';
|
||||
|
||||
@ -201,6 +201,13 @@ export function getDirectory( uri ){
|
||||
}
|
||||
}
|
||||
|
||||
export function getTrack( uri ){
|
||||
return {
|
||||
type: 'MOPIDY_GET_TRACK',
|
||||
data: { uri: uri }
|
||||
}
|
||||
}
|
||||
|
||||
export function getLibraryArtists(){
|
||||
return {
|
||||
type: 'MOPIDY_GET_LIBRARY_ARTISTS'
|
||||
|
||||
@ -1703,6 +1703,27 @@ const MopidyMiddleware = (function(){
|
||||
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'MOPIDY_GET_TRACK':
|
||||
instruct( socket, store, 'library.lookup', action.data )
|
||||
.then(
|
||||
response => {
|
||||
if (response.length > 0){
|
||||
store.dispatch({
|
||||
type: 'TRACK_LOADED',
|
||||
key: action.data.uri,
|
||||
track: response[0]
|
||||
});
|
||||
}
|
||||
},
|
||||
error => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
"Mopidy: "+(error.message ? error.message : "Could not get track"),
|
||||
error
|
||||
));
|
||||
}
|
||||
)
|
||||
break
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Link } from 'react-router'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import FontAwesome from 'react-fontawesome'
|
||||
|
||||
import Header from '../components/Header'
|
||||
import TrackList from '../components/TrackList'
|
||||
import Thumbnail from '../components/Thumbnail'
|
||||
import Parallax from '../components/Parallax'
|
||||
import ArtistSentence from '../components/ArtistSentence'
|
||||
import ArtistGrid from '../components/ArtistGrid'
|
||||
import FollowButton from '../components/FollowButton'
|
||||
@ -48,7 +48,10 @@ class Track extends React.Component{
|
||||
if( helpers.uriSource( this.props.params.uri ) != 'spotify' ){
|
||||
this.loadTrack( nextProps )
|
||||
}
|
||||
} else if (!nextProps.track.lyrics && nextProps.track.artists && !this.props.track.artists){
|
||||
}
|
||||
|
||||
// We don't have lyrics, and we have just received our artists
|
||||
if (!nextProps.track.lyrics && !this.props.track.artists && nextProps.track.artists){
|
||||
this.props.geniusActions.getTrackLyrics(nextProps.track);
|
||||
}
|
||||
}
|
||||
@ -73,6 +76,16 @@ class Track extends React.Component{
|
||||
this.props.spotifyActions.getTrack( props.params.uri );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (props.mopidy_connected){
|
||||
if (props.track){
|
||||
console.info('Loading track from index')
|
||||
} else {
|
||||
this.props.mopidyActions.getTrack( props.params.uri );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,24 +118,42 @@ class Track extends React.Component{
|
||||
|
||||
if (!this.props.track){
|
||||
return null
|
||||
} else {
|
||||
var track = this.props.track
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="view track-view content-wrapper">
|
||||
|
||||
{this.props.slim_mode ? <Header icon="cd" title="Album" handleContextMenuTrigger={e => this.handleContextMenu(e)} uiActions={this.props.uiActions} /> : null}
|
||||
{this.props.slim_mode ? <Header
|
||||
icon="music"
|
||||
title="Track"
|
||||
handleContextMenuTrigger={e => this.handleContextMenu(e)}
|
||||
uiActions={this.props.uiActions} /> : null}
|
||||
|
||||
<div className="thumbnail-wrapper">
|
||||
<Thumbnail size="large" canZoom images={ this.props.track.album.images } />
|
||||
<Thumbnail size="large" canZoom images={track.images} />
|
||||
</div>
|
||||
|
||||
<div className="title">
|
||||
|
||||
<h1>{ this.props.track.name }</h1>
|
||||
<h1>{track.name}</h1>
|
||||
<h2 className="grey-text">{track.album ? <Link to={global.baseURL+'album/'+track.album.uri}>{track.album.name}</Link> : "Unknown album"} by <ArtistSentence artists={track.artists} /></h2>
|
||||
|
||||
<ul className="details">
|
||||
{ !this.props.slim_mode ? <li className="has-tooltip"><FontAwesome name={helpers.sourceIcon( this.props.params.uri )} /><span className="tooltip">{helpers.uriSource( this.props.params.uri )} track</span></li> : null }
|
||||
<li><ArtistSentence artists={this.props.track.artists} /></li>
|
||||
{!this.props.slim_mode ? <li className="has-tooltip"><FontAwesome name={helpers.sourceIcon(this.props.params.uri)} /><span className="tooltip">{helpers.uriSource(this.props.params.uri)} track</span></li> : null}
|
||||
{track.date ? <li><Dater type="date" data={track.date} /></li> : null}
|
||||
{track.explicit ? <li><span className="flag dark">EXPLICIT</span></li> : null}
|
||||
<li>
|
||||
{track.disc_no ? <span>Disc {track.disc_no}</span> : null}
|
||||
{track.disc_number ? <span>Disc {track.disc_number}</span> : null}
|
||||
{track.track_no ? <span>, track {track.track_no}</span> : null}
|
||||
{track.track_number ? <span>, track {track.track_number}</span> : null}
|
||||
</li>
|
||||
<li>
|
||||
{track.duration_ms ? <Dater type="length" data={track.duration_ms} /> : null}
|
||||
{track.length ? <Dater type="length" data={track.length} /> : null}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
@import 'views/user';
|
||||
@import 'views/album';
|
||||
@import 'views/playlist';
|
||||
@import 'views/track';
|
||||
@import 'views/queue';
|
||||
@import 'views/search';
|
||||
@import 'views/library';
|
||||
|
||||
@ -158,6 +158,13 @@ h2 {
|
||||
border-bottom: 1px solid $white;
|
||||
}
|
||||
}
|
||||
|
||||
&.grey-text {
|
||||
a:hover {
|
||||
color: $mid_grey !important;
|
||||
border-bottom: 1px solid $mid_grey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
|
||||
83
src/scss/views/_track.scss
Executable file
83
src/scss/views/_track.scss
Executable file
@ -0,0 +1,83 @@
|
||||
|
||||
main .track-view {
|
||||
padding-left: 30%;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
h2 {
|
||||
a:hover {
|
||||
color: darken($mid_grey, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
padding: 25px 0 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.thumbnail-wrapper {
|
||||
position: absolute;
|
||||
padding: 40px;
|
||||
width: 30%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
.thumbnail {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.lyrics {
|
||||
p {
|
||||
line-height: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( $bp_medium ){
|
||||
padding-top: 0;
|
||||
padding-left: 10px;
|
||||
|
||||
.thumbnail-wrapper {
|
||||
width: 40%;
|
||||
padding: 10px 20px 10px 0;
|
||||
float: left;
|
||||
position: static;
|
||||
|
||||
.thumbnail {
|
||||
float: none;
|
||||
max-width: none;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 30px 0 20px 40%;
|
||||
|
||||
.details {
|
||||
padding: 5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@include clearfix();
|
||||
padding: 10px 0 20px 40%;
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive( $bp_small ){
|
||||
.title {
|
||||
@include clearfix();
|
||||
padding: 20px 20px 10px 40%;
|
||||
min-height: 20vw;
|
||||
}
|
||||
|
||||
.actions {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user