plugin-category-cloud (a README Experience)

A plugin for Micro.blog that creates a page displaying links to your categories layed out as a category cloud. Its code lives here.

If you feel like viewing its use out in the wild, you can mosey on over to my category cloud:

Cloud

A category cloud weighted by posts per category.

Where It's At

Once installed, the generated page will be found at [SCHEME]://[HOSTNAME]/cloud/. By default, the content file, content/cloud.md, registers a menu item for the page:

+++
title = "Cloud"
description = "A category cloud weighted by posts per category."
type = "cloud"

[menu.main]
name = 'Cloud'
title = 'Cloud'
identifier = 'cloud'
url = '/cloud/'
weight = 110
+++
{{< plugin-category-cloud >}}

If you'd rather use the native Micro.blog page interface, locate this file and make it look like this:

+++
title = "Cloud"
description = "A category cloud weighted by posts per category."
type = "cloud"
+++
{{< plugin-category-cloud >}}

If you'd rather not have a dedicated page for your category cloud, feel free to delete content/cloud.md entirely. You can stick the cloud anywhere you like by invoking the partial from a template like so:

{{ if templates.Exists "partials/plugin-category-cloud/category-cloud.html" }}
{{ partial "plugin-category-cloud/category-cloud.html" . }}
{{ end }}

If you do invoke the partial from a template, be sure to include the relative page path in Config.PagePaths per the parameter's documentation.

Parameters, Where TF are the Parameters?

The parameters live in data templates under the data/plugin_category_cloud directory.

data/plugin_category_cloud/Config.toml contains debug and build related parameters:

# Debug and build related parameters.
#####################################

# Theme version, printed to HTML comment when the plugin loads.
#
Version = '6.0.9'

# Whether to print HTML comments for debugging purposes.
#
DebugPrint = false

# Whether to provide subresource integrity by generating a 
# base64-encoded cryptographic hash and attaching a .Data.Integrity
# property containing an integrity string, which is made up of the
# name of the hash function, one hyphen and the base64-encoded hash sum.
#
Fingerprint = true

# Output style for /assets/sass/category-cloud.scss. 
# Valid options are nested, expanded, compact and compressed
#
SassOutput = 'compact'

# The relative paths of pages that should link to the stylesheet.
# The stylesheet  is always linked for the page generated at /cloud/. 
# If you want to remove the generated page from the menu and/or insert 
# the cloud elsewhere you can enter the relative page path(s) here to
# ensure the stylesheet is linked for pages wherein you've inserted 
# an invocation of the partial
# (i.e. {{ partial "plugin-category-cloud/category-cloud.html" . }}).
# 
# For example, the relative path of the home page would be '/'. The
# relative path for a page like https://my.blog/archive/ would be '/archive/'.
# The relative path for a page like https://my.blog/some/random/page.html would
# be '/some/random/page.html'
#
PagePaths = []

data/plugin_category_cloud/Names.toml contains parameters relating to how category names will be displayed:

# Configuring the way the cloud displays category names.
########################################################

# Category names are fetched in their anchorized form.
# Setting this parameter to true will convert anchorized
# forms into capitalized and spaced forms.
#
#   my-category → My Category
#
Humanize = true

# The default path to a category page takes the form:
#  /categories/my-anchorized-category
# 
# If the category has been lifted into the main menu,
# and its path has been altered (perhaps by dropping /categories)
# the plugin can try to match a category to its menu item and
# use the URL value of the menu item.
#
MenuItemMatching = true

# List of categories to exclude from the category cloud.
#
# For example: ['Pinned', 'Temporary']
#
ExclusionList = [ ]

# The plugin fetches the category names in anchorized form.
# The 'Humanize' parameter will return the category names
# to their capitalized and spaced form. The DisplayNames
# parameter allows for direct control over how a category
# name will be displayed
#
[DisplayNames]

# To define exactly how to display a specific category name 
# enter its value below with its anchorized form as the key.
# My use case for this option is this category:
#
# stream-of-consciousness = 'Stream of Conscioussness'
#

data/plugin_category_cloud/Style.toml contains mostly stylesheet-related parameters:

# Parameters for styling the cloud.
###################################

# ID to set on the wrapper.
#
WrapperID = 'category-cloud'

# Sass (or CSS) to apply to the wrapper.
#
Wrapper = ''

# Sass (or CSS) to apply to links.
#
Link = ''

# Max font size to use in the cloud in rem units.
#
MaxSize = 2.34

# Min font size to use in the cloud in rem units.
#
MinSize = 0.9

# Max font weight to use in the cloud.
#
MaxWeight = 800

# Min font weight to use in the cloud.
#
MinWeigth = 200

# Whether to display parenthesized page counts along
# with the category names.
#
DisplayPageCounts = false

# Whether to wrap category links with <nobr>
#
UnbreakableLinks = true

Read the comments in the files, I took the time to write them. As far as parameters go, this bunch is fairly straight forward. Setting DisplayPageCounts = true, for example, would land you a cloud kinda like:

Set Humanize = false, and you may end up with a cloud kinda like:

So You're Unhappy with the Style

I knew you would be. That is why I stuck those two hooks in data/plugin_category_cloud/Style.toml, Wrapper and Link. You can stick whatever Sass or CSS you want between the quotes and the plugin will inject it into the build like so…

@import "vendor/rfs";

#category-cloud { 
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-content: center;
  align-items: baseline;
  @include rfs(10px, gap);
  @include padding(0 20px);
  @include margin(40px auto);
  /* Wrapper */
  
  a {
    line-height: 1;
    padding: 0;
    margin: 0;
    /* Link */
    
    span {
      display: none;
    }
    
    @for $i from 1 through /* TotalSteps */ {
      
      &.step-#{$i} {
        @include font-size((/* MinSize */rem + $i * /* SizeIncrement */rem));
        font-weight: /* MinWeight */ + $i * 100;
      }
      
    }
    
  }
  
}

where TotalSteps is equal to (MaxWeight - MinWeight) ÷ 100 and SizeIncrement is equal to (MaxSize - MinSize) ÷ TotalSteps.

Planning for Persistence

The downside of ensuring the plugin receives good data by running through Hugo's data template API is that the files in data/plugin_category_cloud will be overwritten every time the plugin is updated. The solution is to move the files outside of the plugin's directory. All my plugins resolve their parameter values by merging what they find in two specific locations. For this plugin these two locations happen to be data/plugin_category_cloud and data/plugin-category-cloud. Files in the dash-cased directory take precedence during the merge. If you have a custom theme, simply create new templates that replicate the plugin files … changing the underscores in the path into dashes.

As an alternative for folks that feel like custom themes are bit much to wrap the head around, I created a plugin solely for the purpose of housing all my plugin's configuration files (with all the values commented out so that overriding parameter values is opt-in (by uncommenting)). The files in that plugin will also be overwritten whenever that plugin updates, but I should hardly ever need to update that repository (hardly ever need to bump the version of it prompting you to update would be more accurate). If this sounds like the way you want to go, install plugin-configuration-files.