Back

Nuts and bolts of this site

November 15th, 2020
Approx reading time: 0 mins

Having spent many years struggling to find the time to build my own personal site, lockdown finally made it happen!!

So, now that it's built, I thought it might make a good first blog post to go over the tools behind this site as well as document some code snippets from some of the libraries that I've enjoyed using.

Design

Let's start off with the look and feel, I'm by no means a professional designer, but I really do enjoy it. I wanted something clean which also reflected my personality, so instead of the usual splash screen image of me trying to look trendy sitting looking at code, I went for one of my favourite holiday photos. Taken whilst on a walk with one of my daughters, Lily, we had an amazing view of the campsite we were staying on, the Atlantic Ocean, the Isle of Skye and the spectacular scenery around Gairloch in the North West Highlands of Scotland. A beautiful place to visit and 8 months into lockdown, I so want to be there right now!

I chose a fairly neutral colour scheme, I quite like the contrast of using bold blacks against a slightly off-white. Where there are drops of colour in logos and images it makes them stand out. I'm sure all of the designers reading this are rolling their eyes right now so I'll quickly move on to the content and development side of things...

Content

contentful-logo-wordmark-dark

For me, a site with a blog was always going to be best created in something like Wordpress but I wanted to build this site in React and figured I didn't need a traditional CMS at all. All I needed was somewhere to pull the data from and the freedom to use it in whatever front end I wanted. My first instinct was to use a traditional CMS headless, but why set up and maintain a CMS if you can use something like Contentful?

Contentful is a hosted content management service which lets you organise your content in a really slick UI and then pull the data into your application using their API. So with a combination of Contentful, React and GraphQL there's no need for a database or updating security patches in Wordpress, in fact, this whole site is as static as static comes, and that's thanks to Gatsby...

The Surprisingly Great Gatsby

Gatsby-Logo

I'm fairly new to Gatsby and have only started using it in the last few months, but so far I'm really impressed, enough so to build this site with it. At first, I thought it would be easier to just use Create React App and add all of the tools I needed, but Gatsby takes care of so many things, it was definitely the right choice for this site.

Gatsby generates a static site with all your metadata and fully rendered content without relying on server-side rendering and running Node.js in the background, and the way it manages images is really impressive. It will optimise your images based on screens size, blur on load, lazy load, adjustments and many other things, take a look at Gatsby Image here.

GraphQL is built into Gatsby with so many queries ready to use, even loading assets from within your site is done through GraphQL. There's a Gatsby plugin available to hook GraphQL up to Contentful so pulling your content in is really easy. You can also get plugins to pull data from Wordpress, Drupal and I'm sure other CMS's, but as previously said, I like the no maintenance aspect of Contentful.

It's probably worth pointing out a slight drawback with pulling in external data in this way, it only happens on build, so new content won't make it through to your live site without rebuilding it in Gatsby. Not a massive problem, but for any site constantly updating content, maybe it's not the ideal solution.

Gatsby Plugins

There are loads of Gatsby plugins available, helping to enhance what you get out of the box. Here is a list of some of the ones I am using.

  • gatsby-plugin-react-helmet

  • gatsby-plugin-sass

  • gatsby-plugin-styled-components

  • gatsby-source-contentful

  • gatsby-transformer-sharp

  • gatsby-plugin-sharp

  • gatsby-theme-material-ui

  • gatsby-plugin-web-font-loader

Just install the plugin using yarn or npm and then add to your config file

1plugins: [ 
2  `gatsby-plugin-react-helmet`,
3  `gatsby-plugin-sass`,
4  `gatsby-plugin-styled-components`
5]

There's so much to cover in Gatsby, I highly recommend heading to their docs and learning more about it, like anything there are some decent YouTube guides as well. Meanwhile, let's get into the heart of Gatsby and the main reason I'm using it.......React!

React - my favourite toy!

reactjs

