Algo que acontece com muitos Devs é não ter alguma aptidão ou mesmo não ter tempo hábil para fazer os Designs e Layouts de suas aplicações, mas quem não gosta de um front-end bonitinho?

Para ajudar a todos, existem muitas bibliotecas com padrões de Design e Layout bem definidos, e é sobre uma delas que falaremos hoje, o Material UI.

Não falaremos do Material UI em si, mas sim da junção dele com o nosso queridíssimo ReactJS criando uma interface semelhante ao do WhatsApp Web. Então pegue o seu guarda-chuva pois virá uma chuva de códigos abaixo.

/!\ WARNING /!\

Se você não conhece o JavaScript ou suas novas features com o ES6+ veja nossos cursos gratuitos starter: javascript e ES6+!!

Configurando o ambiente

Vamos começar criando um App React com o CLI do create-react-app, que já configura o webpack, eslint e outras cozitas a mais.

create-react-app material-app

Depois no diretório do seu projeto vamos instalar o Material UI:

npm install @material-ui/core

Caso queiramos adicionar os componentes ícones:

npm install @material-ui/icons

E também, no arquivo public/index.html adicionaremos os links das fonts Roboto e Fonts Icon:

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

Isso já é o suficiente para você utilizar o ReactJS com o Material UI. Logicamente não vou deixar você brincar sozinho com isso, então bora fazer alguma coisa!!!

Configuração inicial

Resultado do App com ReactJS e Material UI

Vamos, a princípio, limpar alguns arquivos que não nos interessam e ajustar o que é preciso. Então vamos deixar apenas os arquivos:

// No src ficará apenas
src/App.js
src/index.js
src/index.css

Uma pequena limpeza no index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

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

Uma enxugada no index.html:

<!DOCTYPE html>
<html lang="pt-br">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>React + Material | RocketSeat</title>
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

E por fim, um fundo acinzentado no body, no index.css:

body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  background: "#dfdfdf";
}

Pronto!! Agora vamos sem medo fazer nosso App.

Aplicação

Para ficar mais fácil, aqui quebrei em diversas partes o nosso código para ir comentando.

import React from "react";
import { withStyles } from "@material-ui/core/styles";
import MoreVertIcon from "@material-ui/icons/MoreVert";
import { Paper, Typography, Grid, Card, CardHeader, CardContent, Avatar, List, ListItem, ListItemText, IconButton } from "@material-ui/core";

A função withStyles servirá para injetamos um CSS customizado dentro do nosso componente principal e com ela podemos pegar informações do Material UI e assim criar algumas classes CSS que serão necessárias.

Como importamos o Fonts Icon, é através do @material-ui/icons que pegamos os ícones que queremos. E pelo @material-ui/core importamos os componentes já estilizados e padronizados do Material UI. Você pode olhar todos os componente aqui.

Para montarmos nosso estilo utilizaremos uma Arrow Function que retorna um objeto (as nossas classes).

const styles = () => ({
 root: {
    padding: "50px 100px",
    zIndex: 999,
    position: "absolute"
  },
  card: {
    display: "flex",
    height: "calc(100vh - 100px)"
  },
  rightBorder: {
    borderRight: "solid #d0D0D0 1px"
  },
  content: {
    marginTop: 0
  },
  background: {
    position: "absolute",
    height: 200,
    width: "100%",
    top: 0,
    background: "#7159C1"
  },
  rightContainer: {
    background:
      "url(https://hdwallsource.com/img/2014/8/my-neighbor-totoro-wallpaper-27981-28703-hd-wallpapers.jpg) center center",
    flex: 1
  },
  heightAdjust: {
    display: "flex",
    flexDirection: "column"
  },
  paper: {
    background: "#9de1fe",
    padding: 20
  },
  information: {
    color: "#444"
  }
});

