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:
parent
23aa8b52ab
commit
198d50aec5
26
app/components/Settings.jsx
Normal file
26
app/components/Settings.jsx
Normal 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));
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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 (
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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";
|
||||||
|
18
app/views/SettingsPage.jsx
Normal file
18
app/views/SettingsPage.jsx
Normal 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
@ -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
Loading…
Reference in New Issue
Block a user