This custom website, powered by Gatsby.

This project page is about the very website you are looking at! I attempted to build a new portfolio website at the beginning of 2020 using Jekyll, a static generation tool I've used a few times before to build websites during my MFA, but I found that when it came to customizing a website it just didn't work for me. I'm not a web developer by trade and Jekyll seemed to jump from very tidy if you found a theme you really liked and could live with, to very messy if you wanted to start customizing.

Enter Gatsby! I started building this website mid-March of 2020 and launched in about five weeks, including writing all of my project content and collected image assets. I really appreciate their design philosophy, especially their concept of progressively disclose complexity which essentially boils down to simplifying the experience for most users without limiting the abilities of more advanced users. I have to say, I think they've done a great job holding to that philosophy. I'm quite happy with this site and how easy it is to maintain, modify, and update.

A somewhat new habit for me is keeping bullet journals for any of my projects, and this website is no exception. Below is the growing bullet journal for my journey creating this website.

May 7th, 2020

  • Just going through each project and adding some images to the slider gallery, the copy, and the trailing gallery! A little tedious but not terrible since I already prepped images for just about everything.
  • Took about three hours but done! Each project has images to display. Looks pretty good I think. I also added more projects that I'd forgotten to set to publish. At this point I feel comfortable pushing my website around, though I do still want to get the 'awards' stuff parsing before I well and truly call it 'done'.

May 5th, 2020

  • I fixed padding in the mdx image component when images are 'center' aligned. It just didn't have any padding set so the bottom was tight against text which looked weird. I see why the 'mobile' specific css is there and hope I can get it to work with my website state. Basically, if it is mobile, just go 100% width and not flow text. The typescript version was doing this with the help of <StateConsumer>. I should be able to figure out how that one works and replicate it myself.
    • The context.tsx file looks simple enough so I think I can recreate my own <StateConsumer> for providing mobile state.
  • I attempted to add inline code highlighting with the gatsby-remark-vscode plugin I'm using but it isn't working. Harumph.

May 4th, 2020

  • The 'install on homescreen' and 'offline' stuff seems to be working? I know not all browsers have the same level of support so there probably isn't much else I can do. In either case, it works well enough and done.
  • I'm hoping to finish getting the custom react node for images that I can just plop inside markdown working... The example has syntax I'm not familiar with but I believe is React stuff:
