Artist base url = overview; /iris basename for all URLs, may affect proxy setups
This commit is contained in:
@ -3520,6 +3520,8 @@ select {
|
||||
color: #cf2d2d;
|
||||
display: inline-block;
|
||||
opacity: 1; }
|
||||
.field .description a {
|
||||
color: inherit; }
|
||||
.field.radio input[type="radio"],
|
||||
.field.radio input[type="checkbox"], .field.checkbox input[type="radio"],
|
||||
.field.checkbox input[type="checkbox"] {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
71
mopidy_iris/static/app.min.css
vendored
71
mopidy_iris/static/app.min.css
vendored
@ -3520,6 +3520,8 @@ select {
|
||||
color: #cf2d2d;
|
||||
display: inline-block;
|
||||
opacity: 1; }
|
||||
.field .description a {
|
||||
color: inherit; }
|
||||
.field.radio input[type="radio"],
|
||||
.field.radio input[type="checkbox"], .field.checkbox input[type="radio"],
|
||||
.field.checkbox input[type="checkbox"] {
|
||||
@ -5063,7 +5065,7 @@ aside {
|
||||
.grid__item {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
border-bottom: 0;
|
||||
border-bottom: 0 !important;
|
||||
position: relative;
|
||||
cursor: pointer; }
|
||||
.grid__item__wrapper {
|
||||
@ -5095,9 +5097,9 @@ aside {
|
||||
-webkit-transform: scale(0.98);
|
||||
transform: scale(0.98); }
|
||||
|
||||
.grid--categories .grid__item {
|
||||
.grid--tiles .grid__item {
|
||||
position: relative; }
|
||||
.grid--categories .grid__item__name {
|
||||
.grid--tiles .grid__item__name {
|
||||
position: absolute;
|
||||
bottom: 15%;
|
||||
left: 0;
|
||||
@ -5109,7 +5111,7 @@ aside {
|
||||
z-index: 2; }
|
||||
|
||||
@media (min-width: 1000px) {
|
||||
.grid--categories .grid__item__name {
|
||||
.grid--tiles .grid__item__name {
|
||||
font-size: 16px; } }
|
||||
|
||||
@media (min-width: 1900px) {
|
||||
@ -6408,17 +6410,20 @@ main header {
|
||||
border-color: #08d58f;
|
||||
opacity: 1; }
|
||||
|
||||
.error-boundary {
|
||||
padding: 20px; }
|
||||
.error-boundary__title {
|
||||
.error-message {
|
||||
padding: 40px 40px 40px 80px;
|
||||
position: relative; }
|
||||
.error-message__icon {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 40px;
|
||||
font-size: 2rem;
|
||||
color: #cf2d2d; }
|
||||
.error-message__title {
|
||||
color: #cf2d2d;
|
||||
padding: 10px;
|
||||
padding: 4px 0 10px 0 !important;
|
||||
margin: 0; }
|
||||
.error-boundary__title .icon {
|
||||
font-size: 1em;
|
||||
padding-right: 10px;
|
||||
vertical-align: middle; }
|
||||
.error-boundary__trace {
|
||||
.error-message__trace {
|
||||
padding: 10px; }
|
||||
|
||||
.artist-view .body-loader:not(.lazy-loader) {
|
||||
@ -6750,10 +6755,11 @@ main .track-view {
|
||||
z-index: 2; }
|
||||
.queue-view .current-track .title {
|
||||
font-size: 18px;
|
||||
padding-top: 20px;
|
||||
padding-top: 30px;
|
||||
position: relative;
|
||||
z-index: 2; }
|
||||
.queue-view .current-track .artist-sentence {
|
||||
padding-top: 10px;
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
opacity: 0.5;
|
||||
@ -7117,9 +7123,14 @@ main .track-view {
|
||||
animation-duration: 0.2s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: 1;
|
||||
position: relative;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: #0d0d0d;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
min-height: 100%; }
|
||||
|
||||
@keyframes fadein {
|
||||
@ -7157,9 +7168,9 @@ main .track-view {
|
||||
.modal .actions button {
|
||||
margin: 0 3px; }
|
||||
.modal .content {
|
||||
padding: 80px 25%;
|
||||
padding: 80px 20%;
|
||||
margin: 0 auto;
|
||||
width: 50%;
|
||||
width: 60%;
|
||||
color: #FFFFFF; }
|
||||
.modal .content h1 {
|
||||
padding-bottom: 20px;
|
||||
@ -7238,24 +7249,28 @@ main .track-view {
|
||||
.modal .content .list.playlists {
|
||||
padding-top: 40px; }
|
||||
.modal .content .list.playlists .list__item {
|
||||
margin: 0 0 20px 0;
|
||||
padding: 5px;
|
||||
margin: 5px 0;
|
||||
padding: 10px;
|
||||
cursor: pointer; }
|
||||
.modal .content .list.playlists .list__item:before {
|
||||
display: none; }
|
||||
.modal .content .list.playlists .list__item .thumbnail {
|
||||
float: left;
|
||||
margin-right: 20px; }
|
||||
float: left; }
|
||||
.modal .content .list.playlists .list__item__name, .modal .content .list.playlists .list__item__details {
|
||||
padding-left: 70px; }
|
||||
.modal .content .list.playlists .list__item__name {
|
||||
padding-top: 0;
|
||||
margin-bottom: 5px; }
|
||||
.modal .content .list.playlists .list__item .source {
|
||||
position: static;
|
||||
top: auto;
|
||||
left: auto; }
|
||||
.modal .content .list.small {
|
||||
display: flex;
|
||||
flex-wrap: wrap; }
|
||||
.modal .content .list.small .list__item {
|
||||
width: 49%;
|
||||
float: left;
|
||||
width: 50%;
|
||||
font-size: inherit; }
|
||||
.modal .content .list.small .list__item:nth-child(2n) {
|
||||
margin-left: 2%; }
|
||||
.modal--image-zoom .content {
|
||||
text-align: center;
|
||||
padding: 100px 5%;
|
||||
@ -7268,6 +7283,10 @@ main .track-view {
|
||||
margin-top: 50px; }
|
||||
.modal--edit-radio form .field input[type="text"] {
|
||||
padding-right: 80px; }
|
||||
.modal--share-configuration .field.checkbox .label .title {
|
||||
font-size: 1.2rem; }
|
||||
.modal--share-configuration .field.checkbox .label .description {
|
||||
padding-top: 4px; }
|
||||
.modal--kiosk-mode {
|
||||
background: #000000;
|
||||
overflow: hidden; }
|
||||
@ -7326,6 +7345,8 @@ main .track-view {
|
||||
padding-top: 50px;
|
||||
width: 60vw;
|
||||
max-width: 60vh; }
|
||||
.modal--kiosk-mode .content .progress-wrapper .slider__track {
|
||||
background: rgba(128, 128, 128, 0.25); }
|
||||
@media (max-width: 800px) {
|
||||
.modal .controls {
|
||||
top: 0;
|
||||
|
||||
58
mopidy_iris/static/app.min.js
vendored
58
mopidy_iris/static/app.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -98,7 +98,7 @@
|
||||
|
||||
// Release details
|
||||
// These are automatically injected to built HTML
|
||||
var build = "1548114212";
|
||||
var build = "1548233333";
|
||||
var version = "3.31.8";
|
||||
|
||||
// Construct the script tag
|
||||
|
||||
@ -31,6 +31,7 @@ export default class extends React.Component{
|
||||
if (this.props.nav){
|
||||
return (
|
||||
<NavLink
|
||||
exact={this.props.exact !== undefined ? this.props.exact : false}
|
||||
onClick={e => this.handleClick(e)}
|
||||
activeClassName={this.props.activeClassName ? this.props.activeClassName : className+"--active"}
|
||||
className={className}
|
||||
|
||||
@ -130,7 +130,7 @@ class List extends React.Component{
|
||||
{this.props.thumbnail ? <Thumbnail className="list__item__column__item list__item__column__item--thumbnail" images={(row.images ? row.images : null)} size="small" /> : null}
|
||||
|
||||
<div className="list__item__column__item list__item__column__item--name">
|
||||
{this.renderValue(row, 'name')}
|
||||
{row.name !== undefined ? this.renderValue(row, 'name') : <span className="grey-text">{row.uri}</span>}
|
||||
</div>
|
||||
|
||||
{this.props.details ?<ul className="list__item__column__item list__item__column__item--details details">
|
||||
|
||||
@ -73,7 +73,7 @@ export default class Notifications extends React.Component{
|
||||
<p>Do you want to import this?</p>
|
||||
</div>
|
||||
<br />
|
||||
<a className="button" onClick={e => this.importConfiguration(notification.key, notification.configuration)}>Import</a>
|
||||
<a className="button button--default" onClick={e => this.importConfiguration(notification.key, notification.configuration)}>Import</a>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ global.baseURL = '/';
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<BrowserRouter basename="/iris">
|
||||
<Route path="/" component={App} />
|
||||
</BrowserRouter>
|
||||
</Provider>,
|
||||
|
||||
@ -246,14 +246,19 @@ class Artist extends React.Component{
|
||||
|
||||
var thumbnails = [];
|
||||
if (artist.images && artist.images.length > 0){
|
||||
for (var i = 0; i < artist.images.length; i++){
|
||||
for (var images of artist.images){
|
||||
|
||||
// Capture potential 'null' images
|
||||
// TODO: Prevent these from existing in the first place
|
||||
if (images.huge){
|
||||
thumbnails.push(
|
||||
<div className="tile thumbnail-wrapper" key={i}>
|
||||
<Thumbnail size="huge" canZoom images={artist.images[i]} />
|
||||
<div className="tile thumbnail-wrapper" key={images.huge}>
|
||||
<Thumbnail size="huge" canZoom images={images} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="body about">
|
||||
@ -325,9 +330,10 @@ class Artist extends React.Component{
|
||||
<div className="sub-views" id="sub-views-menu">
|
||||
<Link
|
||||
nav
|
||||
exact={true}
|
||||
className="option"
|
||||
activeClassName="active"
|
||||
to={'/artist/'+this.props.uri+'/overview'}
|
||||
to={'/artist/'+encodeURIComponent(this.props.uri)}
|
||||
scrollTo="sub-views-menu">
|
||||
<h4>Overview</h4>
|
||||
</Link>
|
||||
@ -335,7 +341,7 @@ class Artist extends React.Component{
|
||||
nav
|
||||
className="option"
|
||||
activeClassName="active"
|
||||
to={'/artist/'+this.props.uri+'/related-artists'}
|
||||
to={'/artist/'+encodeURIComponent(this.props.uri)+'/related-artists'}
|
||||
scrollTo="sub-views-menu">
|
||||
<h4>Related artists</h4>
|
||||
</Link> : null}
|
||||
@ -343,7 +349,7 @@ class Artist extends React.Component{
|
||||
nav
|
||||
className="option"
|
||||
activeClassName="active"
|
||||
to={'/artist/'+this.props.uri+'/about'}
|
||||
to={'/artist/'+encodeURIComponent(this.props.uri)+'/about'}
|
||||
scrollTo="sub-views-menu">
|
||||
<h4>About</h4>
|
||||
</Link>
|
||||
@ -358,10 +364,7 @@ class Artist extends React.Component{
|
||||
<Route exact path="/artist/:id/about">
|
||||
{this.renderAbout()}
|
||||
</Route>
|
||||
<Route exact path="/artist/:id/overview">
|
||||
{this.renderOverview()}
|
||||
</Route>
|
||||
<Route>
|
||||
<Route exact path="/artist/:id">
|
||||
{this.renderOverview()}
|
||||
</Route>
|
||||
</Switch>
|
||||
|
||||
@ -34,7 +34,7 @@ class Track extends React.Component{
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.props.coreActions.loadTrack(this.props.match.params.uri);
|
||||
this.props.coreActions.loadTrack(this.props.uri);
|
||||
|
||||
// We already have the track in our index, so it won't fire componentWillReceiveProps
|
||||
if (this.props.track){
|
||||
@ -48,15 +48,15 @@ class Track extends React.Component{
|
||||
|
||||
handleContextMenu(e){
|
||||
e.preventDefault()
|
||||
var data = { uris: [this.props.match.params.uri] }
|
||||
var data = { uris: [this.props.uri] }
|
||||
this.props.uiActions.showContextMenu(e, data, 'track', 'click' )
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
|
||||
// if our URI has changed, fetch new track
|
||||
if (nextProps.match.params.uri != this.props.match.params.uri){
|
||||
this.props.coreActions.loadTrack(nextProps.match.params.uri);
|
||||
if (nextProps.uri != this.props.uri){
|
||||
this.props.coreActions.loadTrack(nextProps.uri);
|
||||
|
||||
if (nextProps.genius_authorized && nextProps.tracks.artists){
|
||||
this.props.geniusActions.findTrackLyrics(nextProps.track);
|
||||
@ -64,8 +64,8 @@ class Track extends React.Component{
|
||||
|
||||
// if mopidy has just connected AND we're not a Spotify track, go get
|
||||
} else if (!this.props.mopidy_connected && nextProps.mopidy_connected){
|
||||
if (helpers.uriSource(this.props.match.params.uri) != 'spotify'){
|
||||
this.props.coreActions.loadTrack(nextProps.match.params.uri);
|
||||
if (helpers.uriSource(this.props.uri) != 'spotify'){
|
||||
this.props.coreActions.loadTrack(nextProps.uri);
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,13 +110,13 @@ class Track extends React.Component{
|
||||
e: e,
|
||||
context: 'track',
|
||||
items: [this.props.track],
|
||||
uris: [this.props.match.params.uri]
|
||||
uris: [this.props.uri]
|
||||
}
|
||||
this.props.uiActions.showContextMenu(data)
|
||||
}
|
||||
|
||||
play(){
|
||||
this.props.mopidyActions.playURIs([this.props.match.params.uri], this.props.match.params.uri)
|
||||
this.props.mopidyActions.playURIs([this.props.uri], this.props.uri)
|
||||
}
|
||||
|
||||
renderLyricsSelector(){
|
||||
@ -191,7 +191,7 @@ class Track extends React.Component{
|
||||
}
|
||||
|
||||
render(){
|
||||
if (helpers.isLoading(this.props.load_queue,['spotify_track/'+helpers.getFromUri('trackid',this.props.match.params.uri)])){
|
||||
if (helpers.isLoading(this.props.load_queue,['spotify_track/'+helpers.getFromUri('trackid',this.props.uri)])){
|
||||
return (
|
||||
<div className="body-loader loading">
|
||||
<div className="loader"></div>
|
||||
@ -238,7 +238,7 @@ class Track extends React.Component{
|
||||
</h2>
|
||||
|
||||
<ul className="details">
|
||||
{!this.props.slim_mode ? <li><Icon type="fontawesome" name={helpers.sourceIcon(this.props.match.params.uri)} /></li> : null}
|
||||
{!this.props.slim_mode ? <li><Icon type="fontawesome" name={helpers.sourceIcon(this.props.uri)} /></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>
|
||||
@ -253,7 +253,7 @@ class Track extends React.Component{
|
||||
|
||||
<div className="actions">
|
||||
<button className="button button--primary" onClick={e => this.play()}>Play</button>
|
||||
<LastfmLoveButton uri={this.props.match.params.uri} artist={(this.props.track.artists ? this.props.track.artists[0].name : null)} track={this.props.track.name} addText="Love" removeText="Unlove" is_loved={this.props.track.userloved} />
|
||||
<LastfmLoveButton uri={this.props.uri} artist={(this.props.track.artists ? this.props.track.artists[0].name : null)} track={this.props.track.name} addText="Love" removeText="Unlove" is_loved={this.props.track.userloved} />
|
||||
<ContextMenuTrigger onTrigger={e => this.handleContextMenu(e)} />
|
||||
</div>
|
||||
|
||||
@ -266,16 +266,10 @@ class Track extends React.Component{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export our component
|
||||
*
|
||||
* We also integrate our global store, using connect()
|
||||
**/
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
var uri = ownProps.match.params.uri;
|
||||
var uri = decodeURIComponent(ownProps.match.params.uri);
|
||||
return {
|
||||
uri: uri,
|
||||
slim_mode: state.ui.slim_mode,
|
||||
load_queue: state.ui.load_queue,
|
||||
track: (state.core.tracks && state.core.tracks[uri] !== undefined ? state.core.tracks[uri] : false),
|
||||
|
||||
@ -95,14 +95,13 @@ class EditCommand extends React.Component{
|
||||
"stop",
|
||||
"shuffle",
|
||||
"snooze",
|
||||
"volume_down",
|
||||
"volume_off",
|
||||
"volume_down",
|
||||
"volume_up",
|
||||
"arrow_left",
|
||||
"arrow_drop_up",
|
||||
"arrow_right",
|
||||
"arrow_drop_down",
|
||||
"volume_up",
|
||||
"done",
|
||||
"done_all",
|
||||
"add",
|
||||
@ -175,7 +174,7 @@ class EditCommand extends React.Component{
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
var id = ownProps.params.id;
|
||||
var id = ownProps.match.params.id;
|
||||
return {
|
||||
id: id,
|
||||
command: (id && state.pusher.commands && state.pusher.commands[id] !== undefined ? state.pusher.commands[id] : null)
|
||||
|
||||
@ -123,7 +123,10 @@ class ShareConfiguration extends React.Component {
|
||||
|
||||
return (
|
||||
<Modal className="modal--share-configuration">
|
||||
|
||||
<h1>Share configuration</h1>
|
||||
<h2>Push your authorizations and interface settings to another, connected user</h2>
|
||||
|
||||
<form onSubmit={e => this.handleSubmit(e)}>
|
||||
<div className="field checkbox white">
|
||||
<div className="name">Recipients</div>
|
||||
|
||||
@ -441,6 +441,10 @@ select {
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
&.radio,
|
||||
|
||||
Reference in New Issue
Block a user