Como podemos ver, no código abaixo utilizamos o componente Grid, um sistema de colunas que vai de 1 a 12 representando a porcentagem de uma div. Isso acontece dentro de uma div container, e as colunas são “itens” desse container.

Por isso, passamos a propriedade container na nossa primeira Grid e a Grid filha com a propriedade item para ser uma coluna. Nada impede de uma Grid item ter outra container.

const App = ({ classes }) => (
  <div>
    <div className={classes.background} />
    <Grid container className={classes.root}>
      <Grid item xs={12}>
        <Card className={classes.card}>
          <Grid container>
            <LeftContainer classes={classes} />
            <RightContainer classes={classes} />
          </Grid>
        </Card>
      </Grid>
    </Grid>
  </div>
);

Observe a propriedade xs, ela indica que em telas muito pequenas aquela Grid será representada com 12 colunas ou seja 100% de width. Isso acontece por que as Grids são responsivas.

Existem outras propriedades como xs, sm, md, lg, e xl, assim você pode configurar para que em telas grandes seja representada por 6 colunas e nas pequenas 12 por exemplo. Para saber mais.

Card

Nosso componente principal será um grande Card que forçamos ter o tamanho da nossa tela subtraindo os paddings de 50px do topo e rodapé. Nele dividiremos em duas colunas que separamos em dois componentes stateless o LeftContainer e RightContainer.

const list = [
  { id: 1, name: "Diego", text: "Lorem ipsum", image: <ImageIcon /> },
  { id: 2, name: "Robson", text: "Lorem ipsum", image: <WorkIcon /> },
  { id: 3, name: "Cleiton", text: "Lorem ipsum", image: <BeachAccessIcon /> }
];

const LeftContainer = ({ classes }) => (
  <Grid item xs={3}>
    <CardHeader
      className={classes.rightBorder}
      avatar={
        <Avatar aria-label="Recipe" className={classes.avatar}>
          H
        </Avatar>
      }
    />
    <Paper className={classes.paper} elevation={0}>
      <Typography className={classes.information} variant="subheader">
        Acesse nossa comunidade no Discord e fique por dentro das novidades!
      </Typography>
    </Paper>
    <List>
      {list.map(item => (
        <ListItem>
          <Avatar>{item.image}</Avatar>
          <ListItemText primary={item.name} secondary={item.text} />
        </ListItem>
      ))}
    </List>
  </Grid>
);

Começamos com a Grid que representa a porcentagem de 3 colunas do nosso Grid container. Os demais componentes são todos do Material UI que possuem várias propriedades. Adicionei algumas classes para deixar a parada bacana.

const RightContainer = ({ classes }) => (
  <Grid className={classes.heightAdjust} item xs={9}>
    <CardHeader
      avatar={
        <Avatar aria-label="Recipe" className={classes.avatar}>
          <ImageIcon />
        </Avatar>
      }
      action={
        <IconButton>
          <MoreVertIcon />
        </IconButton>
      }
      title="Diego"
    />
    <CardContent className={[classes.rightContainer, classes.content]} />
  </Grid>
);

Aqui definimos uma Grid maior com a porcentagem de 9 colunas. Repara que juntando com o LeftContainer temos 100% da Grid pai preenchida. E como anteriormente todos os demais componentes do Material UI e é só dar aquele bisu no site deles para esclarecer alguma propriedade.

Por fim, vamos exportar o nosso App. Perceba que usamos o withStyles passando como argumento o nosso styles, ela nos retorna uma outra função que injeta a propriedade classes que usamos dentro do nosso App.

export default withStyles(styles)(App);

Conclusão

É nítido que não há limites com o que você pode fazer com o Material UI em pouco tempo e com pouco trabalho!!!

O que eu fiz foi apenas uma demonstração. E que tal você fazer algo e mostrar para gente!??

Código completo no github: https://github.com/Rocketseat/blog-react-material-ui

Não esquece de deixar seu comentário dizendo o que achou e compartilhar com seus amigos. ;P