diff --git a/.editorconfig b/.editorconfig
index 9bb7984..521010b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -7,6 +7,6 @@ charset = utf-8
end_of_line = lf
insert_final_newline = true
-[*.{js,json,html,less}]
+[*.{js,json,html,scss}]
indent_style = space
indent_size = 2
diff --git a/index.html b/index.html
index d30f63f..9bd7a88 100644
--- a/index.html
+++ b/index.html
@@ -5,15 +5,6 @@
+ return
{channels}
;
@@ -33,19 +32,9 @@ export default class FeedChannels extends Component {
_renderRightElement(channel) {
if (channel.isLoading) {
- return
;
+ return
;
}
- return channel.isEnabled ?
check : null;
- }
-
- getStyles() {
- return {
-
- channel: {
- fontSize: 14,
- },
-
- };
+ return channel.isEnabled ?
: null;
}
}
diff --git a/src/components/feed/feed-playlist.js b/src/components/feed/feed-playlist.js
index 2384300..ce3e3e6 100644
--- a/src/components/feed/feed-playlist.js
+++ b/src/components/feed/feed-playlist.js
@@ -11,13 +11,13 @@ export default class FeedPlaylist extends Component {
onToggleShuffle: PropTypes.func.isRequired,
tracks: PropTypes.array.isRequired,
currentTrackId: PropTypes.string,
- };
+ }
static defaultProps = {
compact: false,
currentTrackId: null,
isShuffle: false,
- };
+ }
render() {
const {tracks} = this.props;
diff --git a/src/components/feed/feed.scss b/src/components/feed/feed.scss
new file mode 100644
index 0000000..07d067c
--- /dev/null
+++ b/src/components/feed/feed.scss
@@ -0,0 +1,13 @@
+
+.channels {
+ &Item {
+ font-size: 14px;
+
+ &Image {
+ width: 32px;
+ height: 32px;
+ }
+ }
+}
+
+
diff --git a/src/components/ui/avatar.js b/src/components/ui/avatar.js
deleted file mode 100644
index 84b68af..0000000
--- a/src/components/ui/avatar.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import React, {Component} from 'react';
-
-export default class Avatar extends Component {
- static propTypes = {
- url: React.PropTypes.string.isRequired,
- size: React.PropTypes.number,
- };
-
- static defaultProps = {
- size: 40,
- };
-
- render() {
- return
;
- }
-
- getStyle() {
- const {url, style, size} = this.props;
-
- return {
- background: `url(${url}) center center`,
- backgroundSize: 'cover',
- display: 'inline-block',
- width: size,
- height: size,
- borderRadius: '50%',
- ...style,
- };
- }
-}
diff --git a/src/components/ui/avatar/avatar.js b/src/components/ui/avatar/avatar.js
new file mode 100644
index 0000000..9b489d9
--- /dev/null
+++ b/src/components/ui/avatar/avatar.js
@@ -0,0 +1,15 @@
+import React, {Component} from 'react';
+import cn from 'classnames';
+import styles from './avatar.scss';
+
+export default class Avatar extends Component {
+ static propTypes = {
+ url: React.PropTypes.string.isRequired,
+ }
+
+ render() {
+ return
;
+ }
+}
diff --git a/src/components/ui/avatar/avatar.scss b/src/components/ui/avatar/avatar.scss
new file mode 100644
index 0000000..1d89f59
--- /dev/null
+++ b/src/components/ui/avatar/avatar.scss
@@ -0,0 +1,8 @@
+.avatar {
+ display: inline-block;
+ width: 40px;
+ height: 40px;
+ background-size: cover;
+ background-position: center;
+ border-radius: 50%;
+}
diff --git a/src/components/ui/button/button.scss b/src/components/ui/button/button.scss
new file mode 100644
index 0000000..0429ede
--- /dev/null
+++ b/src/components/ui/button/button.scss
@@ -0,0 +1,31 @@
+.flat {
+ height: 36px;
+ padding: 0 24px;
+ line-height: 16px;
+ font-size: 16px;
+ text-transform: uppercase;
+ border: none;
+ background: none;
+ cursor: pointer;
+
+ &:hover {
+ background: rgba(0,0,0,.1);
+ }
+}
+
+.icon {
+ display: inline-block;
+ position: relative;
+ background-color: transparent;
+ border: none;
+ outline: none;
+ margin: 0;
+ padding: 0;
+ cursor: pointer;
+ border-radius: 50%;
+
+ &:hover {
+ background: rgba(0,0,0,.1);
+ }
+
+}
diff --git a/src/components/ui/button/flat-button.js b/src/components/ui/button/flat-button.js
new file mode 100644
index 0000000..875e774
--- /dev/null
+++ b/src/components/ui/button/flat-button.js
@@ -0,0 +1,15 @@
+import React, {Component, PropTypes} from 'react';
+import cn from 'classnames';
+import styles from './button.scss';
+
+export default class FlatButton extends Component {
+ static propTypes = {
+ label: PropTypes.node.isRequired,
+ }
+
+ render() {
+ return
;
+ }
+}
diff --git a/src/components/ui/button/icon-button.js b/src/components/ui/button/icon-button.js
new file mode 100644
index 0000000..a1f2b81
--- /dev/null
+++ b/src/components/ui/button/icon-button.js
@@ -0,0 +1,23 @@
+import React, {Component, PropTypes} from 'react';
+import cn from 'classnames';
+import Icon from '../icon/icon';
+import styles from './button.scss';
+
+export default class IconButton extends Component {
+ static propTypes = {
+ glyph: PropTypes.string.isRequired,
+ onClick: PropTypes.func.isRequired,
+ size: PropTypes.number,
+ boxSize: PropTypes.number,
+ }
+
+ render() {
+ const {size, boxSize, glyph, onClick, className} = this.props;
+ return
;
+ }
+}
diff --git a/src/components/ui/flat-button.js b/src/components/ui/flat-button.js
deleted file mode 100644
index a4bd559..0000000
--- a/src/components/ui/flat-button.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React, {Component, PropTypes} from 'react';
-import Radium from 'radium';
-
-@Radium
-export default class FlatButton extends Component {
- static propTypes = {
- label: PropTypes.node.isRequired,
- };
-
- render() {
- return
;
- }
-
- getStyles() {
- return {
- height: 36,
- padding: '0 24px',
- lineHeight: '16px',
- fontSize: '16px',
- textTransform: 'uppercase',
- border: 'none',
- background: 'none',
- cursor: 'pointer',
-
- ':hover': {
- background: 'rgba(0,0,0,.1)',
- },
-
- ...this.props.style,
- };
- }
-}
diff --git a/src/components/ui/icon-button.js b/src/components/ui/icon-button.js
deleted file mode 100644
index 4438a31..0000000
--- a/src/components/ui/icon-button.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import Radium from 'radium';
-import Color from 'color';
-import React, {Component, PropTypes} from 'react';
-import Icon from './icon';
-
-@Radium
-export default class IconButton extends Component {
-
- static propTypes = {
- children: PropTypes.string.isRequired,
- onClick: PropTypes.func.isRequired,
- size: PropTypes.number,
- boxSize: PropTypes.number,
- }
-
- render() {
- const {size, boxSize, children, onClick} = this.props;
- return
;
- }
-
- _getIconColor() {
- const style = this.props.style || {color: '#fff'};
- return style.color ? style.color : '#fff';
- }
-
- getStyle() {
- return {
- display: 'inline-block',
- position: 'relative',
- backgroundColor: 'transparent',
- border: 'none',
- outline: 'none',
- margin: 0,
- padding: 0,
- cursor: 'pointer',
- borderRadius: '50%',
-
- ':hover': {
- backgroundColor: Color(this._getIconColor()).alpha(.1).rgbString(),
- },
-
- ...this.props.style,
- };
- }
-}
diff --git a/src/components/ui/icon.js b/src/components/ui/icon.js
deleted file mode 100644
index 1670864..0000000
--- a/src/components/ui/icon.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React, {Component, PropTypes} from 'react';
-
-export default class Icon extends Component {
- static propTypes = {
- children: PropTypes.string.isRequired,
- size: PropTypes.number,
- boxSize: PropTypes.number,
- };
-
- static defaultProps = {
- size: 24,
- boxSize: null,
- };
-
- render() {
- return
- {this.props.children}
- ;
- }
-
- getStyle() {
- const {size, boxSize, style} = this.props;
-
- return {
- display: 'inline-block',
- position: 'relative',
- width: (boxSize || size),
- height: (boxSize || size),
- lineHeight: (boxSize || size) / size,
- textAlign: 'center',
- fontSize: size,
- color: '#fff',
- verticalAlign: 'middle',
- ...style,
- };
- }
-}
diff --git a/src/components/ui/icon/icon.js b/src/components/ui/icon/icon.js
new file mode 100644
index 0000000..f1e9668
--- /dev/null
+++ b/src/components/ui/icon/icon.js
@@ -0,0 +1,32 @@
+import React, {Component, PropTypes} from 'react';
+import cn from 'classnames';
+import styles from './icon.scss';
+
+export default class Icon extends Component {
+ static propTypes = {
+ glyph: PropTypes.string.isRequired,
+ size: PropTypes.number,
+ boxSize: PropTypes.number,
+ };
+
+ static defaultProps = {
+ size: 24,
+ boxSize: null,
+ };
+
+ render() {
+ const {size, boxSize, glyph, className} = this.props;
+
+ return
+ {glyph}
+ ;
+ }
+}
diff --git a/src/components/ui/icon/icon.scss b/src/components/ui/icon/icon.scss
new file mode 100644
index 0000000..b7ce322
--- /dev/null
+++ b/src/components/ui/icon/icon.scss
@@ -0,0 +1,6 @@
+.icon {
+ display: inline-block;
+ position: relative;
+ text-align: center;
+ vertical-align: middle;
+}
diff --git a/src/components/ui/index.js b/src/components/ui/index.js
index f67cff2..386f727 100644
--- a/src/components/ui/index.js
+++ b/src/components/ui/index.js
@@ -1,11 +1,11 @@
export default {
- Avatar: require('./avatar'),
- FlatButton: require('./flat-button'),
- Icon: require('./icon'),
- IconButton: require('./icon-button'),
- LazyList: require('./lazylist'),
- List: require('./list'),
- ListItem: require('./list-item'),
- ListLabel: require('./list-label'),
- Loader: require('./loader'),
+ Avatar: require('./avatar/avatar'),
+ Icon: require('./icon/icon'),
+ FlatButton: require('./button/flat-button'),
+ IconButton: require('./button/icon-button'),
+ LazyList: require('./list/lazy-list'),
+ ListLabel: require('./list/list-label'),
+ List: require('./list/list'),
+ ListItem: require('./list/list-item'),
+ Loader: require('./loader/loader'),
};
diff --git a/src/components/ui/list-item.js b/src/components/ui/list-item.js
deleted file mode 100644
index f6d2414..0000000
--- a/src/components/ui/list-item.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import React, {Component, PropTypes} from 'react';
-import Radium from 'radium';
-import {colors} from '../../utils/styles';
-
-@Radium
-export default class ListItem extends Component {
- static propTypes = {
- primaryText: PropTypes.node.isRequired,
- secondaryText: PropTypes.node,
- leftElement: PropTypes.node,
- leftElementHeight: PropTypes.number,
- rightElement: PropTypes.node,
- rightElementHeight: PropTypes.number,
- onClick: PropTypes.func,
- style: PropTypes.object,
- };
-
- static defaultProps = {
- secondaryText: null,
- leftElement: null,
- leftElementHeight: 40,
- rightElement: null,
- rightElementHeight: 40,
- height: 56,
- onClick: null,
- style: null,
- };
-
- render() {
- const styles = this.getStyles();
- const {leftElement, rightElement} = this.props;
-
- return
- {this.renderElement(leftElement, styles.leftElement)}
- {this.props.primaryText}
- {this.props.secondaryText}
- {this.renderElement(rightElement, styles.rightElement)}
- ;
- }
-
- renderElement(element, elementStyle) {
- if (element === null) {
- return null;
- }
-
- const style = Object.assign({}, elementStyle, element.props.style);
-
- return React.cloneElement(
- element,
- {...element.props, style}
- );
- }
-
- _click(event) {
- if (this.props.onClick) {
- this.props.onClick(event);
- }
- }
-
- getStyles() {
- const height = this.props.height;
- const paddingVert = height/2 - (this.props.secondaryText ? 16 : 8);
- const paddingRight = this.props.rightIcon === null ? 16 : 56;
- const paddingLeft = this.props.leftElement === null ? 16 : 72;
- const isClickable = typeof(this.props.onClick) === 'function';
- const ellipsis = {
- whiteSpace: 'nowrap',
- textOverflow: 'ellipsis',
- overflow: 'hidden',
- };
-
- return {
- container: {
- position: 'relative',
- height,
- boxSizing: 'border-box',
- padding: `${paddingVert}px ${paddingRight}px ${paddingVert}px ${paddingLeft}px`,
- lineHeight: 1.1,
- fontSize: 16,
- cursor: isClickable ? 'pointer' : null,
- ':hover': isClickable ? {
- backgroundColor: 'rgba(0,0,0,.05)',
- } : null,
- ...this.props.style,
- },
-
- primaryText: {
- display: 'inline-block',
- width: '100%',
- ...ellipsis,
- },
-
- secondaryText: {
- display: 'inline-block',
- width: '100%',
- fontSize: 14,
- color: colors.secondaryText,
- ...ellipsis,
- },
-
- leftElement: {
- position: 'absolute',
- left: 16,
- top: this._getSideElementTop(height, this.props.leftElementHeight),
- color: colors.primaryText,
- },
-
- rightElement: {
- position: 'absolute',
- right: 16,
- top: this._getSideElementTop(height, this.props.rightElementHeight),
- color: colors.primaryText,
- },
- };
- }
-
- _getSideElementTop(itemHeight, elementHeight) {
- return ((itemHeight - elementHeight) / 2) + 'px';
- }
-}
diff --git a/src/components/ui/list-label.js b/src/components/ui/list-label.js
deleted file mode 100644
index b9e0aee..0000000
--- a/src/components/ui/list-label.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import React, {Component} from 'react';
-import {colors} from '../../utils/styles';
-
-export default class ListLabel extends Component {
- static propTypes = {
- text: React.PropTypes.oneOfType([
- React.PropTypes.string,
- React.PropTypes.element,
- ]).isRequired,
- rightElement: React.PropTypes.element,
- };
-
- static defaultProps = {
- rightElement: null,
- };
-
- render() {
- const styles = this.getStyles();
-
- return
- {this.props.text}
- {this.renderElement(this.props.rightElement, styles.rightElement)}
-
;
- }
-
- renderElement(element, elementStyle) {
- if (element === null) {
- return null;
- }
-
- const style = Object.assign({}, elementStyle, element.props.style);
-
- return React.cloneElement(
- element,
- {...element.props, style}
- );
- }
-
- getStyles() {
-
- const ellipsis = {
- whiteSpace: 'nowrap',
- textOverflow: 'ellipsis',
- overflow: 'hidden',
- };
-
- return {
-
- container: {
- position: 'relative',
- boxSizing: 'border-box',
- padding: '0 16px',
- height: '48px',
- },
-
- text: {
- display: 'inline-block',
- width: '100%',
- fontSize: '14px',
- lineHeight: '48px',
- color: colors.secondaryText,
- ...ellipsis,
- },
-
- rightElement: {
- position: 'absolute',
- right: '16px',
- top: '12px',
- color: colors.secondaryText,
- },
-
- };
- }
-}
diff --git a/src/components/ui/list.js b/src/components/ui/list.js
deleted file mode 100644
index e262057..0000000
--- a/src/components/ui/list.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React, {Component, PropTypes} from 'react';
-
-export default class List extends Component {
- static propTypes = {
- children: PropTypes.node.isRequired,
- };
-
- render() {
- return
;
- }
-
- getStyle() {
- return {
- listStyleType: 'none',
- margin: 0,
- padding: 0,
- ...this.props.style,
- };
- }
-}
diff --git a/src/components/ui/lazylist.js b/src/components/ui/list/lazy-list.js
similarity index 89%
rename from src/components/ui/lazylist.js
rename to src/components/ui/list/lazy-list.js
index cc78d85..06d6757 100644
--- a/src/components/ui/lazylist.js
+++ b/src/components/ui/list/lazy-list.js
@@ -1,6 +1,8 @@
import React, {Component, PropTypes} from 'react';
import ReactDOM from 'react-dom';
-import {nodeOffset, throttle} from '../../utils/common';
+import {nodeOffset, throttle} from '../../../utils/common';
+import cn from 'classnames';
+import styles from './list.scss';
export default class LazyList extends Component {
@@ -29,9 +31,10 @@ export default class LazyList extends Component {
render() {
const {items, renderItem} = this.props;
const {firstIndex, lastIndex} = this.state;
- const styles = this.getStyles();
+ const offsetStyles = this._getOffsetStyles();
+ const className = cn(styles.list, this.props.className);
- return