Build issue; Grid items
This commit is contained in:
9
build.sh
Executable file
9
build.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! -d production ]; then
|
||||
mkdir production;
|
||||
fi
|
||||
|
||||
cp src/index.html production/index.html
|
||||
cp src/.htaccess production/.htaccess
|
||||
cp -R src/fonts production/fonts
|
||||
@ -1,40 +0,0 @@
|
||||
0 info it worked if it ends with ok
|
||||
1 verbose cli [ '/usr/bin/nodejs', '/usr/bin/npm', 'run', 'dev' ]
|
||||
2 info using npm@2.15.8
|
||||
3 info using node@v4.4.7
|
||||
4 verbose run-script [ 'predev', 'dev', 'postdev' ]
|
||||
5 info predev iris@1.0.0
|
||||
6 info dev iris@1.0.0
|
||||
7 verbose unsafe-perm in lifecycle true
|
||||
8 info iris@1.0.0 Failed to exec dev script
|
||||
9 verbose stack Error: iris@1.0.0 dev: `mkdir production & cp src/index.html production/index.html & cp -R src/fonts production/fonts & NODE_ENV=development webpack & sass src/scss/app.scss production/app.css`
|
||||
9 verbose stack Exit status 65
|
||||
9 verbose stack at EventEmitter.<anonymous> (/usr/lib/node_modules/npm/lib/utils/lifecycle.js:217:16)
|
||||
9 verbose stack at emitTwo (events.js:87:13)
|
||||
9 verbose stack at EventEmitter.emit (events.js:172:7)
|
||||
9 verbose stack at ChildProcess.<anonymous> (/usr/lib/node_modules/npm/lib/utils/spawn.js:24:14)
|
||||
9 verbose stack at emitTwo (events.js:87:13)
|
||||
9 verbose stack at ChildProcess.emit (events.js:172:7)
|
||||
9 verbose stack at maybeClose (internal/child_process.js:827:16)
|
||||
9 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
|
||||
10 verbose pkgid iris@1.0.0
|
||||
11 verbose cwd /var/www/iris
|
||||
12 error Linux 3.16.0-4-amd64
|
||||
13 error argv "/usr/bin/nodejs" "/usr/bin/npm" "run" "dev"
|
||||
14 error node v4.4.7
|
||||
15 error npm v2.15.8
|
||||
16 error code ELIFECYCLE
|
||||
17 error iris@1.0.0 dev: `mkdir production & cp src/index.html production/index.html & cp -R src/fonts production/fonts & NODE_ENV=development webpack & sass src/scss/app.scss production/app.css`
|
||||
17 error Exit status 65
|
||||
18 error Failed at the iris@1.0.0 dev script 'mkdir production & cp src/index.html production/index.html & cp -R src/fonts production/fonts & NODE_ENV=development webpack & sass src/scss/app.scss production/app.css'.
|
||||
18 error This is most likely a problem with the iris package,
|
||||
18 error not with npm itself.
|
||||
18 error Tell the author that this fails on your system:
|
||||
18 error mkdir production & cp src/index.html production/index.html & cp -R src/fonts production/fonts & NODE_ENV=development webpack & sass src/scss/app.scss production/app.css
|
||||
18 error You can get information on how to open an issue for this project with:
|
||||
18 error npm bugs iris
|
||||
18 error Or if that isn't available, you can get their info via:
|
||||
18 error
|
||||
18 error npm owner ls iris
|
||||
18 error There is likely additional logging output above.
|
||||
19 verbose exit [ 1, true ]
|
||||
@ -34,7 +34,7 @@
|
||||
"react-fontawesome": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "mkdir production & cp src/index.html production/index.html & cp -R src/fonts production/fonts & NODE_ENV=development webpack & sass src/scss/app.scss production/app.css",
|
||||
"dev": "./build.sh & NODE_ENV=development webpack & sass src/scss/app.scss production/app.css",
|
||||
"prod": "NODE_ENV=production webpack"
|
||||
},
|
||||
"author": "James Barnsley",
|
||||
|
||||
6
src/.htaccess
Executable file
6
src/.htaccess
Executable file
@ -0,0 +1,6 @@
|
||||
RewriteEngine On
|
||||
|
||||
RewriteBase /
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule . /index.html [L]
|
||||
@ -1,6 +1,6 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import AlbumGridItem from './AlbumGridItem'
|
||||
import GridItem from './GridItem'
|
||||
|
||||
export default class AlbumGrid extends React.Component{
|
||||
|
||||
@ -15,7 +15,9 @@ export default class AlbumGrid extends React.Component{
|
||||
{
|
||||
this.props.items.items.map(
|
||||
(album, index) => {
|
||||
return <AlbumGridItem item={album} key={index} />
|
||||
var link = album.uri;
|
||||
if( album.album ) link = album.album.uri;
|
||||
return <GridItem item={album} key={index} link={'/album/'+link} />
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { Link } from 'react-router'
|
||||
import Thumbnail from './Thumbnail'
|
||||
|
||||
export default class AlbumGridItem extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render(){
|
||||
var item = this.props.item;
|
||||
if( typeof(item.album) !== 'undefined' ){
|
||||
item.album.added_at = item.added_at;
|
||||
item = item.album;
|
||||
}
|
||||
var link = '/album/' + item.uri;
|
||||
return (
|
||||
<Link to={link} className="grid-item album-grid-item">
|
||||
{ item.images ? <Thumbnail size="medium" images={item.images} /> : item.name }
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
28
src/js/components/ArtistGrid.js
Executable file
28
src/js/components/ArtistGrid.js
Executable file
@ -0,0 +1,28 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import AlbumGridItem from './AlbumGridItem'
|
||||
|
||||
export default class AlbumGrid extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render(){
|
||||
if( this.props.items ){
|
||||
return (
|
||||
<ul className="grid album-grid">
|
||||
{
|
||||
this.props.items.items.map(
|
||||
(album, index) => {
|
||||
return <AlbumGridItem item={album} key={index} />
|
||||
}
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
37
src/js/components/GridItem.js
Executable file
37
src/js/components/GridItem.js
Executable file
@ -0,0 +1,37 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { Link, browserHistory } from 'react-router'
|
||||
|
||||
import Thumbnail from './Thumbnail'
|
||||
import ArtistList from './ArtistList'
|
||||
|
||||
export default class GridItem extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
handleClick(e){
|
||||
if( e.target.tagName.toLowerCase() !== 'a' ){
|
||||
browserHistory.push( this.props.link );
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
var item = this.props.item;
|
||||
if( typeof(item.album) !== 'undefined' ){
|
||||
item.album.added_at = item.added_at;
|
||||
item = item.album;
|
||||
}
|
||||
return (
|
||||
<div className="grid-item" onClick={ (e) => this.handleClick(e) }>
|
||||
{ item.images ? <Thumbnail size="medium" images={item.images} /> : item.name }
|
||||
<div className="name">{ item.name }</div>
|
||||
<div className="secondary">
|
||||
{ item.artists ? <ArtistList artists={ item.artists } /> : null }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,9 +40,7 @@ export default class Track extends React.Component{
|
||||
render(){
|
||||
|
||||
var className = 'list-item track';
|
||||
var selectedIcon = 'square-o';
|
||||
if( typeof(this.props.track.selected) !== 'undefined' && this.props.track.selected ){
|
||||
selectedIcon = 'check-square-o';
|
||||
className += ' selected';
|
||||
}
|
||||
|
||||
@ -55,12 +53,12 @@ export default class Track extends React.Component{
|
||||
className={className}
|
||||
onDoubleClick={ (e) => this.handleDoubleClick(e) }
|
||||
onClick={ (e) => this.handleClick(e) }>
|
||||
<FontAwesome name={selectedIcon} className="select-state" fixedWidth />
|
||||
{ this.props.track.selected ? <FontAwesome name="check" className="select-state" fixedWidth /> : null }
|
||||
<span className="col name">
|
||||
{this.props.track.name}
|
||||
</span>
|
||||
<span className="col artists">
|
||||
<ArtistList artists={this.props.track.artists} />
|
||||
{ this.props.track.artists ? <ArtistList artists={this.props.track.artists} /> : null }
|
||||
</span>
|
||||
<span className="col album">
|
||||
{ this.props.track.album ? <AlbumLink album={this.props.track.album} /> : null }
|
||||
|
||||
@ -19,18 +19,6 @@ export default function reducer(mopidy = {}, action){
|
||||
tlid: action.tlid
|
||||
});
|
||||
|
||||
case 'MOPIDY_HIGHLIGHT_CURRENT_TLTRACK':
|
||||
if( !action.data ) return mopidy;
|
||||
for( var i = 0; i < mopidy.tracks.length; i++ ){
|
||||
if( mopidy.tracks[i].tlid == action.data.tlid ){
|
||||
action.data.track.playing = true;
|
||||
Object.assign(mopidy.tracks[i], action.data);
|
||||
}else{
|
||||
mopidy.tracks[i].track.playing = false;
|
||||
}
|
||||
}
|
||||
return Object.assign({}, mopidy, { tracks: mopidy.tracks });
|
||||
|
||||
case 'MOPIDY_PLAYLISTS_LOADED':
|
||||
if( !action.data ) return mopidy;
|
||||
return Object.assign({}, mopidy, { playlists: action.data });
|
||||
@ -65,8 +53,16 @@ export default function reducer(mopidy = {}, action){
|
||||
});
|
||||
|
||||
case 'MOPIDY_CURRENTTLTRACK':
|
||||
var tracks = [];
|
||||
Object.assign(tracks, mopidy.tracks);
|
||||
|
||||
for( var i = 0; i < tracks.length; i++ ){
|
||||
Object.assign(tracks[i].track, { playing: ( tracks[i].tlid == action.data.tlid ) });
|
||||
}
|
||||
|
||||
return Object.assign({}, mopidy, {
|
||||
currentTlTrack: action.data
|
||||
currentTlTrack: action.data,
|
||||
tracks: tracks
|
||||
});
|
||||
|
||||
case 'MOPIDY_VOLUME':
|
||||
|
||||
@ -46,35 +46,39 @@ class Settings extends React.Component{
|
||||
title="Settings"
|
||||
/>
|
||||
|
||||
<h4>Mopidy</h4>
|
||||
<form onSubmit={() => this.setMopidyConfig()}>
|
||||
<label>
|
||||
<span className="label">Host</span>
|
||||
<input onChange={ e => this.setState({ mopidy_host: e.target.value })} value={ this.state.mopidy_host } />
|
||||
</label>
|
||||
<label>
|
||||
<span className="label">Port</span>
|
||||
<input onChange={ e => this.setState({ mopidy_port: e.target.value })} value={ this.state.mopidy_port } />
|
||||
</label>
|
||||
<button type="submit">Apply</button>
|
||||
</form>
|
||||
<section>
|
||||
|
||||
<h4>Spotify</h4>
|
||||
<form onSubmit={() => this.setSpotifyConfig()}>
|
||||
<label>
|
||||
<span className="label">Country</span>
|
||||
<input onChange={ e => this.setState({ spotify_country: e.target.value })} value={ this.state.spotify_country } />
|
||||
</label>
|
||||
<label>
|
||||
<span className="label">Locale</span>
|
||||
<input onChange={ e => this.setState({ spotify_locale: e.target.value })} value={ this.state.spotify_locale } />
|
||||
</label>
|
||||
<button type="submit">Apply</button>
|
||||
</form>
|
||||
<h3>Mopidy</h3>
|
||||
<form onSubmit={() => this.setMopidyConfig()}>
|
||||
<label>
|
||||
<span className="label">Host</span>
|
||||
<input onChange={ e => this.setState({ mopidy_host: e.target.value })} value={ this.state.mopidy_host } />
|
||||
</label>
|
||||
<label>
|
||||
<span className="label">Port</span>
|
||||
<input onChange={ e => this.setState({ mopidy_port: e.target.value })} value={ this.state.mopidy_port } />
|
||||
</label>
|
||||
<button type="submit">Apply</button>
|
||||
</form>
|
||||
|
||||
<SpotifyAuthenticationFrame />
|
||||
<h3>Spotify</h3>
|
||||
<form onSubmit={() => this.setSpotifyConfig()}>
|
||||
<label>
|
||||
<span className="label">Country</span>
|
||||
<input onChange={ e => this.setState({ spotify_country: e.target.value })} value={ this.state.spotify_country } />
|
||||
</label>
|
||||
<label>
|
||||
<span className="label">Locale</span>
|
||||
<input onChange={ e => this.setState({ spotify_locale: e.target.value })} value={ this.state.spotify_locale } />
|
||||
</label>
|
||||
<button type="submit">Apply</button>
|
||||
</form>
|
||||
|
||||
<ConfirmationButton content="Reset all settings" confirmingContent="Are you sure?" onConfirm={() => this.resetAllSettings()} />
|
||||
<SpotifyAuthenticationFrame />
|
||||
|
||||
<ConfirmationButton content="Reset all settings" confirmingContent="Are you sure?" onConfirm={() => this.resetAllSettings()} />
|
||||
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -10,5 +10,6 @@
|
||||
@import 'components/icon';
|
||||
@import 'components/sidebar';
|
||||
@import 'components/lists';
|
||||
@import 'components/grid';
|
||||
@import 'components/header';
|
||||
|
||||
|
||||
37
src/scss/components/_grid.scss
Executable file
37
src/scss/components/_grid.scss
Executable file
@ -0,0 +1,37 @@
|
||||
|
||||
.grid {
|
||||
|
||||
padding: 40px 20px;
|
||||
|
||||
.grid-item {
|
||||
width: 16%;
|
||||
margin: 0 2% 3%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
border-bottom: 0;
|
||||
|
||||
.thumbnail {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.name {
|
||||
@include one_line_text;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
@include one_line_text;
|
||||
padding-top: 2px;
|
||||
color: $secondary_grey;
|
||||
}
|
||||
|
||||
&:nth-child(5)::after {
|
||||
@include clear;
|
||||
}
|
||||
|
||||
&:hover{
|
||||
cursor: pointer;
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 8px 10px 8px 30px;
|
||||
padding: 9px 10px 9px 40px;
|
||||
border-top: 1px solid #EEEEEE;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
margin-bottom: -1px;
|
||||
@ -22,9 +22,7 @@
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
clear: both;
|
||||
display: block;
|
||||
@include clear;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
@ -57,12 +55,13 @@
|
||||
|
||||
.select-state {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
top: 12px;
|
||||
left: 15px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
&.playing {
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,10 +5,11 @@ aside{
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background: #333333;
|
||||
background: #111111;
|
||||
width: 200px;
|
||||
overflow: hidden;
|
||||
|
||||
box-shadow: inset -20px 0px 30px -20px rgba(0, 0, 0, 0.5);
|
||||
|
||||
.thumbnail {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -36,11 +37,11 @@ aside{
|
||||
|
||||
&.active {
|
||||
border-color: $turquoise;
|
||||
background: rgba( 0,0,0,0.1 );
|
||||
background: rgba( 0, 0, 0, 0.5 );
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba( 255,255,255,0.1 );
|
||||
background: rgba( 255, 255, 255, 0.1 );
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,13 +74,13 @@ aside{
|
||||
color: #FFFFFF;
|
||||
|
||||
.title {
|
||||
@include one_line_text
|
||||
@include one_line_text;
|
||||
}
|
||||
|
||||
.artist-list {
|
||||
opacity: 0.5;
|
||||
display: block;
|
||||
@include one_line_text
|
||||
@include one_line_text;
|
||||
|
||||
.artist a {
|
||||
color: inherit;
|
||||
|
||||
@ -27,4 +27,15 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
margin-bottom: 14px;
|
||||
padding-bottom: 4px;
|
||||
border-bottom: 1px solid #000000;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,15 @@
|
||||
|
||||
$turquoise: #08d58f;
|
||||
$secondary_grey: #888888;
|
||||
|
||||
@mixin one_line_text {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@mixin clear {
|
||||
content: '';
|
||||
clear: both;
|
||||
display: block;
|
||||
}
|
||||
Reference in New Issue
Block a user