Skip to content

Commit 738a654

Browse files
author
Alex Alexeev
committed
MUI setup with react-jss
1 parent d19d998 commit 738a654

File tree

9 files changed

+501
-26
lines changed

9 files changed

+501
-26
lines changed

components/City.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
import { createFragmentContainer, graphql } from 'react-relay';
2+
import Typography from 'material-ui/Typography';
3+
import List, { ListItem, ListItemIcon, ListItemText } from 'material-ui/List';
4+
5+
const styles = {
6+
subItem: {
7+
marginLeft: '10px'
8+
}
9+
};
210

311
const City = ({ data }) => {
412
if (!data) return null;
513
return (
6-
<ul>
7-
<li>
14+
<List>
15+
<ListItem>
816
City: {data.name}
9-
</li>
10-
<li>
17+
</ListItem>
18+
<ListItem>
1119
Slug: {data.slug}
12-
</li>
13-
</ul>
20+
</ListItem>
21+
</List>
1422
);
1523
};
1624

@@ -21,5 +29,5 @@ export default createFragmentContainer(
2129
name
2230
slug
2331
}
24-
`,
32+
`
2533
);

components/Location.js

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
import { createFragmentContainer, graphql } from 'react-relay';
2+
import Card, { CardActions, CardContent } from 'material-ui/Card';
3+
import Typography from 'material-ui/Typography';
4+
import Button from 'material-ui/Button';
25
import City from './City';
36

47
const Location = ({ data }) => {
58
return (
6-
<li key={data.locationId}>
7-
{data.name}
8-
<City data={data.city} />
9-
</li>
9+
<Card key={data.locationId}>
10+
<CardContent>
11+
<Typography type="headline" component="h2">
12+
{data.name}
13+
</Typography>
14+
15+
<Typography component="div">
16+
<City data={data.city} />
17+
</Typography>
18+
</CardContent>
19+
<CardActions>
20+
<div style={{ flex: '1 1 auto' }} />
21+
<Button color="primary" dense>
22+
Learn More
23+
</Button>
24+
</CardActions>
25+
</Card>
1026
);
1127
};
1228

@@ -20,5 +36,5 @@ export default createFragmentContainer(
2036
...City
2137
}
2238
}
23-
`,
39+
`
2440
);

components/LocationsList.js

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,47 @@
11
import { createFragmentContainer, graphql } from 'react-relay';
2+
import Typography from 'material-ui/Typography';
3+
import List from 'material-ui/List';
4+
import Paper from 'material-ui/Paper';
5+
import Divider from 'material-ui/Divider';
6+
import InboxIcon from 'material-ui-icons/Inbox';
7+
import DraftsIcon from 'material-ui-icons/Drafts';
8+
import Button from 'material-ui/Button';
29
import Location from './Location';
310

11+
const styles = {
12+
header: {
13+
textAlign: 'center',
14+
padding: '10px 0 5px 0'
15+
},
16+
container: {
17+
margin: '100px auto 0 auto',
18+
maxWidth: 400
19+
},
20+
list: {
21+
width: '100%'
22+
}
23+
};
24+
425
const LocationsList = ({ data }) => {
526
return (
6-
<div>
7-
Loaded: {data.allLocations.edges.length}
8-
<ol>
9-
{data.allLocations.edges.map(({ node, cursor }) =>
10-
<Location data={node} key={cursor} />,
11-
)}
12-
</ol>
27+
<div style={styles.container}>
28+
<div style={styles.header}>
29+
<Paper style={styles.header} elevation={4}>
30+
<Typography type="display1" gutterBottom>
31+
Locations
32+
</Typography>
33+
<Typography type="subheading" gutterBottom>
34+
Loaded: {data.allLocations.edges.length}
35+
</Typography>
36+
</Paper>
37+
</div>
38+
<div className={styles.list}>
39+
<List>
40+
{data.allLocations.edges.map(({ node, cursor }) =>
41+
<Location data={node} key={cursor} />
42+
)}
43+
</List>
44+
</div>
1345
</div>
1446
);
1547
};
@@ -27,5 +59,5 @@ export default createFragmentContainer(
2759
}
2860
}
2961
}
30-
`,
62+
`
3163
);