Having spent a few years with my head buried in either Drupal or Salesforce, React completely renewed by dev mojo. I started out as a front-end developer and the creativity that it brings is what made me pursue a career as a developer (which I think I'll write about soon).

If you've not tried React yet, then you really should. I've used Angular and Aurelia in projects before, but with React I really like how you start with a very lightweight framework and build it up as you need to, depending on what you're trying to achieve. There are many libraries and frameworks available and a massive React community to help you along the way.

On a slight side note, I have recently been on a project setting up a React starter kit framework, adding our own layer on top of a standard Create React App. It was such good fun to do, especially as we had the freedom to do things our own way and spend time exploring what we deemed as the right tooling for our work. The starter kit will provide a massive head start for future projects and also keep them consistent by setting out best practices and coding standards.

React definitely puts me in my developer happy place!

This site is far from complex, so tooling is fairly minimal, but here is a high-level summary of what other libraries and frameworks I'm using...

Material UI

mui-logo-blue-svg

Coming from a Bootstrap background, I decided to give Material a try last year and it has now become my goto CSS framework, especially with React, where I use Material UI.

Material UI has a huge library of ready to use components and styling them is really easy too with MUI's built-in makeStyles function, you just write your styles as an object then add them as a class...

1import { makeStyles } from "@material-ui/core/styles"
2
3const useStyles = makeStyles((theme) => ({
4  skillGrid: {
5    [theme.breakpoints.down('md')]: {
6      marginTop: 30,
7    },
8  },
9})); 

Then all you have to do is apply the class, in this case skillGrid, to the component...

1const classes = useStyles();
2
3<Grid xs={12} md={6} item className={classes.skillGrid}>

Really easy and it keeps your styling at a component level which I like. But there is an alternative way to style components, or rather an addition, which I really enjoy using too...

Styled Components

styled-components-logo

Now the logo might look questionable but the way it works is brilliant. You basically take an existing component or an HTML element, add some styles, then pass it to JSX with a brand new look and name, here's an example...

1import Box from "@material-ui/core/Box"
2import styled from "styled-components"
3
4const BlogContent = styled(Box)`
5  margin: 1rem;
6  font-size: 1.1rem;
7`

You can see there that we pass in the Box component to styled() and then add the style properties in backticks, just as you'd write standard CSS. We then use the BlogContent component in the JSX, which is everything the Box component was but with the extra styles...

1<BlogContent>
2  //content goes here
3</BlogContent>

But let's say it's not a component, merely a plain old div or span or any other HTML element, its almost the same, just a very slight difference...

1const BlogContent = styled.div`
2  margin: 1rem;
3  font-size: 1.1rem;
4`

The difference being we use dot notation with HTML elements, everything else is the same, and the newly styled div is then referenced by its new name, BlogComponent.

I'd be doing this library a huge injustice if I said it was as simple as that as there's a lot more you can do, and I've just scratched the surface here.

GraphQL

graphql-logo-svg

I couldn't write this without including GraphQL, another tool I really love using. I recently created a GraphQL server and some queries to retrieve data from Azure Dev Ops as part of a work project, but Gatsby has it built-in and ready to use out of the box.

In the words of the Gatsby website:

You do not have to use GraphQL with Gatsby, however, GraphQL offers a few advantages over other methods of importing data.

  • You can retrieve only the data that you need for a view.

  • You can add new data types and capabilities without needing to create a new endpoint.

  • You can store content in whatever way makes sense for your site, whether that’s in a database, a third-party headless CMS, or Markdown-formatted text files.

I use it for loads across this site, pulling in this content for a start but also for all the images, which you can then use Gatsby's image manipulation tools to do all sorts of cool things. Having worked with API's a lot over the years, GraphQL gives you much better control over what data you need, and more importantly ignoring the data you don't.

Framer Motion

framer-motion

Worth noting - this is more of a basic how-to guide.

Everyone loves a bit of subtle animation, and this library nails it with React. I'm only going to go over the basics of Framer Motion, there are so many use cases for it and it is extremely powerful, far beyond sliding and fading in elements.

I wanted things to animate as the user scrolls down the page, fairly common practice really. When I first discovered Framer Motion I found that it doesn't make this happen on its own, so here is a bit of a guide for anyone, including my future self, for setting up scroll animation and the additional tools needed.

Firstly, you need to install another library, react-intersection-observer. This is what detects the page location and triggers the animation (or anything else you want to trigger on scroll). Being someone who hates bitty code snippets when needing the whole thing, here's a reusable animation component I created, I'll talk through it underneath...

1import React, { useEffect } from "react"
2import { useInView } from "react-intersection-observer"
3import { motion, useAnimation } from "framer-motion"
4
5const FadeMeIn = ({ children, thresh = 0.45, delay = 0, animate = true }) => {
6  const controls = useAnimation()
7  const [ref, inView] = useInView({ threshold: thresh })
8
9  useEffect(() => {
10    if (inView) {
11      controls.start("visible")
12    } else {
13      // controls.start("hidden")
14    }
15  }, [controls, inView])
16
17  const fadeVars = () => {
18    const variants = {
19      visible: {
20        opacity: 1,
21        transition: {
22          delay: delay,
23          duration: 0.8,
24        },
25      },
26      hidden: {
27        opacity: 0,
28      },
29    }
30    return variants
31  }
32
33 if (!animate) {
34    return <>{children}</>
35  }
36
37return (
38    <div ref={ref}>
39      <motion.div animate={controls} initial="hidden" variants={fadeVars()}>
40        {children}
41      </motion.div>
42    </div>
43  )
44}
45
46export default FadeMeIn

So, this is what's going on, we first set a variable for the useAnimation() function, this will trigger the animation when we need it to. Next, we're using the useView hook provided by react-intersection-observer. We have a ref which is a reference to the component we want to watch (see the outer div in the JSX) and we have inView, which lets us know when it is, you guessed it, in view, this will be a boolean value.

In my example I'm passing in a threshold parameter, I've also set it up so that I can pass this value in as a prop, but have a 0.45 default value. This threshold basically represents how much of the component needs to be in view before it sets inView to true, 1 means fully on-screen, and then partially less as you lower that number, 0.45 works well.

Next up we have the React useEffect hook. We pass the controls and inView variables, so useEffect watches for changes on those, when inView is true it will start the animation with controls.start("visible"), passing in 'visible' refers to the options in the fadeVars variable further down. This means that if in view, apply opacity 1 with a transition.

Framer motion knows about these options as we pass them into the motion.div in the JSX, so the controls function just tells it which options to run. By the way, you have to prefix an element with motion, so motion.span etc will work just the same.

Now there are many options that can be passed in, but in this instance, it's a very simple animation, head to their site for all options. You'll also notice the commented out controls.start("hidden"). I left it in to remind myself its there if I ever need it, and also to explain what it does.

Pretty straight forward really, useEffect will go into the else as soon as the element scrolls out of view, so we can trigger the control.start function again if we want, in this case, make the element opacity 0. Now it probably has a good use case but when scrolling down a page, fading text in is nice once, but the second and third time when you scroll back is a bit annoying and lacks the same effect. So by not having anything trigger in the else, means Framer Motion will just leave things be until you tell it otherwise.

To use this animation, you just add it to your component in the usual fashion and wrap the things you want to animate with FadeIn, like so...

1<FadeMeIn thresh={0.1}>
2  <h1>Hello everyone</h1>
3</FadeMeIn>

passing a thresh is optional, I've also added optional delay and animate props. Delay is good if using with other animations (look at my home page splash as an example, the profile pic fade's in a couple of seconds after the text slides in). Animate is a boolean, which lets me turn off animation dynamically under certain circumstances.

Conclusion

I may add more to this as I add more to the site, but I really just wanted to cover off the main tooling I used to create this site. I'm going to write more posts about the things I do and tools I use, it may help you, it may not, but it's quite therapeutic writing about my work, plus, in years to come I can look back at this and get nostalgic about how we used to do things!