Silly Site Challenge-image

Silly Site Challenge

Date published: 27-Nov-2020
Date modified: 21-Dec-2020
14 min read / 3838 words
Author: Paul Scanlon
Gatsby
React
TypeScript
JavaScript
Theme UI
SVG
Netlify Functions
GitHub REST
BumHub The cheekiest way to explore GitHub
A#SillySiteChallengeby@PaulieScanlon
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.

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 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.

Reactions

Loading...

Newsletter

This is a sign-up to Queen Raae's Gatsby Newsletter because I don't really like people, or emails. She'll let you know when I have something new to share!

Pay what you want

If you've enjoyed this post you can make a secure contributionPowered by Stripe - blurple
$