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.
|
||||
|
||||
|
|
@ -7,8 +13,6 @@ Install dependencies and start webpack watcher.
|
|||
|
||||
in another terminal, start a web server using python.
|
||||
|
||||
python2 -m 'SimpleHTTPServer' 1337
|
||||
# or
|
||||
python3 -m 'http.server' 1337
|
||||
npm run serve
|
||||
|
||||
Visit site on http://localhost:1337
|
||||
Visit site on http://localhost:10667
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/* === Base === */
|
||||
body {
|
||||
background-color: #111;
|
||||
color: #aaa;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -67,29 +68,33 @@ footer {
|
|||
right: 0;
|
||||
}
|
||||
|
||||
article {
|
||||
/* === /Base === */
|
||||
/* === Helpers === */
|
||||
|
||||
.blur {
|
||||
filter: blur(25px);
|
||||
}
|
||||
|
||||
/* === /Helpers === */
|
||||
/* === Albums === */
|
||||
|
||||
.album {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
article:hover,
|
||||
article:focus {
|
||||
.album:hover {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
transform: scale(1.05, 1.05);
|
||||
transition: transform .4s linear;
|
||||
}
|
||||
|
||||
article:hover img {
|
||||
transform: scale(1.5, 1.5) translateX(-1.5rem);
|
||||
transition: transform .2s linear;
|
||||
.album__cover {
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
figure img {
|
||||
.album__cover__media {
|
||||
width: 10vw;
|
||||
height: 10vw;
|
||||
padding: 5px;
|
||||
|
|
@ -98,7 +103,24 @@ figure img {
|
|||
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;
|
||||
max-width: 80%;
|
||||
transform: translateY(-3em);
|
||||
|
|
@ -106,27 +128,13 @@ figure img {
|
|||
grid-template-rows: 1fr 2fr;
|
||||
}
|
||||
|
||||
#selected-album figure {
|
||||
.selected-album__cover {
|
||||
grid-column: 1;
|
||||
grid-row: 1 / 3;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#selected-album span {
|
||||
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 {
|
||||
.selected-album__cover__media {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
|
|
@ -134,15 +142,22 @@ figure img {
|
|||
object-fit: cover;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
#albums {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto auto;
|
||||
grid-gap: 10px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.selected-album__summary {
|
||||
align-self: end;
|
||||
text-transform: uppercase;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
#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;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
|
@ -155,6 +170,4 @@ figure img {
|
|||
}
|
||||
}
|
||||
|
||||
.blur {
|
||||
filter: blur(25px);
|
||||
}
|
||||
/* === /Selected album === */
|
||||
|
|
@ -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_OK = 'LOAD_ALBUMS_OK';
|
||||
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 setVisibilityFilter = filter => ({
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export default class AlbumList extends Component {
|
|||
} = this.props;
|
||||
const classNames = blurred ? 'blur' : ''
|
||||
return (
|
||||
<div id="albums" className={classNames}>
|
||||
<div className={"albums " + classNames}>
|
||||
{albums.map(album => (
|
||||
<Album
|
||||
key={album.id}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
|||
|
||||
export default class Album extends Component {
|
||||
render() {
|
||||
const { album, handleOnClick } = this.props
|
||||
const { album, handleOnClick } = this.props;
|
||||
const {
|
||||
id,
|
||||
artist,
|
||||
|
|
@ -15,15 +15,15 @@ export default class Album extends Component {
|
|||
const imagePath = `assets/covers/${img}`;
|
||||
const song = songs.join(', ');
|
||||
return (
|
||||
<article onClick={() => handleOnClick(album)}>
|
||||
<figure>
|
||||
<img src={imagePath} alt="cover" />
|
||||
<article className="album" onClick={() => handleOnClick(album)}>
|
||||
<figure className="album__cover">
|
||||
<img src={imagePath} alt="cover" className="album__cover__media" />
|
||||
</figure>
|
||||
<span>
|
||||
#{id+1}: {artist} - {song}, från "{title}" ({year})<br />
|
||||
<small>✔️ {purchased_on}</small>
|
||||
</span>
|
||||
</article>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,15 +18,15 @@ export default class Modal extends Component {
|
|||
const imagePath = `assets/covers/${img}`;
|
||||
const song = songs.join(', ');
|
||||
return (
|
||||
<div id="selected-album" tabIndex="0" onClick={handleOnClick}>
|
||||
<div>
|
||||
<figure>
|
||||
<img src={imagePath} alt="cover" />
|
||||
<div className="selected-album" tabIndex="0" onClick={handleOnClick}>
|
||||
<div className="selected-album__inner">
|
||||
<figure className="selected-album__cover">
|
||||
<img src={imagePath} alt="cover" className="selected-album__cover__media" />
|
||||
</figure>
|
||||
<span>
|
||||
<span className="selected-album__summary">
|
||||
#{id+1}: {artist} - {song}, från "{title}" ({year})<br />
|
||||
</span>
|
||||
<p>
|
||||
<p className="selected-album__description">
|
||||
{description.split('\n\n').map(text => (
|
||||
<React.Fragment>
|
||||
{text}
|
||||
|
|
@ -37,6 +37,6 @@ export default class Modal extends Component {
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import "babel-polyfill";
|
||||
import 'babel-polyfill';
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { createStore, applyMiddleware, compose } from 'redux';
|
||||
|
|
@ -29,4 +29,4 @@ render(
|
|||
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 { LOAD_ALBUMS, albumsLoadedOk } from '../actions';
|
||||
|
||||
export function* loadAlbumsAsync(action) {
|
||||
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);
|
||||
}
|
||||
function* watchLoadAlbumsAsync() {
|
||||
yield takeEvery(LOAD_ALBUMS, loadAlbumsAsync);
|
||||
}
|
||||
|
||||
export function* watchLoadAlbumsAsync() {
|
||||
yield takeEvery(LOAD_ALBUMS, loadAlbumsAsync);
|
||||
function* loadAlbumsAsync(action) {
|
||||
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* () {
|
||||
yield all([
|
||||
watchLoadAlbumsAsync(),
|
||||
])
|
||||
yield all([
|
||||
watchLoadAlbumsAsync(),
|
||||
]);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue