Jan 28, 2020 4 min read

devLog: 2020-01-28

Table of Contents

New theme development (nightCasper): CSS w/ flexbox, JavaScript conditionals, and Handlebars.js templates.

New Theme Development

As you may have noticed, I tend to write lengthy introductory guides. I think it's important to not only understand how to do something, but even more importantly to understand why you're doing something and how it works. This additional knowledge allows you to not only adapt the guide to your specific situation, it also allows you to troubleshoot issues when something goes wrong. This leads to those lengthy guides where I combine not only the steps for how to do something, but also the background information necessary to understand why you're doing it.

The problem though is that, as you start to read, it can become easy to get lost in the guide. Both in terms of the superficial, "I need to scroll up to see where I am", and the more genuine, "how does the concept I am reading about now, relate to the rest of the information in this article". As I encountered both of these thoughts when reading my own articles (I originally started this blog as a notebook to keep track of stuff that I had implemented and might need to reference later), it became more and more apparent that this blog desperately needed a table of contents. Enter, nightCasper, the new theme that I have developed as a fork from Ghost's Casper.

nightCasper

Overall, I really like Casper, Ghost's default theme. There are just things I wish it had to make it more suitable to me and my audience. Therefore, I decided to fork Casper on GitHub, creating nightCasper. nightCasper contains the following features:

  • Dark theme always on
  • Sidebar
  • Table of Contents
Torqu3Wr3nch/nightCasper
The default personal blogging theme for Ghost. Contribute to Torqu3Wr3nch/nightCasper development by creating an account on GitHub.

Challenges

Full-width images

Casper (Ghost's default theme), defines a full-width image in CSS as 100vw, i.e. 100% of the viewable window. Reasonable, since that would be the definition of a full-width image. The problem is that nightCasper is a flexbox container with two columns: the sidebar and the content. Since I have pegged the sidebar flex to a width of 15vw, that means the content flex item simply needs to be adjusted to the balance of 85vw (100vw - 15vw = 85vw).

Not All Posts Require a Table of Contents

Another problem I faced when designing this theme was that not all of my posts have multiple headers in them, specifically the quick start guides, which may have, at most, one header. In these cases, it would be silly to display a Table of Contents to the reader.

<script type="text/javascript">
    var toc = document.getElementById('toc');
    toc.innerHTML = getTocMarkup(document);
</script>

The way the original table of contents code (above) works is by looping over the headers in a given post and generating a series of anchor links to them. This is returned by the above function, getTocMarkup(document).  The inner HTML of the "toc" element, which up to this point has just been an empty shell, is replaced with this new set of links.

However, in the event getTocMarkup encounters a quick-start guide, not meeting the minimum threshold of two headers, it returns nothing. This would be fine, if not for the fact that the sidebar itself is still present and, being blank, gives the post the appearance of being offset 15% to the right:

Developer tools might make this more apparent:

Thankfully, this is easily resolved with a bit of JavaScript:

<script type="text/javascript">
    var toc = document.getElementById('toc');
    toc.innerHTML = getTocMarkup(document);
    if (toc.innerHTML == "") {
        document.getElementById('sidebar-container').style.display = "none";
    }
</script>

The addition of the above if statement checks to see if getTocMarkup returned nothing. If it did, it simply collapses the sidebar-container by setting its style (CSS) to display="none".

Man, I love JavaScript. She can really get you out of some binds. She's especially useful for when you are simply the receiver, and don't necessarily have any control over some input you're about to receive, or in cases such as this,when you don't have the data you need prior to runtime. This comes in especially handy when using the Ghost CMS since all of its pages are dynamically rendered. I don't actually have access to an article's content itself until the page is rendered, therefore I can't simply check for headers in the article and dispose of the sidebar when they don't exist prior to page load.

Flexbox Truncates Child Elements

While working to make sure my new theme maintained its responsiveness to different display windows, I noticed that as I shrunk the screen horizontally, the post content stored in the flex child would get truncated. Not only that but, when I inspected with Chrome Developer Tools, Flexbox seemed to be miscalculating the width forcing the div to be wider than the actual viewable window (which was, of course, causing the truncation). In other words, my flex child was being blown out the side of the window.

Thankfully, I stumbled upon this reference here, discussing this exact issue where Flexbox prevents a container from narrowing. This was resolved by setting a min-width in the flex child ("content-body" in my case):

#content-body {
    flex: 1 1 auto;
    min-width: 0;
}

Wrap-Up

Well, that's it. Hope you like the new blog theme and, if you like it, you're welcome to check it out on Github and use it in your own blog.

If you have any questions or want to discuss my design choices, I'm eager to hear from you. Let me know what you think of the new theme in the comments below!

Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to The Engineer's Workshop.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.