By Paul Scanlon

Silly Site Challenge

  • Gatsby
  • React
  • TypeScript
  • JavaScript
  • Theme UI
  • SVG
  • Netlify Functions
  • GitHub REST

BumHub The cheekiest way to explore GitHub

šŸ‘ Visit BumHub

Go Go Go

Nov 23 2020

Iā€™m at it again šŸ•ŗ

If you followed along when I did my 100 Days Of Gatsby youā€™ll know I have a tendency to write way too much about very little šŸ˜„

ā€¦ but because 100 Days Of Gatsby was an absolute tray of cakes Iā€™m super excited to be doing it again for the recently announced Silly Site Challenge

If youā€™d like to know more about the challenge hosted by Gatsby have a read here and be sure to follow GatsbyJS on Twitter or search for the hashtag #SillySiteChallenge

This time round Iā€™ll be doing things a little differently because updating a blog post every day for 100 days was, as youā€™d imagineā€¦ an absolute ball ache!

Instead iā€™ll update less frequently but with more significant informationā€¦ deal?

Greatā€¦ see you around!

Update 1

Nov 24 2020

I donā€™t wanna give the game away so hereā€™s a little teaser about whatā€™ll iā€™ll be working on.

Update 2

Nov 26 2020

I thought this update might dive into my process a bit. I still donā€™t want to give the game away by sharing too many visuals but there were a number of things I needed to work on before I announced iā€™d be taking part in the Silly Site Challenge

The reason for this is because the idea I have largely depends on two key things.

    1. Can I get my pea brain around the GitHub REST API docs
    1. Can the GitHub REST API return data I can use?

Iā€™ve spent about a week investigating this and I suppose in agile terms this might be known as a Spike.

If youā€™re not familiar with agile ways of working a spike can be used where the outcome of a thing is uncertain and needs to be investigated before everyone gets too excited and starts presenting ideas to stakeholders.

Now, granted my puny Twitter following is hardly the same as having commercial stakeholders but the theory is the same. I didnā€™t want to announce I was going to do something until I was sure I could deliver.

Iā€™m pleased to report that I have been able to understand the GitHub REST API docs and it can return data I can use to bring my idea to life.

There was also a second spike required for my ideaā€¦ and try to follow along as my mind unravels.

As you might know Gatsby recently announced the new Routes API and I was going to write a blog post about that and perhaps provide a working demo link and repositoryā€¦ but then I thought to myself;

No Paul, thatā€™s not good enoughā€¦ write an entire application, develop it in public and somehow weave it into the #SillySiteChallenge

So thatā€™s what iā€™ve been doing. The new Routes API is amazing, and I have already seen a few Tweets and posts from folks explaining how it worksā€¦ however, and this isnā€™t to knock anyoneā€™s hard work, these examples all seem to be regurgitations of the the Gatsby docsā€¦ and because I like to make my life difficult I started to think about ways to make my demo of the Routes API a bit different. Then it hit me.

Thereā€™s a section in the docs that says the following:

Use the File System Route API when you want to programmatically create pages from your GraphQL data, e.g. to create individual blog post pages for your blog. With this API you can control the file path and queried data by adding some extra notation to the names of your files without touching or creating gatsby-node.js whatsoever.

The key part is this bit ā€œwithout touching or creating gatsby-node.js whatsoeverā€. This statement is 100% accurate but it only applies if you already have the nodes in the GraphQL layer. This would be possible if you had a load of pages as actual files on disk, eg. .js, | .tsx | .md | .mdx butā€¦

What if your ā€œsite contentā€ doesnā€™t exist on disk? What if your ā€œsite contentā€ comes from a remote source, a CMS for example, or in my case a RESTful API. In this scenario you will absolutely need gatsby-node.jsā€¦ and therein lies an angle for my silly site idea.

Iā€™ll be using a remote RESTful API to source data using gatsby-node.js which creates the nodes in the GraphQL layer and THEN I can use the new Routes API to create pages from those nodesā€¦ simple eh!

But when I conjured up this elaborate plan I wasnā€™t sure if it would workā€¦ hence the second spike.

Ok cool, so now the idea is coming together, I can create pages from remotely source data at build time and iā€™ll be able to do something with itā€¦ but what data? all I want to say at the moment is it has something to do with the word ā€œbumsā€ā€¦ because bums are silly!

Naturally ā€œbumsā€ might be considered offensiveā€¦ I donā€™t know how exactly, but It would be prudent to tread carefully so Iā€™ve now entered into the art direction phase of the project.

I need something that looks and feels funā€¦ just like a bum. Iā€™ll be honest my designer days are long behind me but I do still have an eye for it so I spent a few days researching illustrators on dribbble and found this cheeky little ghost by the wonderful Miss_ChatZ so Iā€™ve gone ahead and commissioned her to create a logo and some ancillary character illustrations.

The reason for this is thereā€™s another twist to my silly site idea. Since iā€™ve decided to develop in public iā€™d like to start sharing a dev link of my progress butā€¦ to keep you all interested the site will automatically and progressively get more interesting throughout December, Iā€™ll say no more for now.

Then lastly. Because Gatsby is predominantly a static site generator (it can do much much more FYI) it is by itā€™s very nature quite Eco-Friendly and by this I mean because the grunt work is handled server side at build time rather than by each and every browser that visits your site at run time much less of the worlds power is used up. Much less power means much less CO2, and much less CO2 makes for a healthier planet.

I should point out here iā€™m not attempting to say ā€œIā€™m making the world a better placeā€ā€¦ iā€™ll leave that to the tedious Twitter rock stars and the writers of Silicon Valley who made it into a very funny joke!

Instead I plan to surface some of this Eco-Friendly data by leveraging statistics provided by EcoPingā€¦ This one is a bit up in the air at the moment but Iā€™m in discussions with the makers and hope to have some firmed up answers soon.

So there you go, as promised a slightly more in depth update and I hope iā€™ve piqued your interest.

If youā€™re interested in taking part in the #SillySiteChallenge hereā€™s the sign up link again. www.gatsbyjs.com/silly-site-challenge

Stay silly everyone šŸ˜˜

Update 3

Dec 2 2020

I feel like iā€™m really making progress now, so much so iā€™m now happy to share a link šŸ•ŗ

Iā€™ve continued to work with the magnificent Miss_ChatZ whoā€™s delivered the first of the characters iā€™ll be using on BumHub, aptly named Pants Down and Pants Up which are used in the Advent Calendar cards.

Pants Down is used when an Advent card is click-able which is determined by working out if itā€™s the current day or if the day has passed.

Pants Up is used when an Advent card is disabled which is determined by working out if the day number is in the future.

Iā€™ve also added the custom components to the Bum UI page where you cam see how the components look and how they can be configured with props.

The current date is provided by my api so you wonā€™t be able to cheat it by changing your system clock! In the short term though this might cause a bit of a hiccup.

The data required to populate the Advent Cards is actually sourced at build time so in theory no JavaScript is required for these to render on the page butā€¦ because this is an Advent Calendar I only want to reveal a card when itā€™s the current day therefore JavaScript is required to make the api call to get the current server date. I think iā€™ll leave this as is for now as itā€™s part of the charm of an Advent Calendar but, after Dec 25 thereā€™s no need to disabled any of the cards so Iā€™ll remove the api call so this page will continue to work even if JavaScript is disabled.

Iā€™ve also added a bit of pure CSS animation to the starburst seen behind the main logo. This was achieved using some fun nth-of-type selectors and animation-delay durations. You can see the src here. I hadnā€™t actually tried to use animation keyframes in Theme UI before but having had a look at the src I could see how Theme UI have achieved this in the <Spinner /> component.

Iā€™m hoping to tackle the EcoBum section next. I have it on good authority that EcoPing are in the final stages of testing the special endpoint required to calculate BumHubs carbon usageā€¦ in human farts no less!

Usually I donā€™t love the art direction part of my side projects but this time round iā€™m really enjoying seeing what Miss_ChatZ creates and when I add them to the design it suddenly springs to life.

Iā€™m also really happy I completed the two spikes as mentioned before because iā€™m now 100% sure that I can work with the data Iā€™m receiving which makes the UI development an absolute breeze!

Stay tuned and iā€™ll update this again when iā€™ve completed the next phase of development.

Update 4

Dec 3 2020

I had a good hack on BumHub last night and dusted off my PhotoShop skills and designed the /bums/-name-of-repo page template.

This is the part of BumHub that uses Gatsbyā€™s new Routes API.

As mentioned below, the docs say you no longer need to touch gatsby-node to create pages butā€¦

In my case because iā€™m sourcing the data at build time I still need gatsby-node to create the GraphQL layer from the GitHub REST response but, once the data is in ā€œGatsby worldā€ the new Routes API takes over.

You can see the src here, youā€™ll notice the name of this file is {adventBums.name}.tsx, the bit between the curly brackets is a node from the GraphQL layer I create in gatsby-node followed by .name which is a key in the response object.

This NASA level regex is how the Gatsby engineers allow us to create pages from nodes, or in my case nodes that are repository names sourced from GitHub. Thanks Gatsby engineers, this is some top shelf tekkers!

The Jsx in the ā€œpage templateā€ is populated by using a good old fashioned Gatsby page query plus the node $id, that part is actually old school Gatsby but I do really like the new Routes API, using createPages in gatsby-node was always a bit of faff.

This latest feature completes my rather ambitious goal of weaving multiple ideas together to form one entity worthy of a#SillySiteChallenge submission and the Routes API was always at the core of this so iā€™m pleased it works, itā€™s styled and is out there for all to see. šŸ•ŗšŸ»

Update 5

Dec 8 2020

This update is a bit of A Tale of two Cities. A city called client side and a city called server side.

Letā€™s start with the client side.

I normally use the Fetch API, in fact I love Fetch, itā€™s native to modern / non crappy browsers (IE iā€™m talking about you!) and from what I gather pretty lightweight and lastly, it gets the job done. Butā€¦

Fetch runs in / on the Window object and it canā€™t be used server side to make HTTP requests.

So what about server side?

The server side equivalent is Nodeā€™s http module which is built in to Node and does indeed also get the job done.

ā€¦but this want to use native functionality poses a problem for the Jamstack developer. If like me youā€™re in a situation where you have a requirement to make both client and server side http requests do you opt to keep things native or do you opt for a solution that works consistently across the stack?

For BumHub iā€™ve gone for consistency.

Iā€™ve chosen to use axios.

I wouldnā€™t normally choose this but it can run both client and server side which means my http requests can be written in a consistent fashion. For me on this project, this matters.

Jamstack development requires the humble Front End Developer to be many things and quite frankly itā€™s sometimes too much for my pea brain to take. I feel like I have enough to worry about just making sure my CSS works across the million and one screen sizes that exist. I donā€™t need to be worrying about really dweeby http request methods. If axios can do what it does in the same way when running in Node (server side) as it can in browser (client side) and can be written the same in my project on both sides of the stack then iā€™m happy to let sleeping dogs lie and crack on with the good stuff.

Thatā€™s my opinion there are many other valid ones.

That said I now need to do a bit of refactoring to my <MrFetchy /> component as it currently uses fetch not axios.

The reason for this quandary is that in this update iā€™ve implemented the EcoBum section which utilizes a special end point created for me by my pals at EcoPing. This endpoint is still experimental so exposing it client side might cause some headaches. Instead, iā€™m making the request server side and storing the request address in an environment variable so it stays a secretā€¦ for now, and because Iā€™m making the request server side I need some kind of http request methodā€¦ actually this update is quite dweeby, sorry about that.

Anyway, thereā€™s now a Bum on the index page farting and some lovely eco friendly stats about BumHubā€™s carbon usage.

Enjoy.

Update 6

Dec 10 2020

Not a major update here butā€¦ Iā€™ve been playing around with ways to document the components used in BumHub.

For now at least I have a kind of style guide page which lists each component from BumHub and itā€™s props.

Further down the page iā€™ve started to do the same with the components that ship with Theme UI

