Back

Nuts and bolts of this site

November 15th, 2020
Approx reading time: 0 mins

Having spent many years struggling to find the time and motivation to build a nice little portfolio site, lockdown finally made it happen!! I didn't want a completely work focussed site and now I've parted my ways with Facebook, I plan to make it my 'profile'.

So, instead of a splash screen picture of a fancy MacBook or a thinky face looking at code, I went for one of my favourite ever holiday photos. Taken on a walk with my daughter, Lily, where we had an amazing view of the campsite we were staying on, the Atlantic Ocean, the Isle of Skye and the beautiful 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! Anyway, as this isn't a travel guide let's get back to the mechanics of this site, let's ease in with the content management before exploring the main tools.

contentful-logo-wordmark-dark

Content

For me, a site with a blog was always going to be best created in something like Wordpress but then I started getting more and more into React and realised 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. I know, you can use a traditional CMS headless, but why 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 thats thanks to Gatsby....

Gatsby-Logo

The Reasonably Great Gatsby

Now I'm no expert on Gatsby and have only just started using it in the last few months, but so far I'm really impressed, enough so to build this site with it. There have been times where I thought it would be easier to just use Create React App and just add all of the tools I need but Gatsby takes care of so many things.

Generating 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 amazing. It will optimise your images based on screens size, blur on load, lazy load 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 files is done through GraphQL. Theres a 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 draw back 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!

reactjs

My new favourite toy!

Ok, so having spent the last few years with my head buried in either Drupal or Salesforce, React has 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're not familiar with React yet, then you really should give it a try, building interfaces and even just simple web pages is so much better than doing it all from scratch the old fashioned way. I keep finding new and better ways to do things with it and new libraries that make life so much easier too.

At work we're starting to use it more and I was recently on a project setting up a starter kit framework for future projects, it was such good fun to do, especially as we had the freedom to do things our own way and not be dictated by specific project requirements. As well as being a massive head start for future projects it was a chance to come up with best practices with colleagues and learn from each other.

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

mui-logo-blue-svg

Material UI

I've used this a lot now and its great for getting things looking like they should quickly. There are so many components you can use 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 component level which I like. But there is an alternative which I prefer, and I have used both throughout my code, purely for the benefits of testing....

styled-components-logo

Styled Components

Now the logo might look pants but the way it works is brilliant. It's a bit like taking an existing component or even an HTML element, injecting some styles, then passing it to JSX with a brand new look and relevant 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 styles in back ticks, just as you'd write css, and then we 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 lets say its not a component, merely a plain old div or span or whatever other element you can think of, 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 div still gets a brand new fancy name. Now I'd be doing this library a huge injustice if I said its as simple as that, there is loads you can do, and I've just scratched the surface in my own usage, mostly adding dynamic properties with props and logic, which in itself is really helpful, the combination of SASS and JS makes me happy.

graphql-logo-svg

GraphQL

I couldn't write this without including GraphQL, another tool I'm just getting to grips with but its incredibly good. I created a GraphQL server and some basic queries as part of my work project, but Gatsby has it built in and ready to use in ways I still haven't figured out!

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.

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. Again, this library can do all sorts of clever things but for me it makes things fade and slide in. I did struggle at first I'll be honest, as I wanted things to animate on scroll, then I realised it doesn't make this happen on its own, so here is a bit of a guide for anyone, including my future self, if setting up scroll animation.

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 whats 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 the React useEffect hook. We pass the controls and inView variables, so the hook watches for changes on those, when inView is true it will start the 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 in to 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, none of which I can remember but there was a reason!!!

Conclusion

I may add more to this, but I really just wanted to cover off the highlights, and let's face it, there's plenty of resources out there to learn things properly. 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!