Working on the Layout
In this article, we'll see how to make our blog a bit more appealing by working on the layout. We'll add a header, footer, navigation bar, and in general, we'll see how to create reusable components.
Specifically, we'll define:
- - a component that implements the Header, within which we'll position the site header and, just below it, the navigation bar to move between pages;
- - another component for the Footer, where we'll put, for example, contact information;
- - finally, a Layout component that encapsulates both the Header and Footer components, so we can use only this one in the blog pages.
Prerequisites
We need to install some plugins that will facilitate the development of the site for aspects concerning stylesheets and the use of specific fonts.
Let's start by installing the
gatsby-plugin-sassplugin with the command:
npm install sass gatsby-plugin-sass
Then, let's modify the
gatsby-config.js file and add the
`gatsby-plugin-sass` entry within the
plugins section. Through this addition, we can write our stylesheets in a file with
.scss extension and import it like any other component. Let's also install the
gatsby-plugin-google-fonts plugin with the command:
npm install gatsby-plugin-google-fonts
to use Google Fonts: for our blog, we'll use the Roboto font, so we'll specify these settings in the
gatsby-config.jsfile (in the
plugin section):
{
resolve: `gatsby-plugin-google-fonts`,
options: {
fonts: [
`roboto`
],
display: 'swap'
}
}
Header Component
To structure the source code in an orderly way, let's create a directory that will contain the components. Inside the
srcdirectory, let's create the
componentsdirectory and, inside it, create these files:
- - header.js: will contain the code to define the Header component;
- - header.module.scss: is the style sheet with the stylesheets used by header.js:
Note
As a general rule, each component will consist of two files:- - a file with .js extension will contain the component definition;
- - a file with .scss or .css extension will contain the definition of stylesheets used by the component.
Inside the header.js file, let's insert this code:
import * as React from "react"
import { Link } from "gatsby"
import { graphql } from "gatsby"
import { useStaticQuery } from 'gatsby'
import * as styles from "./header.module.scss"
export default function Header() {
const data = useStaticQuery(headerQuery)
const { title, description, author } = data.site.siteMetadata
return (
<>
<header className={styles.header}>
<Link className={styles.linkHome} to="/">
<p className={styles.title}>{title} - {author}</p>
<p className={styles.description}>{description}</p>
</Link>
<div className={styles.menu}>
<ul className={styles.navigation}>
<li><Link to="/" activeClassName={styles.navigationActive} className={styles.navigation}>Home</Link></li>
<li><Link to="/about/" activeClassName={styles.navigationActive} className={styles.navigation}>About</Link></li>
</ul>
</div>
</header>
</>
)
}
const headerQuery = graphql`
query headerQuery {
site {
siteMetadata {
title
description
author
}
}
}
`
}
In the
header.module.scss file, let's insert this code:
.header {
background-color: #0d4faa;
font-family: Roboto;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 20px;
padding-right: 20px;
}
.linkHome {
color: #d9e9f1;
text-decoration: none;
}
.title {
font-family: Roboto;
font-size: 24pt;
font-weight: bold;
margin: 0px;
}
.description {
font-family: Roboto;
font-size: 16pt;
margin: 0px;
}
.menu {
font-family: Roboto;
color: #ffffff;
background-color: #444444;
margin-top: 10px;
}
ul.navigation {
list-style-type: none;
margin-left: 0px;
margin-right: 0px;
overflow: hidden;
background-color: #358b5c;
margin-block-start: 0px;
margin-block-end: 0px;
padding-inline-start: 0px;
}
ul.navigation > li {
display: block;
float: left;
}
.navigation {
text-decoration: none;
color: white;
}
ul.navigation > li a {
display: block;
color: white;
text-align: center;
text-decoration: none;
padding: 14px 16px;
font-size: 22px;
}
ul.navigation > li a:hover {
background-color: rgb(145, 218, 131);
}
.navigationActive {
background-color: rgb(112, 172, 104);
}
Footer Component
Similarly to what we did for the
Header component, in the
components directory let's create the files:
- - footer.js: will contain the code to define the Footer component;
- - footer.module.scss: is the style sheet with the stylesheets used by footer.js:
Inside the
footer.js file, let's insert this code:
import * as React from "react"
import { graphql } from "gatsby"
import { useStaticQuery } from 'gatsby'
import * as styles from "./footer.module.scss"
export default function Footer() {
const data = useStaticQuery(footerQuery)
const { title, author } = data.site.siteMetadata
return (
<footer className={styles.footer}>
<div>
<h1>
<div className={styles.text}>
2022 - {author} - {title}
</div>
<div className={styles.text}>
<a href="mailto:info@moschini.cloud">
info@moschini.cloud
</a>
</div>
</h1>
</div>
</footer>
)
}
const footerQuery = graphql`
query footerQuery {
site {
siteMetadata {
title
author
}
}
}
`
In the footer.module.scss file, let's insert this code:
.footer {
background-color: #b1c7e6;
margin-top: 30px;
font-family: Roboto;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 20px;
padding-right: 20px;
position: relative;
bottom: 0;
}
.text {
color: rgb(7, 93, 133);
text-decoration: none;
font-family: Roboto;
font-size: 14pt;
font-weight: normal;
text-align: center;
}
Layout Component
Finally, for the
Layout component, in the
components directory let's create the files:
- - layout.js: will contain the code to define the Layout component;
- - layout.module.scss: is the style sheet with the stylesheets used by layout.js:
whose content is:
layout.js:
import * as React from "react"
import PropTypes from "prop-types"
import Header from "./header"
import Footer from "./footer"
import * as styles from "./layout.module.scss"
const Layout = ({ children }) => {
return (
<>
<Header>
</Header>
<div className={styles.maincontent}>
<main>
{children}
</main>
</div>
<Footer>
</Footer>
</>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired
}
export default Layout
layout.module.scss:
* {
box-sizing: border-box;
}
.maincontent {
margin-top: 0px;
margin-bottom: 0px;
margin-left: 150px;
margin-right: 150px;
font-family: Roboto;
}
Using the Layout Component
At this point, we have what we need to standardize the layout of all blog pages. Let's start with the home page, that is, the
index.js file, whose code we'll replace with this:
import React from "react"
import { graphql } from "gatsby"
import { Link } from 'gatsby'
import Layout from "../components/layout"
export default function Home({ data }) {
const { title, description, author } = data.site.siteMetadata
return (
<div>
<Layout>
<h1>{title}</h1>
<p>{description}</p>
<p>{author}</p>
<Link to="about">About</Link>
</Layout>
</div>
)
}
export const pageQuery = graphql`
query MetadataQuery {
site {
siteMetadata {
title
description
author
}
}
}
`
The differences from the previous version concern:
- - importing the Layout component
- - its use through the tags <Layout> ... </Layout>: what we've put between the opening and closing tags is the page content, so any further code additions must be made within the <Layout> ... </Layout> section. This way, if all site pages use the Layout component, we'll have complete uniformity of the visual interface.
Similarly, the code for the About page (file: about.js) will be modified as follows:
import * as React from "react"
import { StaticImage } from "gatsby-plugin-image"
import Layout from "../components/layout"
const About = () => (
<div>
<Layout>
<h1>Mi chiamo Fabio Moschini e sono un programmatore.</h1>
<p>Puoi inviarmi una email a questo indirizzo:
<a href="mailto:info@moschini.cloud">
info@moschini.cloud
</a>
</p>
<StaticImage
layout="fullWidth"
alt="notebook"
src="../images/notebook.jpg"
/>
</Layout>
</div>
)
export default About
In this case too, all the page content is enclosed between the
<Layout> ... </Layout> tags. The final result is: