Working on known bugs

See issue #16

* Add basic settings view
* Fix play next song when playlist is on
* Add timer styling on webplayer
* Fix wrong albums being linked in songs table
This commit is contained in:
Lucas Verney 2016-09-18 20:57:51 +02:00
parent 23aa8b52ab
commit 198d50aec5
15 changed files with 95 additions and 40 deletions

View File

@ -0,0 +1,26 @@
// NPM imports
import React, { Component } from "react";
import CSSModules from "react-css-modules";
import { injectIntl, intlShape } from "react-intl";
// Styles
import css from "../styles/Songs.scss";
/**
* A single row for a single song in the songs table.
*/
class SettingsCSSIntl extends Component {
render() {
return (
<div>
<h2>Settings</h2>
<p>TODO</p>
</div>
);
}
}
SettingsCSSIntl.propTypes = {
intl: intlShape.isRequired,
};
export default injectIntl(CSSModules(SettingsCSSIntl, css));

View File

@ -58,8 +58,8 @@ class SongsTableRowCSSIntl extends Component {
const { formatMessage } = this.props.intl; const { formatMessage } = this.props.intl;
const length = formatLength(this.props.song.get("time")); const length = formatLength(this.props.song.get("time"));
const linkToArtist = "/artist/" + this.props.song.getIn(["artist", "id"]); const linkToArtist = "/artist/" + this.props.song.getIn(["artist", "id"]) + "-" + encodeURIComponent(this.props.song.getIn(["artist", "name"]));
const linkToAlbum = "/album/" + this.props.song.getIn(["album", "id"]); const linkToAlbum = linkToArtist + "/album/" + this.props.song.getIn(["album", "id"]) + "-" + encodeURIComponent(this.props.song.getIn(["album", "name"]));
return ( return (
<tr> <tr>

View File

@ -118,6 +118,7 @@ class WebPlayerCSSIntl extends Component {
<div className="col-xs-12"> <div className="col-xs-12">
<div className="row" styleName="artRow" onMouseOver={this.artOpacityHandler} onMouseOut={this.artOpacityHandler}> <div className="row" styleName="artRow" onMouseOver={this.artOpacityHandler} onMouseOut={this.artOpacityHandler}>
<div className="col-xs-12"> <div className="col-xs-12">
<div styleName="artTimer"></div>
<img src={art} width="200" height="200" alt={formatMessage(webplayerMessages["app.common.art"])} ref="art" styleName="art" /> <img src={art} width="200" height="200" alt={formatMessage(webplayerMessages["app.common.art"])} ref="art" styleName="art" />
<div ref="artText"> <div ref="artText">
{ {
@ -166,6 +167,7 @@ class WebPlayerCSSIntl extends Component {
<button styleName={randomBtnStyles.join(" ")} aria-label={formatMessage(webplayerMessages["app.webplayer.random"])} title={formatMessage(webplayerMessages["app.webplayer.random"])} aria-pressed={this.props.isRandom} onClick={onRandom} ref="randomBtn"> <button styleName={randomBtnStyles.join(" ")} aria-label={formatMessage(webplayerMessages["app.webplayer.random"])} title={formatMessage(webplayerMessages["app.webplayer.random"])} aria-pressed={this.props.isRandom} onClick={onRandom} ref="randomBtn">
<FontAwesome name="random" /> <FontAwesome name="random" />
</button> </button>
{ /* TODO: If already on playlist page, should go back. */ }
<Link to="/playlist" styleName={playlistBtnStyles.join(" ")} aria-label={formatMessage(webplayerMessages["app.webplayer.playlist"])} title={formatMessage(webplayerMessages["app.webplayer.playlist"])}> <Link to="/playlist" styleName={playlistBtnStyles.join(" ")} aria-label={formatMessage(webplayerMessages["app.webplayer.playlist"])} title={formatMessage(webplayerMessages["app.webplayer.playlist"])}>
<FontAwesome name="list" /> <FontAwesome name="list" />
</Link> </Link>

View File

@ -133,12 +133,13 @@ export default createReducer(initialState, {
} }
}, },
[PLAY_NEXT_SONG]: (state) => { [PLAY_NEXT_SONG]: (state) => {
const newIndex = state.get("currentIndex") + 1; let newIndex = state.get("currentIndex") + 1;
if (newIndex >= state.get("playlist").size) { if (newIndex >= state.get("playlist").size) {
// If there is an overflow // If there is an overflow
if (state.get("isRepeat")) { if (state.get("isRepeat")) {
// TODO: Handle repeat // If we are at the end of the playlist and repeat mode is on,
return state.set("error", null); // just play back first song.
newIndex = 0;
} else { } else {
// Just stop playback // Just stop playback
return ( return (

View File

@ -18,6 +18,7 @@ import LoginPage from "./views/LoginPage";
import LogoutPage from "./views/LogoutPage"; import LogoutPage from "./views/LogoutPage";
import PlaylistPage from "./views/PlaylistPage"; import PlaylistPage from "./views/PlaylistPage";
import SongsPage from "./views/SongsPage"; import SongsPage from "./views/SongsPage";
import SettingsPage from "./views/SettingsPage";
export default ( export default (
<Route path="/" component={App}> // Main container is App <Route path="/" component={App}> // Main container is App
@ -35,6 +36,7 @@ export default (
<Route path="artist/:artist/album/:album" component={ArtistPage} /> <Route path="artist/:artist/album/:album" component={ArtistPage} />
<Route path="songs" component={SongsPage} /> <Route path="songs" component={SongsPage} />
<Route path="playlist" component={PlaylistPage} /> <Route path="playlist" component={PlaylistPage} />
<Route path="settings" component={SettingsPage} />
<IndexRoute component={HomePage} /> <IndexRoute component={HomePage} />
</Route> </Route>
</Route> </Route>

View File

@ -19,6 +19,15 @@ $controlsMarginTop: 10px;
min-height: 200px; min-height: 200px;
} }
.artTimer {
position: absolute;
width: 50px;
height: 200px;
background-color: black;
opacity: 0.75;
z-index: -9;
}
/** /**
* Controls * Controls
*/ */

View File

@ -1,6 +1,3 @@
/**
* TODO: Scroll to album if /album/:id is passed.
*/
// NPM imports // NPM imports
import React, { Component, PropTypes } from "react"; import React, { Component, PropTypes } from "react";
import { bindActionCreators } from "redux"; import { bindActionCreators } from "redux";

View File

@ -0,0 +1,18 @@
// NPM imports
import React, { Component } from "react";
// Components
import Settings from "../components/Settings";
/**
* Paginated table of available songs
*/
class SettingsPage extends Component {
render() {
return (
<Settings />
);
}
}
export default SettingsPage;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
!function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={exports:{},id:r,loaded:!1};return e[r].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="./",t(0)}({0:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(636);Object.keys(r).forEach(function(e){"default"!==e&&"__esModule"!==e&&Object.defineProperty(t,e,{enumerable:!0,get:function(){return r[e]}})})},636:function(e,t){!function(t,n){function r(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x<style>"+t+"</style>",r.insertBefore(n.lastChild,r.firstChild)}function a(){var e=b.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=b.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),b.elements=n+" "+e,s(t)}function c(e){var t=E[e[v]];return t||(t={},y++,e[v]=y,E[y]=t),t}function i(e,t,r){if(t||(t=n),f)return t.createElement(e);r||(r=c(t));var a;return a=r.cache[e]?r.cache[e].cloneNode():g.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!a.canHaveChildren||p.test(e)||a.tagUrn?a:r.frag.appendChild(a)}function l(e,t){if(e||(e=n),f)return e.createDocumentFragment();t=t||c(e);for(var r=t.frag.cloneNode(),o=0,i=a(),l=i.length;o<l;o++)r.createElement(i[o]);return r}function u(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return b.shivMethods?i(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+a().join().replace(/[\w\-:]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(b,t.frag)}function s(e){e||(e=n);var t=c(e);return!b.shivCSS||d||t.hasCSS||(t.hasCSS=!!r(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),f||u(e,t),e}var d,f,m="3.7.3-pre",h=t.html5||{},p=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",y=0,E={};!function(){try{var e=n.createElement("a");e.innerHTML="<xyz></xyz>",d="hidden"in e,f=1==e.childNodes.length||function(){n.createElement("a");var e=n.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(t){d=!0,f=!0}}();var b={elements:h.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:h.shivCSS!==!1,supportsUnknownElements:f,shivMethods:h.shivMethods!==!1,type:"default",shivDocument:s,createElement:i,createDocumentFragment:l,addElements:o};t.html5=b,s(n),"object"==typeof e&&e.exports&&(e.exports=b)}("undefined"!=typeof window?window:this,document)}}); !function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={exports:{},id:r,loaded:!1};return e[r].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="./",t(0)}({0:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(638);Object.keys(r).forEach(function(e){"default"!==e&&"__esModule"!==e&&Object.defineProperty(t,e,{enumerable:!0,get:function(){return r[e]}})})},638:function(e,t){!function(t,n){function r(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x<style>"+t+"</style>",r.insertBefore(n.lastChild,r.firstChild)}function a(){var e=b.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=b.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),b.elements=n+" "+e,s(t)}function c(e){var t=E[e[v]];return t||(t={},y++,e[v]=y,E[y]=t),t}function i(e,t,r){if(t||(t=n),f)return t.createElement(e);r||(r=c(t));var a;return a=r.cache[e]?r.cache[e].cloneNode():g.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!a.canHaveChildren||p.test(e)||a.tagUrn?a:r.frag.appendChild(a)}function l(e,t){if(e||(e=n),f)return e.createDocumentFragment();t=t||c(e);for(var r=t.frag.cloneNode(),o=0,i=a(),l=i.length;o<l;o++)r.createElement(i[o]);return r}function u(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return b.shivMethods?i(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+a().join().replace(/[\w\-:]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(b,t.frag)}function s(e){e||(e=n);var t=c(e);return!b.shivCSS||d||t.hasCSS||(t.hasCSS=!!r(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),f||u(e,t),e}var d,f,m="3.7.3-pre",h=t.html5||{},p=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",y=0,E={};!function(){try{var e=n.createElement("a");e.innerHTML="<xyz></xyz>",d="hidden"in e,f=1==e.childNodes.length||function(){n.createElement("a");var e=n.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(t){d=!0,f=!0}}();var b={elements:h.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:h.shivCSS!==!1,supportsUnknownElements:f,shivMethods:h.shivMethods!==!1,type:"default",shivDocument:s,createElement:i,createDocumentFragment:l,addElements:o};t.html5=b,s(n),"object"==typeof e&&e.exports&&(e.exports=b)}("undefined"!=typeof window?window:this,document)}});
//# sourceMappingURL=fix.ie9.js.map //# sourceMappingURL=fix.ie9.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long