Featured image of post Update Emoji When Switching Color Scheme in Hugo Stack Theme

Update Emoji When Switching Color Scheme in Hugo Stack Theme

Learn how to update the emoji displayed in the Hugo x theme Stack when switching between dark and light color schemes.


On Hugo websites using the Stack theme, a color scheme picker allows visitors to switch between dark and light modes. Additionally, there is an emoji in the bottom right corner of the website’s illustration. In this tutorial, I will explain how to update the theme and configure your website to display a different emoji for each color scheme.


❯  Foreword

This article applies to the websites based on goHugo, and using the theme Stack. Then, in the next, I will take the case where the theme was added to the website using submodules. This guide may be different if you have added your theme using Hugo modules.

You also have to be able to apply updates to your theme, implying that you have forked the author’s theme. If this is not the case, I recommend you first look at this reading.


❯  Global explanation on how it works


❯  The emoji

This theme allows you to set an emoji that will, if set, be displayed in the bottom-right corner of your website as follows:

On desktop, the emoji displayed in the bottom-right corner of the website's logo
On desktop, the emoji displayed in the bottom-right corner of the website's logo

You can set this emoji by adding this configuration to your website’s configuration (on config.toml):

1
2
3
4
...
[params.sidebar]
emoji = "🚜"
...

Alternatively, if you have a configuration file params.toml, you can add this configuration on it, without the “params.”.

If this configuration is not present, simply no emoji is displayed.


❯  The color scheme mechanism

On this theme, there is a switch (at the bottom of the left panel on desktop, or in the hamburger menu on mobile) that allows to switch the website on dark or light mode.

The color scheme switch on desktop
The color scheme switch on desktop
The color scheme switch on mobile
The color scheme switch on mobile

This logic is handled on the file assets/ts/colorScheme.ts in the theme. And an event, named onColorSchemeChange is emitted when a user clicks on the switch:

1
2
3
4
5
6
7
8
    ...
    private dispatchEvent(colorScheme: colorScheme) {
        const event = new CustomEvent('onColorSchemeChange', {
            detail: colorScheme
        });
        window.dispatchEvent(event);
    }
    ...

This event is notably consumed to change the color theme of the different comments providers integrations provided by default in the theme.

We will exploit this event to trigger the change of the emoji according to the scheme.


❯  Apply the update


❯  On the theme

The logic concerning the display of elements on the left panel is located in the file partials/sidebar/left.html. There is in particular the logic of the site-avatar, the social-icons, the menu (including the link to the Home), … and the emoji.

1
2
3
4
5
...
    {{ with $.Site.Params.sidebar.emoji }}
        <span class="emoji">{{ . }}</span>
    {{ end }}
...

In the next section, we will add 2 new configuration keys: one for the emoji displayed when the light mode is enabled (emojiLight), and one when the dark mode is enabled (emojiDark). In addition, to guarantee that this adds is not breaking, we will display the configuration key emoji if one of these new keys is missing.

This can be achieved in adding the following code in the left.html, right before the close of the <header> section:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
        <script>
          window.addEventListener('onColorSchemeChange', function (event) {
            let emoji = event.detail === 'light'
              ? "{{ $.Site.Params.sidebar.emojiLight }}"
              : "{{ $.Site.Params.sidebar.emojiDark }}";

            if (emoji.length === 0) {
              emoji = "{{ $.Site.Params.sidebar.emoji }}";
            }

            const emojiElt = document.getElementById("emoji-elt");
            if (emoji.length > 0 && emojiElt) {
              document.getElementById("emoji-elt").innerHTML = emoji;
            } else if (emoji.length > 0 && !emojiElt) {
              document.getElementById("site-avatar")
              .insertAdjacentHTML('beforeend', `<span id="emoji-elt" class="emoji">${emoji}</span>`);
            } else if (emoji.length === 0 && emojiElt) {
              document.getElementById("emoji-elt").remove();
            }
          });
        </script>

Now, the explanation of what this code is doing:

  • by defining the function
1
2
3
window.addEventListener('onColorSchemeChange', function (event) {
    ...
});

We will listen which events are emitted, and perform an action. Something important to notice: this event is also emitted at the launch of the website. We can then fully manage how the emoji is displayed on the page within this function.

  • These lines:
1
2
3
4
5
6
7
8
9
...
let emoji = event.detail === 'light'
    ? "{{ $.Site.Params.sidebar.emojiLight }}"
    : "{{ $.Site.Params.sidebar.emojiDark }}";

    if (emoji.length === 0) {
        emoji = "{{ $.Site.Params.sidebar.emoji }}";
    }
...

Will pick from the configuration, and based on the color received in the event, which emoji we have to display. As I have said above, we will get either the emojiLight or the emojiDark, and if this emoji is not set, or set to an empty chain, we will request the default emoji configuration.

  • Finally, these lines:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
...
    const emojiElt = document.getElementById("emoji-elt");
    if (emoji.length > 0 && emojiElt) {
        document.getElementById("emoji-elt").innerHTML = emoji;
    } else if (emoji.length > 0 && !emojiElt) {
        document.getElementById("site-avatar").insertAdjacentHTML('beforeend', `<span id="emoji-elt" class="emoji">${emoji}</span>`);
    } else if (emoji.length === 0 && emojiElt) {
        document.getElementById("emoji-elt").remove();
    }
...

controls the display of the emoji span. More precisely, if the element is not present and there is an emoji to display, then we add it to the DOM ; if the element is present and there is an emoji to display, we replace the previous emoji by the new one ; if the element is present, but there is no emoji to display, we remove the element.

To locate which figure the JavaScript has to update, you have to add an id as follows:

1
2
3
4
5
...
    {{ if (default true .enabled) }}
        <figure id="site-avatar" class="site-avatar">
        <a href="{{ .Site.BaseURL | relLangURL }}">
...

Since this controls the display of the span and its content, you can remove the following lines of code:

1
2
3
4
5
...
    {{ with $.Site.Params.sidebar.emoji }}
        <span class="emoji">{{ . }}</span>
    {{ end }}
...

❯  On the website’s configuration

Once the change applied in the theme, and the theme updated in your website, we now have to add the configuration on the website. And this is fairly simple! At the same place where the configuration key is located, add two new configuration keys: emojiLight and emojiDark, containing respectively the emoji to display in light mode and for dark mode. You can optionally keep the key emoji, which is used as a fallback if one of the new keys is not set:

1
2
3
4
5
6
...
[params.sidebar]
emoji = "🚜"
emoji = "🌾"
emoji = "🍗"
...

Now, if you start your server, the new emojis should appear

The emoji is updated when we change the color scheme

❯  Minimal example website

To conclude this article, I share here a few links to guide you if you want to add similar changes on your website.

  • A website example here
  • The commit containing changes to apply on the theme here
  • The commit containing changes to apply on the website here