components/withRoot.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import React, { Component } from 'react';
2+
import { JssProvider } from 'react-jss';
3+
import {
4+
withStyles,
5+
createStyleSheet,
6+
MuiThemeProvider
7+
} from 'material-ui/styles';
8+
import { getContext } from '../styles/context';
9+
10+
// Apply some reset
11+
const styleSheet = createStyleSheet(theme => ({
12+
'@global': {
13+
html: {
14+
background: theme.palette.background.default,
15+
WebkitFontSmoothing: 'antialiased', // Antialiasing.
16+
MozOsxFontSmoothing: 'grayscale' // Antialiasing.
17+
},
18+
body: {
19+
margin: 0
20+
}
21+
}
22+
}));
23+
24+
let AppWrapper = props => props.children;
25+
26+
AppWrapper = withStyles(styleSheet)(AppWrapper);
27+
28+
function withRoot(BaseComponent) {
29+
class WithRoot extends Component {
30+
static getInitialProps(ctx) {
31+
if (BaseComponent.getInitialProps) {
32+
return BaseComponent.getInitialProps(ctx);
33+
}
34+
35+
return {};
36+
}
37+
38+
componentDidMount() {
39+
// Remove the server-side injected CSS.
40+
const jssStyles = document.querySelector('#jss-server-side');
41+
if (jssStyles && jssStyles.parentNode) {
42+
jssStyles.parentNode.removeChild(jssStyles);
43+
}
44+
}
45+
46+
render() {
47+
const context = getContext();
48+
49+
return (
50+
<JssProvider registry={context.sheetsRegistry} jss={context.jss}>
51+
<MuiThemeProvider
52+
theme={context.theme}
53+
sheetsManager={context.sheetsManager}
54+
>
55+
<AppWrapper>
56+
<BaseComponent {...this.props} />
57+
</AppWrapper>
58+
</MuiThemeProvider>
59+
</JssProvider>
60+
);
61+
}
62+
}
63+
64+
WithRoot.displayName = `withRoot(${BaseComponent.displayName})`;
65+
66+
return WithRoot;
67+
}
68+
69+
export default withRoot;

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
{
22
"dependencies": {
3+
"material-ui": "next",
4+
"material-ui-icons": "^1.0.0-alpha.19",
35
"next": "beta",
46
"react": "^15.6.1",
57
"react-dom": "^15.6.1",
8+
"react-jss": "^7.0.2",
69
"react-relay": "^1.1.0"
710
},
811
"devDependencies": {

pages/_document.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React from 'react';
2+
import Document, { Head, Main, NextScript } from 'next/document';
3+
import { getContext, setContext } from '../styles/context';
4+
5+
export default class MyDocument extends Document {
6+
static async getInitialProps(ctx) {
7+
// Reset the context for handling a new request.
8+
setContext();
9+
const page = ctx.renderPage();
10+
// Get the context with the collected side effects.
11+
const context = getContext();
12+
return {
13+
...page,
14+
styles: (
15+
<style
16+
id="jss-server-side"
17+
dangerouslySetInnerHTML={{
18+
__html: context.sheetsRegistry.toString()
19+
}}
20+
/>
21+
)
22+
};
23+
}
24+
25+
render() {
26+
const context = getContext();
27+
return (
28+
<html lang="en">
29+
<Head>
30+
<title>My page</title>
31+
<meta charSet="utf-8" />
32+
{/* Use minimum-scale=1 to enable GPU rasterization */}
33+
<meta
34+
name="viewport"
35+
content={
36+
'user-scalable=0, initial-scale=1, maximum-scale=1, ' +
37+
'minimum-scale=1, width=device-width, height=device-height'
38+
}
39+
/>
40+
{/* PWA primary color */}
41+
<meta
42+
name="theme-color"
43+
content={context.theme.palette.primary[500]}
44+
/>
45+
<link
46+
rel="stylesheet"
47+
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"
48+
/>
49+
</Head>
50+
<body>
51+
<Main />
52+
<NextScript />
53+
</body>
54+
</html>
55+
);
56+
}
57+
}

pages/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
import App from '../components/App';
2+
import withRoot from '../components/withRoot';
23

3-
export default () => <App />;
4+
const Index = () => <App />;
5+
6+
export default withRoot(Index);

styles/context.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { create } from 'jss';
2+
import preset from 'jss-preset-default';
3+
import { SheetsRegistry } from 'react-jss';
4+
import createPalette from 'material-ui/styles/palette';
5+
import createMuiTheme from 'material-ui/styles/theme';
6+
import { purple, green } from 'material-ui/colors';
7+
import createGenerateClassName from 'material-ui/styles/createGenerateClassName';
8+
9+
const theme = createMuiTheme({
10+
palette: createPalette({
11+
primary: purple,
12+
accent: green
13+
})
14+
});
15+
16+
// Configure JSS
17+
const jss = create(preset());
18+
jss.options.createGenerateClassName = createGenerateClassName;
19+
20+
function createContext() {
21+
return {
22+
jss,
23+
theme,
24+
// This is needed in order to deduplicate the injection of CSS in the page.
25+
sheetsManager: new WeakMap(),
26+
// This is needed in order to inject the critical CSS.
27+
sheetsRegistry: new SheetsRegistry()
28+
};
29+
}
30+
31+
export function setContext() {
32+
// Singleton hack as there is no way to pass variables from _document.js to pages yet.
33+
global.__INIT_MATERIAL_UI__ = createContext();
34+
}
35+
36+
export function getContext() {
37+
// Make sure to create a new store for every server-side request so that data
38+
// isn't shared between connections (which would be bad)
39+
if (!process.browser) {
40+
return global.__INIT_MATERIAL_UI__;
41+
}
42+
43+
// Reuse context on the client-side
44+
if (!global.__INIT_MATERIAL_UI__) {
45+
global.__INIT_MATERIAL_UI__ = createContext();
46+
}
47+
48+
return global.__INIT_MATERIAL_UI__;
49+
}

0 commit comments

Comments
 (0)