THOUGHTS, STORIES AND IDEAS

To style this Ghost blog I purchased the theme Nurui made by fueko, because I really like its style. Nevertheless there are some things I customized to make it even better. In the following I'll show you which changes I made and how I did them.

Add a Table of Contents

As especially my previous post is really long I decided to display a small Table of Contents (ToC) on top of (nearly) every post. This ToC should be there automatically and only be hidden, if the tag #no-toc is added to the post.

To add the ToC the theme itself had to be changed. Therefore the first step was to download and unzip the theme.

The ToC is generated with Tocbot, which is very easy to set up. First I linked its stylesheet in the <head> section of the default.hbs file, just before the stylesheet of the theme itself is linked:

<head>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.10.0/tocbot.css">
    <link rel="stylesheet" type="text/css" href="{{asset "css/screen.css"}}">
	{{ghost_head}}
</head>

Then I added the script tag and initialized Tocbot at the end of the <body> section, just before {{ghost-foot}} is rendered:

<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.min.js"></script>
<script>
	tocbot.init({
		tocSelector: '.toc',
		contentSelector: '.post-wrap',
		hasInnerContainers: true
	});
</script>
{{ghost-foot}}

Adding this code to the theme enabled me to add a ToC to any post just by adding a HTML block with the following code to the post.

<aside class="toc"></aside>

That would have been already a quite good solution, but I still decided to move on because I wanted to add the ToC automatically to all posts. Further I wanted to apply some styling to integrate it nicely to my blog.

NOTE: If you are following my instructions and the functionality I implemented until now is enough for you, you can simply inject the above shown code into the header and footer section via the Ghost admin panel in the 'Code Injection' section. Then you wouldn't have to touch your theme at all.

Automatically add the ToC to all posts

To add the ToC on top of all posts the template file for a single post, the post.hbs file, has to be changed. This is where the post content will be rendered with the {{content}} Handlebars helper which is provided by Ghost. So in the first iteration I simply added <aside class="toc"></aside> before rendering the post content with this helper. That was of course working, but I didn't like it, as I wanted to show a little introduction paragraph above the ToC.

That's when a second file came into the game: the assets/post.js file. There I added the below code to manipulate the post content and insert the ToC above the first heading instead of displaying it on top of the whole post.

const postContent = document.getElementById("post-content").innerHTML
if (postContent !== null) {
    const indexOfFirstHeading = postContent.indexOf("<h")
    const postIntroduction = postContent.substring(0, indexOfFirstHeading)
    const postText = postContent.substring(indexOfFirstHeading)

    document.getElementById("post-content").innerHTML =
        postIntroduction // introduction paragraph -> everything before the first heading
        + "<aside class=\"toc\"></aside>" // Table of Contents
        + postText; // post content from the first heading on
}

To make this code working the {{content}} in the post.hbs file had to be wrapped with a div with the id post-content as you can see below. Further the line with <aside class="toc"></aside> was not necessary anymore, as the ToC is added when manipulating the DOM with JavaScript.

<div id="post-content"> {{!-- Wrap the content in a div to identify the element with javascript and manipulate it there--}}
	{{content}}
</div>

Now the Table of Contents is displayed before the first heading of every post.

Hide the ToC with a custom tag

As the Nurui theme uses a lot of tags to style posts and the page itself (e.g. to set the dark theme), I decided to create a tag to hide the ToC. This tag is #no-toc. If this tag is set, the table of contents won't be rendered on top of the post. This was quite easy to set up with the #has Handlebars helper Ghost provides. So I'm checking if the #no-toc tag is there and if yes, I'm wrapping the {{content}} with the required <div>, otherwise I'm just rendering it without the <div>. When doing so, the div can't be found when manipulating the DOM and therefore nothing will be changed in the post content and no ToC will be displayed.

{{#has tag="#no-toc"}}
	{{content}} {{!-- No div needed because, the content won't be manipulated --}}
{{else}}
	<div id="post-content"> {{!-- Wrap the content in a div to identify the element with javascript and manipulate it there--}}
		{{content}}
	</div>
{{/has}}

Style the ToC

Hide subheadings

As I'm (nearly) always displaying the ToC at the start of a post, it should be as short as possible to still be helpful. To achieve this goal, I decided to only add <h1> and <h2> headings in the ToC. Adding the following line to Tocbot's init method did the trick.

headingSelector: 'h1, h2'

Add a title

My next step was to enhance the ToC a bit more by displaying a title that says "Contents" above it. The first step was very easy, I simply had to add <h2>Contents</h2> before adding<aside class=\"toc\"></aside> in assets/post.js. Basically this would be enough, but now "Contents" is also shown in the ToC, which is not necessary. To remove it, I wrapped the post content in a <div> with the class post-content. This could have been any css class name that is not in use in the project yet, but post-content seemed like a good and describing name to me. The updated code looks like that now:

document.getElementById("post-content").innerHTML =
	postIntroduction // introduction paragraph -> everything before the first heading
	+ "<h2>Contents</h2><aside class=\"toc\"></aside>" // ToC and its title
	+ "<div class=\"post-content\">" + postText + "</div>"; // Wrap the post content in a div to exclude the title of the ToC from the ToC

With that change made, I could tell Tocbot to just read the headings inside this class by setting contentSelector: '.post-content' in the init method in the default.hbs file. The full init method looked like this now:

tocbot.init({
	tocSelector: '.toc',
	contentSelector: '.post-content',
	headingSelector: 'h1, h2',
	hasInnerContainers: true
});

The last thing to style the ToC was to change the highlighting color of the active link item to the primary color of the blog. I did that by adding the following code in assets/css/sreens.css.

.is-active-link::before {
   background-color: var(--color-details);
}

Style the headings

The different sections of a post, which are "divided" by <h2> headlines, seemed a little bit close together to me. Therefore I decided to add a padding of 32px on top of each <h2> tag by editing the css style in the file assets/css/screens.css in line 304. Doing this only adds the margin on big screens, to also edit the small ones you would need to edit the @media queries a little bit further below. I didn't do this, because I liked how it looks on smaller devices.

h2 { 
   font-size: 40px;
   margin-top: 32px;
}

Add a 'Back to Top' Button

On the bottom right of all my posts you can see a little 'Back to Top' button after scrolling a bit down. I added this button with 3 steps: adding the button to the post, implementing the logic of the button and styling it. In the following I'll describe those steps in detail.

To add the button to the post itself, I added the following code to the post.hbs file after the {{ content }} is rendered.

<span onclick="goToTop()" id="goToTopButton" class="go-to-top-button"/>

As you can see the button will now invoke the function goToTop() when the user clicks it. Therefore I added this function to assets/js/post.js. The implementation of the function and some necessary helpers are displayed below.

//Get the button:
goToTopButton = document.getElementById("goToTopButton");

// When the user scrolls down 200px from the top of the document, show the button
window.onscroll = function () {
    if (document.body.scrollTop > 200 || document.documentElement.scrollTop > 200) {
        goToTopButton.style.display = "block";
    } else {
        goToTopButton.style.display = "none";
    }
};

// When the user clicks on the button, scroll to the top of the document
function goToTop() {
    document.body.scrollTop = 0; // For Safari
    document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
}

Now the only thing left to do is, to style the button by creating its class in assets/css/screen.css.

.go-to-top-button:hover {
   border-top: 0.3em solid var(--color-details);
   border-right: 0.3em solid var(--color-details);
}
    
.go-to-top-button {
   display: none;
   content: '';
   position: fixed;
   bottom: 20px; 
   right: 30px; 
   margin-top: 1.4em;
   width: 1.4em;
   height: 1.4em;
   border-top: 0.3em solid #333;
   border-right: 0.3em solid #333;
   -moz-transform: rotate(-45deg);
   -webkit-transform: rotate(-45deg);
   transform: rotate(-45deg);
   cursor: pointer;
}

Use the automatic dark version of the theme

To use the dark version of the Nurui theme you just need to add the tag #dark-version to any post. But to me the preferable way is to only use the dark version if the user is using a dark theme in his browser. Therefore I added #auto-dark-version to this post instead of the above described tag.

Style code blocks

There is not much to say about how I styled my code blocks as I exactly followed this tutorial.

Below I will show the code I injected in the admin panel. The only change I made is that I used the funky theme instead of tomorrow and thus replaced the background color with #000 to match the theme color.

NOTE: You could also add this things to your theme directly but I wanted to make it very easy to change the code block style in the future.

Header section:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism-tomorrow.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/line-numbers/prism-line-numbers.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.19.0/plugins/toolbar/prism-toolbar.min.css" />
<style>
    pre[class*=language-] {
        background: #000;
    }
</style>

Footer section:

<script>
    window.addEventListener('DOMContentLoaded', (event) => {      
        document.querySelectorAll('pre[class*=language-]').forEach(function(node) {
            node.classList.add('line-numbers');
		});
        Prism.highlightAll();
    });
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.19.0/plugins/toolbar/prism-toolbar.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.19.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>

Add Disqus Comments

First I headed to disqus.com and created an account. To do so I clicked 'Get started' and selected 'I want to installs Disqus on my site'. Then I just followed the instructions to enter my site info and clicked 'Create site'. After that I chose 'Subscribe for the basic plan' and 'Ghost' as integration goal. Then I navigated to the universal embed code and copied the short name of my site, which is the part that is displayed in the URL before 'disqus.com'.

Then I opened partials/services/disqus.hbs and followed the directions in the file itself to add my short name. That's it, after uploading the theme again I was ready to use comments.

Allow users to subscribe to new posts

This functionality is basically built in to the Nurui theme but it requires some configuration to work properly. First of all I headed to 'Labs' in the Ghost admin panel and uploaded the routes.yaml file, which is part of the theme, in the 'Routes' section. Then the 'Members' area appeared and I enabled Members itself and the 'Allow free member signup' option. By now a new menu point, which is named 'Members', has been added to Ghost's admin panel. There members can edited or deleted.

As a next step I headed to mailgun.com and followed the instructions to create and setup an account. I chose the Flex plan, which offers some free mails for the first 3 months and then charges 0.8 USD for 1000 mails, which is more than ok for my planned usage.

After creating my Mailgun account I went back to the 'Labs' area of the Ghost admin panel and opened 'Email settings' in the 'Members' section. There I entered my Mailgun domain and public API key.

Now all setup work was done and I could add the 'Subscribe' page. Therefore I created a new page, named it 'Subscribe' (that name can be whatever you want), opened the page settings and scrolled to 'Template' where I selected 'Newsletter' in the dropdown. Then I saved the page and added it to the menu of my blog.  

After doing all that subscribing basically worked for users. But now the user sees his account options when heading back to the blog after clicking the 'Subscribe' link in the email he received. To suppress any kind of member area on the page directly, I added the #login-panel-disable tag to this post (could be added to any post again).

If you create a new post now, Ghost will ask you if the subscribers should be informed about it. If this is approved, all subscribers will get an email which contains information about the newly created post.

NOTE: You could add the tag #subscribe-form to a post or page to display the subscription form there. I decided against this, because I just want to give people the opportunity to subscribe, but don't want to annoy them by doing so.

Enabling the search functionality was very easy. I just headed to 'Integrations' in the Ghost admin panel, selected 'Create Custom Integration', named it 'Search' (can be any name)and clicked 'Create'. Then Ghost generated a content API key, which I copied. In my theme I pasted the key in partials/search_api_key.hbs between the quotation marks and that's all. After that searching worked just fine.

Set the background color of posts without images

I have to admit, that this is not really a customization or configuration but it's a feature I enjoy so much about this theme, that I want to highlight it. You can set the background color of posts without images to red, blue, green, yellow, orange or violet. To do so you just need to add some tags in the post settings. To change the color of the post shown on the home screen you can simply use one of the following tags:

#red 
#blue 
#green 
#yellow 
#orange 
#violet

To change the background color of the title in the post itself you can use the same color names, just prefix them with post-, like the following tags show:

#post-red 
#post-blue 
#post-green
#post-yellow 
#post-orange
#post-violet

This means you could even style the post on the home page with a different color than the post itself. Of course I wouldn't recommend this, but I like the possibility a lot. Make sure to not forget the # at the start of the tag.

Further you can make colored overlays to your title images in both the home page and the post page, by just adding the correct tag.

Version information

At the time of writing I was using Ghost 3.14.0 and Nurui 2.2.1.

Resources and further reading

Nurui - Multipurpose Ghost Blog Theme
This is not a Wordpress theme. Please note that we do not provide refunds for mistaken purchases. Introduction Nurui is a Ghost theme with a sleek and modern design. Personal or professional, lifestyle blog, culinary blog, or design blog. Nurui will easily fit it all, an online journal or a magazine…
Tocbot
Tocbot - Generate a table of contents based on the heading structure of an html document
Ghost Handlebars Themes - Building a custom Ghost theme - Docs
Our handlebars theme templating framework works with the Ghost API to build flexible publishing websites. Get all the tools you need to start building your custom theme here!
A complete guide to code samples in Ghost
Ghost Tutorials: Discover how to add syntax highlighting to your code blocks when writing in the Ghost editor.
Disqus – The #1 way to build your audience
Disqus offers the best add-on tools for websites to increase engagement. We help publishers power online discussions with comments and earn revenue with native advertising.
You've successfully subscribed to ksick.dev
Welcome back! You've successfully signed in.
Great! You've successfully signed up.
Success! Your account is fully activated, you now have access to all content.