Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MUI setup with react-jss #9

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
26 changes: 17 additions & 9 deletions components/City.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import { createFragmentContainer, graphql } from 'react-relay';
import Typography from 'material-ui/Typography';
import List, { ListItem, ListItemText } from 'material-ui/List';

const styles = {
subItem: {
marginLeft: '10px'
}
};

const City = ({ data }) => {
if (!data) return null;
return (
<ul>
<li>
City: {data.name}
</li>
<li>
Slug: {data.slug}
</li>
</ul>
<List>
<ListItem>
<ListItemText primary={`City: ${data.name}`} />
</ListItem>
<ListItem>
<ListItemText primary={`Slug: ${data.slug}`} />
</ListItem>
</List>
);
};

Expand All @@ -21,5 +29,5 @@ export default createFragmentContainer(
name
slug
}
`,
`
);
26 changes: 21 additions & 5 deletions components/Location.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import { createFragmentContainer, graphql } from 'react-relay';
import Card, { CardActions, CardContent } from 'material-ui/Card';
import Typography from 'material-ui/Typography';
import Button from 'material-ui/Button';
import City from './City';

const Location = ({ data }) => {
return (
<li key={data.locationId}>
{data.name}
<City data={data.city} />
</li>
<Card key={data.locationId}>
<CardContent>
<Typography type="headline" component="h2">
{data.name}
</Typography>

<Typography component="div">
<City data={data.city} />
</Typography>
</CardContent>
<CardActions>
<div style={{ flex: '1 1 auto' }} />
<Button color="primary" dense>
Learn More
</Button>
</CardActions>
</Card>
);
};

Expand All @@ -20,5 +36,5 @@ export default createFragmentContainer(
...City
}
}
`,
`
);
44 changes: 36 additions & 8 deletions components/LocationsList.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
import { createFragmentContainer, graphql } from 'react-relay';
import Typography from 'material-ui/Typography';
import List from 'material-ui/List';
import Paper from 'material-ui/Paper';
import Location from './Location';

const styles = {
header: {
textAlign: 'center',
padding: '10px 0 5px 0'
},
container: {
margin: '100px auto 0 auto',
maxWidth: 400
},
list: {
width: '100%'
}
};

const LocationsList = ({ data }) => {
return (
<div>
Loaded: {data.allLocations.edges.length}
<ol>
{data.allLocations.edges.map(({ node, cursor }) =>
<Location data={node} key={cursor} />,
)}
</ol>
<div style={styles.container}>
<div style={styles.header}>
<Paper style={styles.header} elevation={4}>
<Typography type="display1" gutterBottom>
Locations
</Typography>
<Typography type="subheading" gutterBottom>
Loaded: {data.allLocations.edges.length}
</Typography>
</Paper>
</div>
<div className={styles.list}>
<List>
{data.allLocations.edges.map(({ node, cursor }) =>
<Location data={node} key={cursor} />
)}
</List>
</div>
</div>
);
};
Expand All @@ -27,5 +55,5 @@ export default createFragmentContainer(
}
}
}
`,
`
);
69 changes: 69 additions & 0 deletions components/withRoot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React, { Component } from 'react';
import { JssProvider } from 'react-jss';
import {
withStyles,
createStyleSheet,
MuiThemeProvider
} from 'material-ui/styles';
import { getContext } from '../styles/context';

// Apply some reset
const styleSheet = createStyleSheet(theme => ({
'@global': {
html: {
background: theme.palette.background.default,
WebkitFontSmoothing: 'antialiased', // Antialiasing.
MozOsxFontSmoothing: 'grayscale' // Antialiasing.
},
body: {
margin: 0
}
}
}));

let AppWrapper = props => props.children;

AppWrapper = withStyles(styleSheet)(AppWrapper);

function withRoot(BaseComponent) {
class WithRoot extends Component {
static getInitialProps(ctx) {
if (BaseComponent.getInitialProps) {
return BaseComponent.getInitialProps(ctx);
}

return {};
}

componentDidMount() {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles && jssStyles.parentNode) {
jssStyles.parentNode.removeChild(jssStyles);
}
}

render() {
const context = getContext();

return (
<JssProvider registry={context.sheetsRegistry} jss={context.jss}>
<MuiThemeProvider
theme={context.theme}
sheetsManager={context.sheetsManager}
>
<AppWrapper>
<BaseComponent {...this.props} />
</AppWrapper>
</MuiThemeProvider>
</JssProvider>
);
}
}

WithRoot.displayName = `withRoot(${BaseComponent.displayName})`;

return WithRoot;
}

export default withRoot;
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
{
"dependencies": {
"material-ui": "next",
"material-ui-icons": "^1.0.0-alpha.19",
"next": "beta",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-jss": "^7.0.2",
"react-relay": "^1.1.0"
},
"devDependencies": {
Expand Down
57 changes: 57 additions & 0 deletions pages/_document.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import Document, { Head, Main, NextScript } from 'next/document';
import { getContext, setContext } from '../styles/context';

export default class MyDocument extends Document {
static async getInitialProps(ctx) {
// Reset the context for handling a new request.
setContext();
const page = ctx.renderPage();
// Get the context with the collected side effects.
const context = getContext();
return {
...page,
styles: (
<style
id="jss-server-side"
dangerouslySetInnerHTML={{
__html: context.sheetsRegistry.toString()
}}
/>
)
};
}

render() {
const context = getContext();
return (
<html lang="en">
<Head>
<title>My page</title>
<meta charSet="utf-8" />
{/* Use minimum-scale=1 to enable GPU rasterization */}
<meta
name="viewport"
content={
'user-scalable=0, initial-scale=1, maximum-scale=1, ' +
'minimum-scale=1, width=device-width, height=device-height'
}
/>
{/* PWA primary color */}
<meta
name="theme-color"
content={context.theme.palette.primary[500]}
/>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
5 changes: 4 additions & 1 deletion pages/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import App from '../components/App';
import withRoot from '../components/withRoot';

export default () => <App />;
const Index = () => <App />;

export default withRoot(Index);
49 changes: 49 additions & 0 deletions styles/context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { create } from 'jss';
import preset from 'jss-preset-default';
import { SheetsRegistry } from 'react-jss';
import createPalette from 'material-ui/styles/palette';
import createMuiTheme from 'material-ui/styles/theme';
import { purple, green } from 'material-ui/colors';
import createGenerateClassName from 'material-ui/styles/createGenerateClassName';

const theme = createMuiTheme({
palette: createPalette({
primary: purple,
accent: green
})
});

// Configure JSS
const jss = create(preset());
jss.options.createGenerateClassName = createGenerateClassName;

function createContext() {
return {
jss,
theme,
// This is needed in order to deduplicate the injection of CSS in the page.
sheetsManager: new WeakMap(),
// This is needed in order to inject the critical CSS.
sheetsRegistry: new SheetsRegistry()
};
}

export function setContext() {
// Singleton hack as there is no way to pass variables from _document.js to pages yet.
global.__INIT_MATERIAL_UI__ = createContext();
}

export function getContext() {
// Make sure to create a new store for every server-side request so that data
// isn't shared between connections (which would be bad)
if (!process.browser) {
return global.__INIT_MATERIAL_UI__;
}

// Reuse context on the client-side
if (!global.__INIT_MATERIAL_UI__) {
global.__INIT_MATERIAL_UI__ = createContext();
}

return global.__INIT_MATERIAL_UI__;
}
Loading