Lint code and introduce BEM
This commit is contained in:
parent
d447143312
commit
055511e555
11 changed files with 361 additions and 78 deletions
15
.editorconfig
Normal file
15
.editorconfig
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Based on the React EditorConfig file. See:
|
||||||
|
# - http://editorconfig.org
|
||||||
|
# - https://github.com/facebook/react/blob/master/.editorconfig
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.{html,js,jsx,json,scss,css,yml}]
|
||||||
|
indent_size = 4
|
||||||
216
.eslintrc.js
Normal file
216
.eslintrc.js
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
var OFF = 0, WARN = 1, ERROR = 2;
|
||||||
|
|
||||||
|
module.exports = exports = {
|
||||||
|
"env": {
|
||||||
|
"es6": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"ecmaFeatures": {
|
||||||
|
// env=es6 doesn't include modules, which we are using
|
||||||
|
"modules": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
|
||||||
|
"rules": {
|
||||||
|
// Possible Errors (overrides from recommended set)
|
||||||
|
"no-extra-parens": ERROR,
|
||||||
|
"no-unexpected-multiline": ERROR,
|
||||||
|
// All JSDoc comments must be valid
|
||||||
|
"valid-jsdoc": [ ERROR, {
|
||||||
|
"requireReturn": false,
|
||||||
|
"requireReturnDescription": false,
|
||||||
|
"requireParamDescription": true,
|
||||||
|
"prefer": {
|
||||||
|
"return": "returns"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
|
||||||
|
// Best Practices
|
||||||
|
|
||||||
|
// Allowed a getter without setter, but all setters require getters
|
||||||
|
"accessor-pairs": [ ERROR, {
|
||||||
|
"getWithoutSet": false,
|
||||||
|
"setWithoutGet": true
|
||||||
|
}],
|
||||||
|
"block-scoped-var": WARN,
|
||||||
|
"consistent-return": ERROR,
|
||||||
|
"curly": ERROR,
|
||||||
|
"default-case": WARN,
|
||||||
|
// the dot goes with the property when doing multiline
|
||||||
|
"dot-location": [ WARN, "property" ],
|
||||||
|
"dot-notation": WARN,
|
||||||
|
"eqeqeq": [ ERROR, "smart" ],
|
||||||
|
"guard-for-in": WARN,
|
||||||
|
"no-alert": ERROR,
|
||||||
|
"no-caller": ERROR,
|
||||||
|
"no-case-declarations": WARN,
|
||||||
|
"no-div-regex": WARN,
|
||||||
|
"no-else-return": WARN,
|
||||||
|
"no-empty-label": WARN,
|
||||||
|
"no-empty-pattern": WARN,
|
||||||
|
"no-eq-null": WARN,
|
||||||
|
"no-eval": ERROR,
|
||||||
|
"no-extend-native": ERROR,
|
||||||
|
"no-extra-bind": WARN,
|
||||||
|
"no-floating-decimal": WARN,
|
||||||
|
"no-implicit-coercion": [ WARN, {
|
||||||
|
"boolean": true,
|
||||||
|
"number": true,
|
||||||
|
"string": true
|
||||||
|
}],
|
||||||
|
"no-implied-eval": ERROR,
|
||||||
|
"no-invalid-this": ERROR,
|
||||||
|
"no-iterator": ERROR,
|
||||||
|
"no-labels": WARN,
|
||||||
|
"no-lone-blocks": WARN,
|
||||||
|
"no-loop-func": ERROR,
|
||||||
|
"no-magic-numbers": WARN,
|
||||||
|
"no-multi-spaces": ERROR,
|
||||||
|
"no-multi-str": WARN,
|
||||||
|
"no-native-reassign": ERROR,
|
||||||
|
"no-new-func": ERROR,
|
||||||
|
"no-new-wrappers": ERROR,
|
||||||
|
"no-new": ERROR,
|
||||||
|
"no-octal-escape": ERROR,
|
||||||
|
"no-param-reassign": ERROR,
|
||||||
|
"no-process-env": WARN,
|
||||||
|
"no-proto": ERROR,
|
||||||
|
"no-redeclare": ERROR,
|
||||||
|
"no-return-assign": ERROR,
|
||||||
|
"no-script-url": ERROR,
|
||||||
|
"no-self-compare": ERROR,
|
||||||
|
"no-throw-literal": ERROR,
|
||||||
|
"no-unused-expressions": ERROR,
|
||||||
|
"no-useless-call": ERROR,
|
||||||
|
"no-useless-concat": ERROR,
|
||||||
|
"no-void": WARN,
|
||||||
|
// Produce warnings when something is commented as TODO or FIXME
|
||||||
|
"no-warning-comments": [ WARN, {
|
||||||
|
"terms": [ "TODO", "FIXME" ],
|
||||||
|
"location": "start"
|
||||||
|
}],
|
||||||
|
"no-with": WARN,
|
||||||
|
"radix": WARN,
|
||||||
|
"vars-on-top": ERROR,
|
||||||
|
// Enforces the style of wrapped functions
|
||||||
|
"wrap-iife": [ ERROR, "outside" ],
|
||||||
|
"yoda": ERROR,
|
||||||
|
|
||||||
|
// Strict Mode - for ES6, never use strict.
|
||||||
|
"strict": [ ERROR, "never" ],
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
"init-declarations": [ ERROR, "always" ],
|
||||||
|
"no-catch-shadow": WARN,
|
||||||
|
"no-delete-var": ERROR,
|
||||||
|
"no-label-var": ERROR,
|
||||||
|
"no-shadow-restricted-names": ERROR,
|
||||||
|
"no-shadow": WARN,
|
||||||
|
// We require all vars to be initialized (see init-declarations)
|
||||||
|
// If we NEED a var to be initialized to undefined, it needs to be explicit
|
||||||
|
"no-undef-init": OFF,
|
||||||
|
"no-undef": ERROR,
|
||||||
|
"no-undefined": OFF,
|
||||||
|
"no-unused-vars": WARN,
|
||||||
|
// Disallow hoisting - let & const don't allow hoisting anyhow
|
||||||
|
"no-use-before-define": ERROR,
|
||||||
|
|
||||||
|
// Node.js and CommonJS
|
||||||
|
"callback-return": [ WARN, [ "callback", "next" ]],
|
||||||
|
"global-require": ERROR,
|
||||||
|
"handle-callback-err": WARN,
|
||||||
|
"no-mixed-requires": WARN,
|
||||||
|
"no-new-require": ERROR,
|
||||||
|
// Use path.concat instead
|
||||||
|
"no-path-concat": ERROR,
|
||||||
|
"no-process-exit": ERROR,
|
||||||
|
"no-restricted-modules": OFF,
|
||||||
|
"no-sync": WARN,
|
||||||
|
|
||||||
|
// ECMAScript 6 support
|
||||||
|
"arrow-body-style": [ ERROR, "always" ],
|
||||||
|
"arrow-parens": [ ERROR, "always" ],
|
||||||
|
"arrow-spacing": [ ERROR, { "before": true, "after": true }],
|
||||||
|
"constructor-super": ERROR,
|
||||||
|
"generator-star-spacing": [ ERROR, "before" ],
|
||||||
|
"no-arrow-condition": ERROR,
|
||||||
|
"no-class-assign": ERROR,
|
||||||
|
"no-const-assign": ERROR,
|
||||||
|
"no-dupe-class-members": ERROR,
|
||||||
|
"no-this-before-super": ERROR,
|
||||||
|
"no-var": WARN,
|
||||||
|
"object-shorthand": [ WARN, "never" ],
|
||||||
|
"prefer-arrow-callback": WARN,
|
||||||
|
"prefer-spread": WARN,
|
||||||
|
"prefer-template": WARN,
|
||||||
|
"require-yield": ERROR,
|
||||||
|
|
||||||
|
// Stylistic - everything here is a warning because of style.
|
||||||
|
"array-bracket-spacing": [ WARN, "always" ],
|
||||||
|
"block-spacing": [ WARN, "always" ],
|
||||||
|
"brace-style": [ WARN, "1tbs", { "allowSingleLine": false } ],
|
||||||
|
"camelcase": WARN,
|
||||||
|
"comma-spacing": [ WARN, { "before": false, "after": true } ],
|
||||||
|
"comma-style": [ WARN, "last" ],
|
||||||
|
"computed-property-spacing": [ WARN, "never" ],
|
||||||
|
"consistent-this": [ WARN, "self" ],
|
||||||
|
"eol-last": WARN,
|
||||||
|
"func-names": WARN,
|
||||||
|
"func-style": [ WARN, "declaration" ],
|
||||||
|
"id-length": [ WARN, { "min": 2, "max": 32 } ],
|
||||||
|
"indent": [ WARN, 4 ],
|
||||||
|
"jsx-quotes": [ WARN, "prefer-double" ],
|
||||||
|
"linebreak-style": [ WARN, "unix" ],
|
||||||
|
"lines-around-comment": [ WARN, { "beforeBlockComment": true } ],
|
||||||
|
"max-depth": [ WARN, 8 ],
|
||||||
|
"max-len": [ WARN, 132 ],
|
||||||
|
"max-nested-callbacks": [ WARN, 8 ],
|
||||||
|
"max-params": [ WARN, 8 ],
|
||||||
|
"new-cap": WARN,
|
||||||
|
"new-parens": WARN,
|
||||||
|
"no-array-constructor": WARN,
|
||||||
|
"no-bitwise": OFF,
|
||||||
|
"no-continue": OFF,
|
||||||
|
"no-inline-comments": OFF,
|
||||||
|
"no-lonely-if": WARN,
|
||||||
|
"no-mixed-spaces-and-tabs": WARN,
|
||||||
|
"no-multiple-empty-lines": WARN,
|
||||||
|
"no-negated-condition": OFF,
|
||||||
|
"no-nested-ternary": WARN,
|
||||||
|
"no-new-object": WARN,
|
||||||
|
"no-plusplus": OFF,
|
||||||
|
"no-spaced-func": WARN,
|
||||||
|
"no-ternary": OFF,
|
||||||
|
"no-trailing-spaces": WARN,
|
||||||
|
"no-underscore-dangle": WARN,
|
||||||
|
"no-unneeded-ternary": WARN,
|
||||||
|
"object-curly-spacing": [ WARN, "always" ],
|
||||||
|
"one-var": OFF,
|
||||||
|
"operator-assignment": [ WARN, "never" ],
|
||||||
|
"operator-linebreak": [ WARN, "after" ],
|
||||||
|
"padded-blocks": [ WARN, "never" ],
|
||||||
|
"quote-props": [ WARN, "consistent-as-needed" ],
|
||||||
|
"quotes": [ WARN, "single" ],
|
||||||
|
"require-jsdoc": [ WARN, {
|
||||||
|
"require": {
|
||||||
|
"FunctionDeclaration": true,
|
||||||
|
"MethodDefinition": true,
|
||||||
|
"ClassDeclaration": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"semi-spacing": [ WARN, { "before": false, "after": true }],
|
||||||
|
"semi": [ ERROR, "always" ],
|
||||||
|
"sort-vars": OFF,
|
||||||
|
"space-after-keywords": [ WARN, "always" ],
|
||||||
|
"space-before-blocks": [ WARN, "always" ],
|
||||||
|
"space-before-function-paren": [ WARN, "never" ],
|
||||||
|
"space-before-keywords": [ WARN, "always" ],
|
||||||
|
"space-in-parens": [ WARN, "never" ],
|
||||||
|
"space-infix-ops": [ WARN, { "int32Hint": true } ],
|
||||||
|
"space-return-throw-case": ERROR,
|
||||||
|
"space-unary-ops": ERROR,
|
||||||
|
"spaced-comment": [ WARN, "always" ],
|
||||||
|
"wrap-regex": WARN
|
||||||
|
}
|
||||||
|
};
|
||||||
35
.stylelintrc.js
Normal file
35
.stylelintrc.js
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
rules: {
|
||||||
|
"at-rule-no-unknown": true,
|
||||||
|
"block-no-empty": true,
|
||||||
|
"color-no-invalid-hex": true,
|
||||||
|
"comment-no-empty": true,
|
||||||
|
"declaration-block-no-duplicate-properties": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
ignore: ["consecutive-duplicates-with-different-values"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"declaration-block-no-shorthand-property-overrides": true,
|
||||||
|
"font-family-no-duplicate-names": true,
|
||||||
|
"font-family-no-missing-generic-family-keyword": true,
|
||||||
|
"function-calc-no-unspaced-operator": true,
|
||||||
|
"function-linear-gradient-no-nonstandard-direction": true,
|
||||||
|
"keyframe-declaration-no-important": true,
|
||||||
|
"media-feature-name-no-unknown": true,
|
||||||
|
"no-descending-specificity": true,
|
||||||
|
"no-duplicate-at-import-rules": true,
|
||||||
|
"no-duplicate-selectors": true,
|
||||||
|
"no-empty-source": true,
|
||||||
|
"no-extra-semicolons": true,
|
||||||
|
"no-invalid-double-slash-comments": true,
|
||||||
|
"property-no-unknown": true,
|
||||||
|
"selector-pseudo-class-no-unknown": true,
|
||||||
|
"selector-pseudo-element-no-unknown": true,
|
||||||
|
"selector-type-no-unknown": true,
|
||||||
|
"string-no-newline": true,
|
||||||
|
"unit-no-unknown": true
|
||||||
|
}
|
||||||
|
};
|
||||||
14
README.md
14
README.md
|
|
@ -1,4 +1,10 @@
|
||||||
# Getting started
|
# BRÜTAL LEGEND
|
||||||
|
|
||||||
|
Progress visualisation of the quest to own a vinyl copy of all songs older than 1990 used in [Brütal Legend](https://en.wikipedia.org/wiki/Br%C3%BCtal_Legend), where possible.
|
||||||
|
|
||||||
|
Also a project for learning CSS Grid layout, React, Redux and Redux-sagas.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
Install dependencies and start webpack watcher.
|
Install dependencies and start webpack watcher.
|
||||||
|
|
||||||
|
|
@ -7,8 +13,6 @@ Install dependencies and start webpack watcher.
|
||||||
|
|
||||||
in another terminal, start a web server using python.
|
in another terminal, start a web server using python.
|
||||||
|
|
||||||
python2 -m 'SimpleHTTPServer' 1337
|
npm run serve
|
||||||
# or
|
|
||||||
python3 -m 'http.server' 1337
|
|
||||||
|
|
||||||
Visit site on http://localhost:1337
|
Visit site on http://localhost:10667
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
/* === Base === */
|
||||||
body {
|
body {
|
||||||
background-color: #111;
|
background-color: #111;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
font-size: large;
|
font-size: large;
|
||||||
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif;
|
||||||
padding: 5rem 10rem;
|
padding: 5rem 10rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,29 +68,33 @@ footer {
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
article {
|
/* === /Base === */
|
||||||
|
/* === Helpers === */
|
||||||
|
|
||||||
|
.blur {
|
||||||
|
filter: blur(25px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === /Helpers === */
|
||||||
|
/* === Albums === */
|
||||||
|
|
||||||
|
.album {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
figure {
|
.album:hover {
|
||||||
margin: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
article:hover,
|
|
||||||
article:focus {
|
|
||||||
background: #333;
|
background: #333;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
transform: scale(1.05, 1.05);
|
transform: scale(1.05, 1.05);
|
||||||
transition: transform .4s linear;
|
transition: transform .4s linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
article:hover img {
|
.album__cover {
|
||||||
transform: scale(1.5, 1.5) translateX(-1.5rem);
|
margin: 1rem;
|
||||||
transition: transform .2s linear;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
figure img {
|
.album__cover__media {
|
||||||
width: 10vw;
|
width: 10vw;
|
||||||
height: 10vw;
|
height: 10vw;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
|
@ -98,7 +103,24 @@ figure img {
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#selected-album > div {
|
.album__cover__media:hover {
|
||||||
|
transform: scale(1.5, 1.5) translateX(-1.5rem);
|
||||||
|
transition: transform .2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
.albums {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto auto;
|
||||||
|
grid-gap: 10px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === /Albums === */
|
||||||
|
/* === Selected album === */
|
||||||
|
|
||||||
|
.selected-album__inner {
|
||||||
display: grid;
|
display: grid;
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
transform: translateY(-3em);
|
transform: translateY(-3em);
|
||||||
|
|
@ -106,27 +128,13 @@ figure img {
|
||||||
grid-template-rows: 1fr 2fr;
|
grid-template-rows: 1fr 2fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#selected-album figure {
|
.selected-album__cover {
|
||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
grid-row: 1 / 3;
|
grid-row: 1 / 3;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#selected-album span {
|
.selected-album__cover__media {
|
||||||
align-self: end;
|
|
||||||
text-transform: uppercase;
|
|
||||||
padding: 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#selected-album p {
|
|
||||||
color: #fff;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
align-self: start;
|
|
||||||
padding: 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#selected-album img {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
|
|
@ -134,15 +142,22 @@ figure img {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 600px) {
|
.selected-album__summary {
|
||||||
#albums {
|
align-self: end;
|
||||||
display: grid;
|
text-transform: uppercase;
|
||||||
grid-template-columns: auto auto auto;
|
padding: 0 1rem;
|
||||||
grid-gap: 10px;
|
}
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
#selected-album {
|
.selected-album__description {
|
||||||
|
color: #fff;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
align-self: start;
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
.selected-album {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
|
@ -155,6 +170,4 @@ figure img {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.blur {
|
/* === /Selected album === */
|
||||||
filter: blur(25px);
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';
|
|
||||||
export const SET_SORT_KEY = 'SET_SORT_KEY';
|
|
||||||
export const LOAD_ALBUMS = 'LOAD_ALBUMS';
|
export const LOAD_ALBUMS = 'LOAD_ALBUMS';
|
||||||
export const LOAD_ALBUMS_OK = 'LOAD_ALBUMS_OK';
|
export const LOAD_ALBUMS_OK = 'LOAD_ALBUMS_OK';
|
||||||
export const SELECT_ALBUM = 'SELECT_ALBUM';
|
export const SELECT_ALBUM = 'SELECT_ALBUM';
|
||||||
|
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';
|
||||||
|
export const SET_SORT_KEY = 'SET_SORT_KEY';
|
||||||
export const UNSELECT_ALBUM = 'UNSELECT_ALBUM';
|
export const UNSELECT_ALBUM = 'UNSELECT_ALBUM';
|
||||||
|
|
||||||
export const setVisibilityFilter = filter => ({
|
export const setVisibilityFilter = filter => ({
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ export default class AlbumList extends Component {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const classNames = blurred ? 'blur' : ''
|
const classNames = blurred ? 'blur' : ''
|
||||||
return (
|
return (
|
||||||
<div id="albums" className={classNames}>
|
<div className={"albums " + classNames}>
|
||||||
{albums.map(album => (
|
{albums.map(album => (
|
||||||
<Album
|
<Album
|
||||||
key={album.id}
|
key={album.id}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||||
|
|
||||||
export default class Album extends Component {
|
export default class Album extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { album, handleOnClick } = this.props
|
const { album, handleOnClick } = this.props;
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
artist,
|
artist,
|
||||||
|
|
@ -15,15 +15,15 @@ export default class Album extends Component {
|
||||||
const imagePath = `assets/covers/${img}`;
|
const imagePath = `assets/covers/${img}`;
|
||||||
const song = songs.join(', ');
|
const song = songs.join(', ');
|
||||||
return (
|
return (
|
||||||
<article onClick={() => handleOnClick(album)}>
|
<article className="album" onClick={() => handleOnClick(album)}>
|
||||||
<figure>
|
<figure className="album__cover">
|
||||||
<img src={imagePath} alt="cover" />
|
<img src={imagePath} alt="cover" className="album__cover__media" />
|
||||||
</figure>
|
</figure>
|
||||||
<span>
|
<span>
|
||||||
#{id+1}: {artist} - {song}, från "{title}" ({year})<br />
|
#{id+1}: {artist} - {song}, från "{title}" ({year})<br />
|
||||||
<small>✔️ {purchased_on}</small>
|
<small>✔️ {purchased_on}</small>
|
||||||
</span>
|
</span>
|
||||||
</article>
|
</article>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,15 @@ export default class Modal extends Component {
|
||||||
const imagePath = `assets/covers/${img}`;
|
const imagePath = `assets/covers/${img}`;
|
||||||
const song = songs.join(', ');
|
const song = songs.join(', ');
|
||||||
return (
|
return (
|
||||||
<div id="selected-album" tabIndex="0" onClick={handleOnClick}>
|
<div className="selected-album" tabIndex="0" onClick={handleOnClick}>
|
||||||
<div>
|
<div className="selected-album__inner">
|
||||||
<figure>
|
<figure className="selected-album__cover">
|
||||||
<img src={imagePath} alt="cover" />
|
<img src={imagePath} alt="cover" className="selected-album__cover__media" />
|
||||||
</figure>
|
</figure>
|
||||||
<span>
|
<span className="selected-album__summary">
|
||||||
#{id+1}: {artist} - {song}, från "{title}" ({year})<br />
|
#{id+1}: {artist} - {song}, från "{title}" ({year})<br />
|
||||||
</span>
|
</span>
|
||||||
<p>
|
<p className="selected-album__description">
|
||||||
{description.split('\n\n').map(text => (
|
{description.split('\n\n').map(text => (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{text}
|
{text}
|
||||||
|
|
@ -37,6 +37,6 @@ export default class Modal extends Component {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import "babel-polyfill";
|
import 'babel-polyfill';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { createStore, applyMiddleware, compose } from 'redux';
|
import { createStore, applyMiddleware, compose } from 'redux';
|
||||||
|
|
@ -29,4 +29,4 @@ render(
|
||||||
document.getElementById('brutal')
|
document.getElementById('brutal')
|
||||||
);
|
);
|
||||||
|
|
||||||
store.dispatch({ type: 'LOAD_ALBUMS', payload: { source: '/json/albums.json' }});
|
store.dispatch({ type: 'LOAD_ALBUMS', payload: { source: 'json/albums.json' }});
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
import { put, takeEvery, all, call } from 'redux-saga/effects';
|
import { put, takeEvery, all, call } from 'redux-saga/effects';
|
||||||
import { LOAD_ALBUMS, albumsLoadedOk } from '../actions';
|
import { LOAD_ALBUMS, albumsLoadedOk } from '../actions';
|
||||||
|
|
||||||
export function* loadAlbumsAsync(action) {
|
function* watchLoadAlbumsAsync() {
|
||||||
try {
|
yield takeEvery(LOAD_ALBUMS, loadAlbumsAsync);
|
||||||
const { source } = action.payload;
|
|
||||||
const data = yield call(() => fetch(source)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => data), {}
|
|
||||||
);
|
|
||||||
yield put(albumsLoadedOk(data));
|
|
||||||
} catch (error) {
|
|
||||||
yield console.error(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* watchLoadAlbumsAsync() {
|
function* loadAlbumsAsync(action) {
|
||||||
yield takeEvery(LOAD_ALBUMS, loadAlbumsAsync);
|
try {
|
||||||
|
const { source } = action.payload;
|
||||||
|
const data = yield call(() => fetch(source)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => data), {}
|
||||||
|
);
|
||||||
|
yield put(albumsLoadedOk(data));
|
||||||
|
} catch (error) {
|
||||||
|
yield console.error(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function* () {
|
export default function* () {
|
||||||
yield all([
|
yield all([
|
||||||
watchLoadAlbumsAsync(),
|
watchLoadAlbumsAsync(),
|
||||||
])
|
]);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue