Skip to content
This repository has been archived by the owner on Jan 27, 2019. It is now read-only.

Add JSS example #23

Merged
merged 3 commits into from
Sep 21, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion examples/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"extends": "airbnb",

"rules": {
"react/prop-types": 0
},
"env": {
"browser": true,
"mocha": true
Expand Down
19 changes: 19 additions & 0 deletions examples/jss/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "jss-example",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
"scripts": {
"start": "../node_modules/.bin/webpack-dev-server --config ../webpack.base.babel.js --content-base build"
},
"author": "Max Stoiber",
"license": "MIT",
"devDependencies": {
"css-loader": "0.25.0",
"jss": "5.5.4",
"jss-preset-default": "0.4.0",
"react-jss": "3.0.1",
"style-loader": "0.13.1"
},
"dependencies": {}
}
29 changes: 29 additions & 0 deletions examples/jss/src/components/app/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import useSheet from 'react-jss';

import Tweet from '../tweet';
import data from '../../../../shared/data/755481795206971392.json';

import 'normalize.css';

const styles = {
// Local styles
container: {
margin: '0 auto',
width: '100%',
'@media screen and (min-width: 360px)': {
maxWidth: '400px',
},
'@media screen and (min-width: 600px)': {
maxWidth: '600px',
},
},
};

const App = (props) => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a bit nicer notation (but really stylistic preference)

const App = ({sheet: {classes}}) => (
...

 <div className={classes.container}>

<div className={props.sheet.classes.container}>
<Tweet data={data} />
</div>
);

export default useSheet(App, styles);
1 change: 1 addition & 0 deletions examples/jss/src/components/app/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './app';
39 changes: 39 additions & 0 deletions examples/jss/src/components/content/content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { PropTypes } from 'react';
import useSheet from 'react-jss';

const styles = {
text: {
fontSize: '1.25rem',
fontWeight: '300',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use a number here

lineHeight: '1.5em',
margin: '0',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use a number here

padding: '.65625rem 0 .98438rem',
},
media: {
borderRadius: '.35rem',
border: '1px solid #e1e8ed',
color: '#1da1f2',
display: 'block',
margin: '.65625rem 0 1.3125rem',
},
image: {
display: 'block',
maxWidth: '100%',
},
};

const Content = ({ text, media, sheet }) => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, looks like much less repition to me if you spread the sheet and just pick classes ... you rarely need the sheet ref:

+const Content = ({ text, media, sheet: {classes} }) => (

<div>
<p className={sheet.classes.text} dangerouslySetInnerHTML={{ __html: text }} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if I need to comment on this, because not related to jss, but looks like something can be done differently ...

<a className={sheet.classes.media} href={media.expanded_url}>
<img className={sheet.classes.image} src={media.media_url_https} alt="" />
</a>
</div>
);

Content.propTypes = {
media: PropTypes.object,
text: PropTypes.string,
};

export default useSheet(Content, styles);
1 change: 1 addition & 0 deletions examples/jss/src/components/content/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './content';
136 changes: 136 additions & 0 deletions examples/jss/src/components/footer/footer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import React, { Component, PropTypes } from 'react';
import useSheet from 'react-jss';

import ReplyIcon from '../../../../shared/assets/reply.svg';
import RetweetIcon from '../../../../shared/assets/retweet.svg';
import LikeIcon from '../../../../shared/assets/like.svg';
import MoreIcon from '../../../../shared/assets/more.svg';

const styles = {
'@keyframes liked': {
'50%': {
transform: 'scale(1.2)',
},
'100%': {
tranform: 'scale(1)',
},
},
date: {
paddingBottom: '.98438rem',
color: '#8899a6',
},
counters: {
borderTop: '1px solid #e1e8ed',
padding: '.98438rem 0',
textTransform: 'uppercase',
},
value: {
fontWeight: '700',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be a number

},
label: {
color: '#8899a6',
fontSize: '.85rem',
},
favorite: {
display: 'inline-block',
marginLeft: '1.96875rem',
},
actions: {
alignItems: 'center',
borderBottom: '1px solid #e1e8ed',
borderTop: '1px solid #e1e8ed',
color: '#8899a6',
display: 'flex',
fontSize: '1.5rem',
height: '3.28125rem',
width: '100%',
},
icon: {
display: 'flex',
flexGrow: '1',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be a number

justifyContent: 'center',
textAlign: 'center',
},
button: {
display: 'flex',
flexGrow: '1',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be a number

justifyContent: 'center',
textAlign: 'center',
background: 'none',
border: 'none',
color: 'inherit',
cursor: 'pointer',
fontSize: 'inherit',
outline: 'none',
},
liked: {
animationName: 'liked',
animationDuration: '.25s',
color: '#e81c4f',
},
};

class Footer extends Component {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not to use decorator

@useSheet(styles)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of decorators since they aren't standardized yet and rely on a legacy babel transform. 😁 See this dicussion: facebook/create-react-app#107

Specifically this part:

Decorators are currently at "stage 1" in the ecmascript-standardization process, and it isn't until "stage 3" that all the syntax and semantics are complete, so I think it makes sense to wait.


constructor(props) {
super(props);

this.state = {
liked: false,
};

this.handleClick = this.handleClick.bind(this);
}

handleClick() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not to use this syntax so you don't need to bind:

handleClick = () => {}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, but need to update all examples. Will add to #24!

this.setState({
liked: !this.state.liked,
});
}