const imgs: { [k: string]: React.ReactNode } = {};
if (images) {
  images.forEach((image, i) => {
    const { childImageSharp } = safe(image);
    const { fluid } = safe(childImageSharp);

    imgs[`Image${i}`] = () => <Img fluid={fluid} />;
  • The const imgs: { ... } = {}; syntax I'm not familiar with.
  • Ah, the individual that created the ticket with the above example wrote up a using gatsby images with mdx guide!
  • Hahaha, ok, it's because it's typescript!!! That's why the syntax wasn't making sense to me!
  • Thank you Em Lazerwalker! She helped me convert the typescript... rather, just pick out the validation and typing that TS does. Much closer... Needed to install gatsby-plugin-material-ui - not entirely sure if I need it yet.
  • This is what I needed to install exactly btw... needed core.
npm install gatsby-plugin-material-ui @material-ui/styles @material-ui/core
  • With a bit more help from Em it works! Finally! I don't think it is actually using the material-ui stuff I installed so I'll see if I should just remove it, but it isn't hurting anything atm.
  • Ultimately it was <StateConsumer> causing the problem, since it is part of a bigger state management thing that was actually looking for {mobile} and injecting or calling stuff. Just ripped it out. I can dig around that typescript blog later if I want to go that route or explore the more advanced stuff. For now, work on getting images in all the projects looking nice!

May 3rd, 2020

  • Went through every project to name and optimize any extra photos that weren't ready for use, and found new pictures if there weren't enough or some were missing. Took a while, but I'm hoping I still have time today to actually get more pictures on each of the project pages, at least in the little slidy gallery at the top and maybe a handful tacked on the bottom.
  • Trying to decide how images should exist in a project space. The small slideshow is nice but it doesn't lightbox. Perhaps I can add that feature?
    • There is a 'gallery' of images at the bottom from the theme, which is simply a vertical list of images. Not even padded (so I added some).
  • I finally figured out what the React ... is called: property spread notation - it's basically for passing around iterables.
  • I found a great example (in the form of a bug report) for creating html tags you can insert into the markdown, injected by MDXRenderer: gatsby mdx images - I haven't gotten it to work yet, some weird (to me) syntax for the template page but I'm working on it!
  • I installed the manifest and offline plugins (so you can add the website to your phone home screen and use it offline respectively). Going to test over the next day and see if it works!

April 24th, 2020

  • Got sucked into trying to get emojis to work in markdown. Failed, but I found what I think is a better code highlighting plugin: gatsby-remark-vscode
    • It has the added benefit of using the same color themes I'm used to. Line numbering isn't built in but I'll figure that out later.

April 23rd, 2020

  • Still couldn't set the CNAME for 'www'. I contacted dreamhost support and they confirmed there is an occasional bug where switching to 'DNS Only' hands on to 'www'. I'm guessing because I had it set to remove 'www' when fully hosted and that doesn't get cleaned up. In any case, support cleared it and I was able to set the CNAME! It should propagate in a few hours so I'll check this afternoon.
  • I guess I'm officially launched!!!

April 22nd, 2020

  • High hopes of launching the website today. Lots left to do but I think I've achieved MVP (minimum viable product).
  • First thing I noticed was that in mobile mode the pixel jerry and title + subtitle broke. Thankfully I was able to fix it relatively quickly by adding flex-wrap: wrap to the flex box they are in.
  • I had created a Capitalize helper function in utils.js but I was calling export default Capitalize so only that function could exist in that file. With the help of this Stack Overflow question I figured out how to set up a javascript file with multiple helpers.
    • First, in utils.js instead of const Capitalize ... and after the function export default Capitalize; just use export const Capitalize ... and drop the default export.
    • Second, instead of importing like this: import Capitalize from "../components/utils", explicitely use the exported name like this: import { Capitalize } from "../components/utils"
      • You see, if you export default, then you can call the import whatever you want and use it by that name. If you have more than one export (so you aren't exporting default) then you need to use the curly brackets and the exact name exported. So import Capitalize ... could have been import Cappy ... and it would have worked with export default Capitalize;.
  • I screwed up today trying to deploy! Since I'm not using gh-pages and I want the site live at the root of the github pages user account ( that means pushing to the master branch. Well, I pushed the generated content on top of the source. It was gross. I reverted and did a bit more searching until I found this gatsby to github deployment tutorial. Even better, they linked to the source of their own website so I could poke around. Not only did it help me write the script I needed to handle deploying, but I realized I can have a source repository that stays private, and the destination repository ( can be public for serving the final website. Phew!
  • Ready to actually deploy! First up, I made sure a file called CNAME was in the gatsby static folder with the domain value:
  • Then I added the A records to my domain and it updated pretty quickly! Since dreamhost was already handling removing the 'www' they both work to get to the github served website. It's nice too that still works and just forward to as well.
    • The one issue is the security certificate is, of course, now invalid. I removed and readded it but that didn't change anything. Eventually it'll probably fix itself when it generates a new cert, but that could be an issue if employers are visiting the website...
    • Figured it out with a little help from this dreamhost to github tutorial! First, I needed to update my domain hosting on dreamhost to DNS Only. This didn't mess up the A records I had already input. Then I was able to, from the repo settings on github, check the Enforce HTTPS setting in the Github Pages section. Now the website shows as secure again! Only one thing left...
    • I think I need to wait for dreamhost to update stuff... In order to make sure still works, I needed to add a CNAME entry with www* as the name, and** as the value. It won't let me add it yet (which makes sense if they are hosting, but I switched to DNS only)... so we'll check tomorrow!

April 21st, 2020

  • The last three days have been primarily focused on finishing drafts of page content for all projects. My amazing wife did an editing pass to help push things along, so page text content is now ready!
  • Yesterday I refocused on images. How should I handle the source images? This includes naming, image format, compression, and master files.
    • For naming I read that SEO prefers dash '-' over underscore '_'. Who am I to argue?
    • I'm also not going to include many other identifiers in filenames, like the resolution (1000x1000 as part of the filename for example).
    • One exception is I've been appending '-grid' to perfectly square images that I made at 1000x1000.
    • I created a masters folder in each project image folder to put the source files, before any editing, format changes, or compression. It has been added to .gitignore as **/masters.
    • The default resolution I'm going to use for source images is a maximum of 1600 pixel in either or both width and height.
    • The format will be jpg but at the highest possible quality setting.
    • Image files will also be run through ImageOptim at lossless to scrape out any extra stuff. Gatsby handles resizing and compression for specific images in the website so no reason to screw with it at this level.
    • Turns out, Automator is pretty amazing software on the Mac. I made a resize action in about 2 minutes with this Automator Image Resize Tutorial.
    • I then found this issue page for ImageOptim that allowed me to set up a single action for resizing and optimizing. I even added format conversion so I can bring in whatever files I want and convert + optimize them all in one go. The action I made is destructive however. So remember to only run it on copies.
      • Make sure to put actions in ~/Library/Services/
    • I wonder if I can have a single action create a png and jpg and then compare the filesize, keeping whatever is smaller?
  • I also started the process of figuring out how I'm going to deploy the website. Actually, that is what got me onto handling images, since I need to be able to do a full checkin to deal with deploy stuff. I have completed a base level conversion of images, enough so every project has a project image it can use so it doesn't have a '?' on the project list. I'm going to check things in now so I can test deploying today.
  • I fixed the problem I had with embedded media not parsing and/or code formatting. I simply wasn't formatting the list of remark plugins correctly. They needed to be in their own sets of brackets.
  • I added the new homepage. Simple but at least I have a source to work from now. I need to figure out getting an image inline, so text flows around it.
  • For now, I removed the circle that wasn't working around the social media icons. I didn't love it anyway. I also set them to justify left so it looks cleaner. They are as of now, good enough!
  • One of the gatsby-image settings (perhaps just a fluid setting of childImageSharp) is the cropFocus of an image. I had project headers set to cropFocus: CENTER but I'm going to try out cropFocus: ATTENTION which is described as "focus on the region with the highest luminance frequency, colour saturation and presence of skin tones"_ (as quoted on this image-processing gatsby website.
    • Very interesting but not overall best for project headers. Good to know though!
  • I added the project cards to skills / tags (along with general formatting) and I think I'll go that route. Need to clean it up a bit.
  • I added a nice little pixel jerry to the sidebar. Took a little googling to figuring out the divs and css classes but works great!
  • I need to add a generated 'award' section onto project pages, pulling from the YAML and using the laurel image.

April 11th, 2020

  • Before jumping into todays tasks, I had a thought. It would be really great if I could easily bring bullet journals for projects to the website. I'm not 100% sure where they should go, perhaps some sort of component on a project, or a proper 'blog' extending from project paths. I would need to find a workflow to handle the following:
    • Reasonably easily pulling content from OneNote and pasting into markdown.
    • I'd prefer to not have to split up entries manually, but still have the option of one 'stream' of entries or individually displayed entries.
    • Must be some way to parse from the entry dates as long as I'm consistent...
    • A component that that contains a single entry while allowing easy navigation other entries and permalinks to whatever...
  • I need to test pulling in content. There are probably some simple formatting things I can change to make conversion easier. Perhaps if I put code blocks in the entries they will just work.
  • Sigh. Ok, didn't do anything that was on my list. Just worked on code highlighting, but here is the process:
    • First go through OneNote and replace code notes with either inline backtick or with proper markdown code blocks (triple backtick + language, then code, then closing backticks).
    • Then copy/paste content from OneNote into something like Paste to Markdown to get something back reasonable.
    • It doesn't space bullets correctly so do a find/replace if possible. For indented bullets it seems to just leave a newline so it is easy to spot and manually fix. I think that is mostly it for reformatting.
  • I found a new notetaking tool to replace OneNote, at least for my bullet journals, so they can start as markdown: Boost Note
  • I can install on android, access online, work offline, and on macOS. This'll be nice for code / bullet stuff.
  • After trying a theme-ui solution for code formatting and barely getting it working (plus a lot of mess) I tried this much simpler gatsby-remark-prismjs plugin that worked reasonably well out of the box.
    • I followed the plugin page instructions and created a custom css file that I call from layout.js. This fixed most issues but overwrites the prism theme background-color so you have to manually reset it.
    • Change the background-color in the section below to whatever matches your theme, this color is from the okaidia theme:
.gatsby-highlight pre[class*="language-"] {
   background-color: #272822;
   margin: 0;
   padding: 0;
   overflow: initial;
   float: left; /* 1 */
   min-width: 100%; /* 2 */

April 10th, 2020

  • Got the social icon page working right away! I just had to fully reduce to:
const SocialIcons = props => ( HTML HERE );
export default SocialIcons;
  • I don't completely understand the different classes or objects I have to work with or what exactly to call things. I guess this is a Functional React Component Type?
  • Actually looks like I can do it the Class-Based React Component Type way where I define the component, a constructor, render function, and any other functions I want. That is found just below the Functional example in the Jennifer Wadella website in the April 9th bullets. Can still pass in props and then bind variables and whatnot. More than I need for this but cool.
import React from "react"

class Template extends React.Component {
   constructor(props) {
      this.coolFunction = this.coolFunction.bind(this)
      this.state = {
         stateToggle: true,

   coolFunction() {
         stateToggle: !this.state.stateToggle,

   render() {
      const conditionalClassName = 'state-class ' + (this.state.stateToggle ? ' thisclass' : '')

      return (
         <div className={conditionalClassName } id="conditionalThing">
            ... conditional content
  • Ok I went down a rabbit hole. I wanted social media to be dynamic. Have all the profiles in a json file with attributes, including links and the icon to use, but at least using react-icons I can't figure out how to just use the icon I want dynamically. For now I've actually gone back to the original method of displaying the icons that the theme I'm using used, linking directly to file URLs. I do that have working but I now need a new way to get images since I don't want online links for icons. Also the rollover CSS doesn't work with this method (or recoloring). BLARG.
  • Fuck yeah! I got it! The first real problem was realizing that just getting the
    to render wasn't enough because it isn't HTML, it's a React Component. React needs to know about it. After a bit more searching with that in mind I found this tutorial:

  • The project was extremely helpful. I suppose having nice tools for testing and developing web on the web makes sense. Basically I ended up creating an Icons.js that imports the icons needed (one for each social profile I might want up) and a map from the json profile component string to the imported icon component.
  • In essence the key is creating a component that you can pass in some data and use React.createElement to get the dynamic component you want back.
  • I still need to get the social icons to style properly... Ugh.
  • Perhaps if the <FaIcon> is conditionally rendered different colors depending on hover instead of trying to dynamically recolor it?
  • Then focus on:
    • A couple projects written in the new format
    • Formatting the rest of those projects with photos / etc.
    • Structure and draft the content for the about and home landing pages

April 9th, 2020

April 1st, 2020

  • In my quest to make it extremely easy to drop in images on project pages, I worked on figuring out how to put an array of filenames in the markdown frontmatter, verifying the files exist (if not putting a 'missing image' in their place) and feeding the list into some sort of gallery component. In this case called 'react-slick'.
  • I was successful! I'm getting the hang of working through node content in 'gatsby-node' and getting what I want out the other end. The next issue is in 'project.js' figuring out some JSX code that conditionally shows the gallery. If so slider images exist, don't show it!
  • Got it! I created a JSX function to called SliderGallery taking in slides = <SliderGallery slides={slides} /> and if slides is null, it returns null, otherwise it returns all of the necessary html.

March 31st, 2020

  • I'd like to note that when handling image paths from 'gatsby-node.js', you have to think about the image paths in two ways, at least with how I'm currently doing things.
    • First, in order for the image to be automatically found and turned into image data, the path must start from where the source file for the page it is used on is. Meaning, if the image is references in src/projects/ and the image is in src/images/projects/neat-thing/image.jpg, then the path should end up ../images/projects/neat-thing/image.jpg.
    • Second, to check if the file exists, because the context of gatsby-node.js is at your project root, you need to use the entire path In this case the path would be: src/images/projects/neat-thing/image.jpg and I'd call: fs.existsSync(path)
    • So you check one path and save the other using createNodeField.
  • The other thing to note. If you want access to the site metadata while in gastby-node.js, specifically in onCreateNode, you just call:
    • getNode('Site').siteMetadata
    • The getNode call gets the site node as you see it in gatsby-config.js - tacking .siteMetadata on the end is just a shortcut.

March 30th, 2020

  • Today was figure out how to pass data from a template like project.js to the markdown day! The most important piece is MDXRenderer. You pass it data you want to access within the markdown body, and then wrap the markdown body content within the tags:
<MDXProvider components={shortcodes}>
	<MDXRenderer fields={project.fields} frontmatter={project.frontmatter}>{project.body}</MDXRenderer>
  • So you see I had a project object with fields and frontmatter that I wanted access to in the markdown. Notice project.body, that is the markdown content here. The rest of the data is passed in with appropriate names and then accessible via props. For instance:
  • Not exactly markdown but I can drop that in to my markdown and it works. What if I want to use gatsby-image the great component for displaying images? I'll need access to the component in markdown. I can do this one of two ways. The first way (which Is evident in the example above) uses MDXProvider to pass in components. Wrap up MDXRenderer and in components provide an array of short codes. In the template js file (project.js in this case) at the top is: import Img from gatsby-image
  • The short code here is then 'Img', so somewhere else in the file I'd need to create something like: const shortcodes = { Img }
    • I can comma separate more codes if I want, so { Img, Slider } for example.
  • The other method is to simply put import Img from 'gatsby-image' directly under the markdown files frontmatter, at the beginning of the markdown.
    • Why not just do that? Well, the former method means I do this once in the template, the latter would mean putting that line of import code in every single markdown file that needs it.
  • Of course, part of the beauty of having such control over the template file and the markdown is that I can do a lot of the formatting and functionality in the template once and just put some frontmatter in the markdown files to configure it. Ideally the markdown space is as simple as possible and just about text formatting.
  • That said, using plugins like 'gatsby-remark-embedder' make working in markdown lovely because I can paste in a YouTube or Twitter link directly in and they will get processed nicely. In fact, most of the special processing I'm doing is just to take advantage of 'gatsby-image' and how it intelligently handles lazy loading, generating multiple image sizes, and other great features. Hopefully the rest can simply be not super invasive markdown based plugins.

March 22nd, 2020 - Catchup

  • One of the challenges I faces was the desire to only have to put in image filenames in markdown files but have them turn into image data when it came time to render, say in the project.js template. There are a few ways to handle this, but essentially, if the string is a valid file path, like an image, it'll get converted to a proper image node. So in gatsby-node.js in the onCreateNode function I build the paths, pulling in sitewide configurable path data in the site node in siteMetadata, I check that the file exists, and then I set the proper path in a new node field. This keeps the original string as it was, but Gatsby will find the new image path and turn it into an image ready to go!
  • Then I ran into another challenge. For markdown to be convenient, I need to be able to drop media and components into the markdown easily. Jekyll allowed you to bring frontmatter into the markdown and then through plugins (or theme features?) they would magically appear in some form, but it usually wasn't quite how I wanted it. So how do I get data into markdown in Gatsby??
  • The answer was switching from using the 'gatsby-transformer-remark' plugin to the 'gatsby-transformer-mdx' plugin. Plugins that exist to pull in and transform raw data to node data always (as far as I can tell) start with 'gatsby-transformer-' (including 'gatsby-transformer-json' and 'gatsby-transformer-yaml', the latter is the format frontmatter in markdown is). MDX is a new markdown spec that includes the usage of JSX, which is something something React and Javascript? Not sure but it feels a lot less messy that... the rest of the web. Ok! So MDX means markdown but now I can pass data in and use components! Great!
    • To access any data files you need the 'gatsby-source-filesystem' plugin. You then can define multiple source paths, including paths within paths you've already setup. Ex: you can source src/pages but also src/pages/projects which is what I originally did when using normal markdown. This was fine because I could simply add an ignore folder to the former so it didn't parse projects twice. The remark plugin let you handle all of the createPages stuff in gatsby-node.js, the second major functional aspect of that file.
    • Unfortunately, the mdx plugin likes to be a bit more helpful and it ignores the ignore folders, trying to be more automatic in generating pages I think. After a lot of fiddling around almost getting things to work as is (the order of filesystem config mattered and not colliding with the path it was generating on its own, but it was building extraneous paths/pages no matter what...)... I finally just moved projects up a level so filesystem was configured for src/pages for js based pages, src/projects for all my project markdown, src/images for alllll the images, and I could add more from there, probably src/data for any json/yaml raw data I want to pull in. This fixed my path generation issues and project pages were building fine again!

March 15th, 2020 - Catchup

  • I searched around and found a list someone put together of statically generated website tools and while in Thailand went through them all to see if there was a better way. I really liked Gatsby's Core Philosophy, especially the concept of progressive disclosure of complexity. I'm no dummy. I've been coding for many years. I just hate web tech because it is usually a MESS. React and other tools seems to be cleaning things up a bit, and a framework like Gatsby seemed like a great way to dip my toes in, get some things learning, want to make a change, and have a reasonable way to do that. Spoiler, I stuck with it!
  • I ended up working off of a simple portfolio website (github link). Looks nice, displays lists of projects in a pleasing way, and simple enough to dig into and understand. The most interesting challenge was that it is designed to pull data from an existing CMS where I only want to pull data from my own markdown files (or JSON / YAML / etc.). I had to wrap my head around the plugin and component system so I understood what pieces were connected to the CMS and where I could start changing the data source. The biggest lessons were better understanding 'gatsby-config.js' and 'gatsby-node.js', the former being where you select plugins and configure them, the latter being where you can analyze the node data structure and modify it, then select templates that will be used to generate the final web pages. That is a huge simplification, but more or less it.
  • The tool that really convinced me Gatsby is a great way to go is the GraphQL data language and GraphiQL interactive query tool. The ability to define and debug queries to see if the data is even getting to the page that is failing to render is huge. I absolutely love it. Like any database / query language it tool some messing about to understand but it wasn't very complicated.

January, 2020 - Catchup

  • I started working on a new website... a few months ago in earnest? I think with the new year. I had been trying to work with Jekyll again because I had made a few websites with it during my MFA for assignments. At the time it worked fine, I found templates that looked nice enough and made the information fit the mold. Unfortunately Jekyll is rather opaque and it doesn't make it easy to understand what is going on under the hood unless you are already a proper web dev (which I'm not). I was getting increasingly frustrated because it was too much work to make changes to any themes/templates, taking Jekyll from easy to hard very quickly if you didn't like things exactly how they already were.