If you havenā€™t used Theme UI before iā€™d recommend giving it a go. It is IMO the original and best take yet on CSS-in-Js not just because it thankfully moves us away from class namesā€¦ and we all know namings things is hard but because it blows my mind the way Brent Jackson re-imagined style systemsā€¦ and the best of all these new school methods is what I refer to as the [Responsive Array Syntax](https://paulie.dev/posts/2020/08/Styled Components-responsive-array-syntax/).

With Theme UI you get all this goodness out of the box, in the above blog post I explain how you can achieve a similar thing using [Styled Components](https://Styled Components.com/) but it does seem like a faff to roll your own when Theme UI gives it up for free.

Iā€™m not sure how popular Theme UI is amongst React Devs, I see a lot of chatter about Tailwind but because I know CSS Iā€™ve never felt it was a good fit for me. Theme UI on the other hand provides just the right amount of opinions and restrictions. Iā€™ve built loads of sites/apps/blogs with Theme IU in the last couple of years and so far iā€™ve not found anything it canā€™t do.

In any case, youā€™re free to choose whichever CSS solution youā€™re most comfortable with but for me iā€™m a 100% Theme UI fan boi!

Thanks Jackson, youā€™re the best!

Update 7

Dec 14 2020

Bum Search section is done āœ…

When I first started thinking about an idea for the #SillySiteChallenge I wanted to demonstrate what I would refer to as ā€œapp likeā€ functionality, purely because I regularly see comments on Twitter suggesting that Gatsby is just for blogs. Iā€™ve never understood this.

From the very start of my love affair with Gatsby Iā€™ve understood Gatsby is React. Iā€™m not sure how this point gets missed, perhaps Gatsby donā€™t make a strong enough point about it or perhaps thereā€™s not enough examples of applications built with Gatsby.

Iā€™m not sure for the reason but itā€™s my hope by creating the Bum Search page itā€™ll at least go some way to voicing my opinion that Gatsby is React.

The Bum Search section features a fully functioning Search input, with a Select to change which value from the data you want to filter on, along with table column sorting functionality so users can explore the full data set returned by GitHub.

Arguably in BumHub this kind of functionality isnā€™t all that useful but it does, as mentioned above demonstrate that itā€™s possible to do such things with Gatsby plus it demonstrates my ability to use array methodsā€¦ hopefully that second point might allow me to swerve pointless tech tests when applying for future jobs or contracts. šŸ•ŗ

This latest update pretty much completes my ā€œMVPā€ but iā€™ve had another idea, itā€™s again grounded in my desire to demonstrate Gatsby is React and can do all the things that a straight up React App can do so stay tuned and iā€™ll be back with another update in a week or so.

Update 8

Dec 21 2020

šŸšØ BRAND NEW FEATURE ALERT šŸšØ

Pleased to present Bum Bum Maker and cooorrr blimey guvā€™nor this was a lot of work!

As I mentioned in Update 7 I wanted to make a bit more of a point regarding what you can do with Gatsby, and the TLDR version isā€¦ anything you damn well please. Gatsby is built on top of React so if you can do it with React you can do it with Gatsby.

Bum Bum Maker is an interactive character chooser tool, and it works like this.

I have a React component called <MakerBum /> which receives a config array which looks a bit like the below

iā€™ve removed some of the options for brevity FYI

// src/plages/bum-bum-maker.tsx

export const bumBumConfig = [
  {
    name: 'face',
    ...
    options: [
     ...
      {
        label: 'beard',
        value: 'beard',
        checked: true,
        meta: {
          type: 'image',
          value: '',
        },
      },
    ],
  },
  {
    name: 'miscellaneous',
    ...
    options: [
      ...
      {
        label: 't-shirt',
        value: 'tshirt',
        checked: false,
        meta: {
          type: 'image',
          value: '',
        },
      },
    ],
  },
  {
    name: 'head',
    ...
    options: [
      ...
      {
        label: 'glasses',
        value: 'glasses',
        checked: false,
        meta: {
          type: 'image',
          value: '',
        },
      },
    ],
  },

  {
    name: 'accessories',
    ...
    options: [
      ...
      {
        label: 'coffee',
        value: 'coffee',
        checked: false,
        meta: {
          type: 'image',
          value: '',
        },
      },
    ],
  },
  {
    name: 'tone',
    ...
    options: [
      ...colors.tone
        .map((item): string => item.mid)
        .map(
          (item: string, index: number): IMakerConfigOption => {
            return {
              label: `${index}`,
              value: `${index}`,
              checked: index === 3,
              meta: {
                type: 'swatch',
                value: item,
              },
            }
          },
        ),
    ],
  },
] as IMakerConfigItem[]

Thereā€™s a couple of reasons for this. Firstly and, this is quite common in ā€œapp likeā€ development, the UI is usually driven by data, Bum Bum Maker is no different. I have a list of Radio buttons grouped together for each part of the bum, eg. Head, Face, etc and using a top level name key means I can leverage normal HTML Radio behavior by grouping them together thus only allowing one Radio from each part to be selected at any given time.

The individual options themselves accept a label, value, and a default value for checked. Iā€™ve also added a meta key. This is how I determine if the list items are to have a little graphic of the value or a tone swatch.

The tone hex reference comes from the tone key in Theme UIā€™s color object. The reason for directly referencing the color object in this way means that if I were to add a new tone to the theme the list would automatically display a Radio button for itā€™s given valueā€¦ nice ey!

Using a config object like this is great for the Bum Bum Maker page elements but itā€™s a bit verbose to drive the SVG conditional <g> renderingā€¦ allow me to explain.

By using my old chum Array.prototype.reduce and Array.prototype.filter I can ā€œloopā€ over the items in the bumBumConfig array and reduce the array down so it only contains the names of the options that have checked: true

// src/components/maker-bum.tsx

const getCheckedProperties = (config: IMakerConfigItem[]) => {
  return config.reduce((items, item) => {
    items.push(item.options.filter((option) => option.checked).map((option) => option.value)[0]);
    return items;
  }, []);
};

This results in a new array of strings for each option that is checked eg

// (results array)
['beard', 'noMiscellaneous', 'headphones', 'laptopStickers', '3'];

Then I can use these values to pick a key from a properties dispatch tableā€¦

again iā€™ve removed a lot from the below example for brevity

// src/components/maker-bum.tsx

const properties = (property: string, tone: number) => {
  const config = {
    ['beard'] :(
      <g>...</g>
    )
    ['headphones'] :(
      <g>...</g>
    )
    ['laptopStickers'] :(
      <g>...</g>
    )
  }

  return config[property] ? config[property] : null

}

export const MakerBum: FunctionComponent<IMakerBumProps> = ({ config }) => {
  return (
    <svg
      version="1.0"
      x="0px"
      y="0px"
      viewBox="0 0 550 410"
      width="100%"
      height="100%"
    >
      {getCheckedProperties(config).map(property => properties(property, tone))}
    </svg>
  )
}

For the values contained within the new array I return the SVG <g> element(s) and for values that arenā€™t I return null. This allows me to conditionally render all SVG <g> elements that together form the SVG you see in browser.

If you open up your developer tools and find the SVG element, then click around on the Radio buttons youā€™ll see the SVG re-renders itā€™s child <g> elements according to the checked values provided by the Radio buttons. I typically use this approach in my day job to build complex web applications for companies that make bazillions that no one cares about but here iā€™m using the same approach to conditionally render an SVG Bum graphic which really puts the fun into Functional Programming.

The fruits of this labour intensive task result in a fun UI with an added treat for the user allowing them to download their custom bum graphic as a bitmap in 16:9 aspect ratio, perfect for sharing on Twitter.

This feature was a bit of a last minute idea but iā€™m pretty pleased with the outcome. Itā€™s purely luck that all the separate parts of the illustrations work together in any given order as this wasnā€™t part of my original brief to Miss_ChatZ

Having reviewed the Pre-submission checklist iā€™ve also been working on accessibility and performance and one thing I noticed on the home page was a warning about maximum DOM depth, this was due to the amount of Pants Up / Pants Down bums iā€™m rendering for the advent calendar. A relatively quick fix for this was to limit the amount of Advent Cards to render on initial page load.

Iā€™ve achieved this by utilizing Array.prototype.slice. Hereā€™s the code but in short depending on if the state value isAdventExpanded is true or false I either render the full array or slice the array from -2 indexes from the current day + 2 indexes which gives me a day before the current day and 2 days after the current day or simply just x4 Advent Cards. This has improved the lighthouse scores too.

An added bonus to this fix is that the UX has slightly improved because the user now doesnā€™t need to scroll quite so far to see the other sections in the page, Bum Search, Bum UI etc.

I also popped a little useLocalStorage hook in for the isAdventExpanded value. This is so the page remembers if you were or werenā€™t in the expanded state when you navigate to and from the index page.

Iā€™m not sure thereā€™s anything left to do now so dare I say itā€¦ but, I think iā€™m done! šŸ•ŗ

Update 9

Dec 23 2020

Today iā€™ve pushed a couple of small changes. BumHub now has a footer section outlining roles and responsibilities on the project along with a shout out to my internet friends.

Because I use Theme UI this kind of UI work literally takes seconds. Itā€™s actually more work to create a git branch and a PR than it is to create two new sectionsā€¦ well a <section /> and a <footer /> if weā€™re to be semantically correct.

ā€¦ and I canā€™t think of anything to say about todays update.

Hey!

Leave a reaction and let me know how I'm doing.

  • 0
  • 0
  • 0
  • 0
  • 0
Powered byNeon