render() {
const { createdAt, favoriteCount, retweetCount, sheet } = this.props;
const { liked } = this.state;

return (
<div>
<div className={sheet.classes.date}>{createdAt}</div>
<div className={sheet.classes.counters}>
<span>
<span className={sheet.classes.value}>{retweetCount}</span>
<span className={sheet.classes.label}> Retweets</span>
</span>
<span className={sheet.classes.favorite}>
<span className={sheet.classes.value}>
{liked ? favoriteCount + 1 : favoriteCount}
</span>
<span className={sheet.classes.label}> Likes</span>
</span>
</div>
<div className={sheet.classes.actions}>
<div className={sheet.classes.icon}>
<ReplyIcon />
</div>
<div className={sheet.classes.icon}>
<RetweetIcon />
</div>
<button className={sheet.classes.button} onClick={this.handleClick}>
<LikeIcon className={liked && sheet.classes.liked} />
</button>
<div className={sheet.classes.icon}>
<MoreIcon />
</div>
</div>
</div>
);
}

}

Footer.propTypes = {
createdAt: PropTypes.string,
favoriteCount: PropTypes.number,
retweetCount: PropTypes.number,
};

export default useSheet(Footer, styles);
1 change: 1 addition & 0 deletions examples/jss/src/components/footer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './footer';
65 changes: 65 additions & 0 deletions examples/jss/src/components/header/header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { PropTypes } from 'react';
import useSheet from 'react-jss';

const styles = {
header: {
display: 'flex',
padding: '1rem 0 .65625rem',
},
profile: {
flex: '1 0 0',
margin: '0 .3rem',
},
image: {
borderRadius: '.35rem',
display: 'block',
width: '100%',
},
user: {
flex: '7 0 0',
margin: '0 .3rem',
},
url: {
display: 'inline-block',
marginTop: '-.15rem',
},
name: {
color: '#292f33',
fontWeight: '700',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be a number

'&:hover': {
textDecoration: 'underline',
},
},
screenName: {
color: '#8899a6',
'&:before': {
content: '"\\a"',
whiteSpace: 'pre',
},
},
};

const Header = ({ name, profileImageUrl, screenName, url, sheet }) => (
<div className={sheet.classes.header}>
<div className={sheet.classes.profile}>
<a href={url}>
<img className={sheet.classes.image} src={profileImageUrl} alt={name} />
</a>
</div>
<div className={sheet.classes.user}>
<a className={sheet.classes.url} href={url}>
<span className={sheet.classes.name}>{name}</span>
<span className={sheet.classes.screenName}>@{screenName}</span>
</a>
</div>
</div>
);

Header.propTypes = {
name: PropTypes.string,
profileImageUrl: PropTypes.string,
screenName: PropTypes.string,
url: PropTypes.string,
};

export default useSheet(Header, styles);
1 change: 1 addition & 0 deletions examples/jss/src/components/header/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './header';
1 change: 1 addition & 0 deletions examples/jss/src/components/tweet/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './tweet';
39 changes: 39 additions & 0 deletions examples/jss/src/components/tweet/tweet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { PropTypes } from 'react';
import useSheet from 'react-jss';

import Header from '../header';
import Content from '../content';
import Footer from '../footer';
import { transform } from '../../../../shared/utils/text';

const styles = {
container: {
padding: '0 .6rem',
},
};

const Tweet = ({ data, sheet }) => (
<div className={sheet.classes.container}>
<Header
name={data.user.name}
profileImageUrl={data.user.profile_image_url_https}
screenName={data.user.screen_name}
url={data.user.url}
/>
<Content
media={data.entities.media[0]}
text={transform(data)}
/>
<Footer
createdAt={data.created_at}
favoriteCount={data.favorite_count}
retweetCount={data.retweet_count}
/>
</div>
);

Tweet.propTypes = {
data: PropTypes.object,
};

export default useSheet(Tweet, styles);
41 changes: 41 additions & 0 deletions examples/jss/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import { render } from 'react-dom';
import jss from 'jss';
import preset from 'jss-preset-default';

jss.setup(preset());

const globalStyles = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would probably put this global styles and its rendering into a separate module.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so that this file has a focus on app setup/initialization.

// Global styles
html: {
color: '#292f33',
fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif',
fontSize: '14px',
lineHeight: '1.3125',
},
a: {
textDecoration: 'none',
color: '#1da1f2',
},
svg: {
fill: 'currentColor',
height: '1.25em',
},
'@media screen and (min-width: 360px)': {
Copy link
Contributor

@kof kof Sep 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to show the beauty of js, you could put all media queries into a separate file and then use them like this:

...

[screenSizes.xs]: {
}
...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, would need to update for all CSS-in-JS examples – will add to #24!

html: {
fontSize: '15px',
},
},
'@media screen and (min-width: 600px)': {
html: {
fontSize: '16px',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jss-default-unit allows us to have numeric values here as well, px is added automatically.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are 2 more cases of this in this sheet.

},
},
};

// Attach global styles
jss.createStyleSheet(globalStyles, { named: false }).attach();

import App from './components/app';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imports should be on top, because they are hoisted anyways ... this may lead to a wrong understanding of execution order.


render(<App />, document.getElementById('example-root'));