Frontend Serverless with React and GraphQL

Start at the beginning and work your way through this project. The code for each step as well as the finished project can be found in the Github repository.


4. Add main layout

Objective: Create a theme object that we can use across our application.

Now we need to create the standard layout containers which will display on each page. First, create /components/layout and /utils folders. Next, create a theme.ts file which will contain all of the css defaults that we can utilize across our app. The strength with defining our defaults in one file, is that we can easily update something like a margin across our entire app. Our strategy for naming our constants is to use underscores _ while at the bottom of the document we create an entire object where the keys have dashses - instead. We unfortunately have to make this switch because dashes - are not allowed in variable names.

utils/theme.ts

const padding_zero = `0em`;
const padding_small = `16px`;
const margin_zero = `0em`;
const margin_small = `16px`;
const font_size_xs = `0.75em`;
const font_size_sm = `1.00em`;
const font_size_md = `1.25em`;
const font_size_lg = `1.50em`;
const font_size_xl = `2.00em`;
const heart_color = `#eb2f96`;
const border_color = `#e6e6e6`;
const header_color = `#ffffff`;
const header_border_color = header_color;
const border_width = `2px`;
export const theme = {
'font-size-xs': font_size_xs,
'font-size-sm': font_size_sm,
'font-size-md': font_size_md,
'font-size-lg': font_size_lg,
'font-size-xl': font_size_xl,
'padding-zero': padding_zero,
'padding-small': padding_small,
'margin-zero': margin_zero,
'margin-small': margin_small,
'heart-color': heart_color,
'border-color': border_color,
'border-width': border_width,
'header-color': header_color,
'header-border-color': header_border_color,
};

Now that we have our theme object, we need to add it as a prop to a <ThemeProvider> component so that it can be used across our application. We will create a <MainLayout> component that we will wrap around each page of our application, and so that will be the perfect place to have our <ThemeProvider>.

components/layout/MainLayout.tsx

import { ThemeProvider } from 'styled-components';
import { Component } from 'react';
import { theme } from '../../utils/theme';
export class MainLayout extends Component {
render() {
const { children } = this.props;
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
}
}

We create our <MainLaout> component within the component/layout directory and for now, lets only return the <ThemeProvider> component that is wrapped around the children prop. Creating our component like this will allow us to nest our page content within the <MainLayout> component like this:

pages/index.tsx

import styled from 'styled-components';
import { MainLayout } from '../components/layout/MainLayout';
const StyledHeader = styled.h1`
${({ theme }) => `
font-size: 2em;
text-align: left;
padding: ${theme['padding-small']} ${theme['padding-small']};
`}
`;
const Index = () => {
return (
<MainLayout>
<StyledHeader>Index Page</StyledHeader>
</MainLayout>
);
};
export default Index;

We will use a similar pattern for each new page component that we create for this application. A totally reasonable question at this point is "if the <MainLayout> component is going to live on each page, why not just put it in the _app.tsx component?" The reason why we are doing this, is that later we will pass in a prop to the <MainLayout> component called title which will set the title in the head of the html document. Since that prop will change from page to page, we can't utilize a static <MainLayout> and so we will instead call it in each page.