Feeding Data to My Plugins

A guide to navigating the non-obvious nature of the process for providing the data my plugins want … and that you want to give them.

Option One: When You Want to Copy/Paste and Keep Your Fingers Crossed

This option uses the Micro.blog plugin parameter interface. The parameter interface is great when all we need to store is a simple string or number value. When we’re looking to feed data that a plugin can convert into a map/table/dictionary/pick-your-programmatical-term-of-choice-for-storing-key-value-pairs, however, we’re kind of purposefully breaking the interface.

How, you ask? Well, if you paste in your totally valid JSON object, click Update Settings, move on with your life, suddenly recall you meant to enter a particular value into the field for one of the plugin’s other parameters (say some simple parameter like Twitter Username), click again on Update Settings … so … if you do that, guess what … you just totally boinked the JSON object parameter. It didn’t get loaded back into the field the same way you had pasted it in there the first time and now you have to go find (or recreate) the data to copy/paste once more.

Anyway, if this sounds fun. You already know what to do; but, let’s break this down for the f$&k of it.

⑴ Hit up the Plugins tab and locate the plugin you wanna feed data to (we’ll be feeding data to plugin-cards for the purposes of this post).

Installed Plugins

⑵ Click * ⚙︎ Settings* to the right of the plugin’s name.

Plugin Settings

⑶ Enter any parameter values and/or data you want to configure and click Update Settings.

Data Pasted as Parameter

Here’s what I pasted into that Card Data (JSON) field (if you’re new to JSON, this is a totally valid JSON object):

{
  "/2020/": "https://moondeer.blog/uploads/2021/24760a1062.jpg",
  "/2021/": "https://moondeer.blog/uploads/2021/98295e13a8.jpg",
  "/about/": "https://moondeer.blog/uploads/2021/955619b235.jpg",
  "/artsy-fartsy/": "https://moondeer.blog/uploads/2021/76f1f5d0d6.jpg",
  "/biographical-tripe/": "https://moondeer.blog/uploads/2021/92a565154b.jpg",
  "/bookshelf/": "https://moondeer.blog/uploads/2021/27a279361f.jpg",
  "/categories/artsy-fartsy/": "https://moondeer.blog/uploads/2021/76f1f5d0d6.jpg",
  "/categories/biographical-tripe/": "https://moondeer.blog/uploads/2021/92a565154b.jpg",
  "/categories/critters/": "https://moondeer.blog/uploads/2021/0a37500db6.jpg",
  "/categories/inside-the-art/": "https://moondeer.blog/uploads/2021/8c4669346c.jpg",
  "/categories/music/": "https://moondeer.blog/uploads/2021/8d0a055caa.jpg",
  "/categories/personal-favorites/": "https://moondeer.blog/uploads/2021/328c442bd6.jpg",
  "/categories/perspectives/": "https://moondeer.blog/uploads/2021/f5f64b49bb.jpg",
  "/categories/poetry/": "https://moondeer.blog/uploads/2021/23a2035cdc.jpg",
  "/categories/programming/": "https://moondeer.blog/uploads/2021/47e02e5e74.jpg",
  "/categories/projects/": "https://moondeer.blog/uploads/2021/a0c8728c89.jpg",
  "/categories/stream-of-consciousness/": "https://moondeer.blog/uploads/2021/c11b3de2ff.jpg",
  "/cloud/": "https://moondeer.blog/uploads/2021/547d825d8a.jpg",
  "/critters/": "https://moondeer.blog/uploads/2021/0a37500db6.jpg",
  "/gallery/": "https://moondeer.blog/uploads/2021/8585a4a081.jpg",
  "/inside-the-art/": "https://moondeer.blog/uploads/2021/8c4669346c.jpg",
  "/music/": "https://moondeer.blog/uploads/2021/8d0a055caa.jpg",
  "/personal-favorites/": "https://moondeer.blog/uploads/2021/328c442bd6.jpg",
  "/perspectives/": "https://moondeer.blog/uploads/2021/f5f64b49bb.jpg",
  "/plausible/": "https://moondeer.blog/uploads/2021/e71e7d47c1.jpg",
  "/poetry/": "https://moondeer.blog/uploads/2021/23a2035cdc.jpg",
  "/programming/": "https://moondeer.blog/uploads/2021/47e02e5e74.jpg",
  "/projects/": "https://moondeer.blog/uploads/2021/a0c8728c89.jpg",
  "/stream-of-consciousness/": "https://moondeer.blog/uploads/2021/c11b3de2ff.jpg",
  "default": "https://moondeer.blog/uploads/2021/7c412827ad.jpg"
}

Boom! A brand new config.json file was just created in the plugin’s directory. Wanna see it? Here’s how to navigate: DesignEdit Custom ThemesSelect Plugin.

Let’s look at what got stored. Here’s the prettified version of config.json:

{
  "params": {
    "card_twitter_username": "moondeerdotblog",
    "card_data": "{   \"/2020/\": \"https://moondeer.blog/uploads/2021/24760a1062.jpg\",   \"/2021/\": \"https://moondeer.blog/uploads/2021/98295e13a8.jpg\",   \"/about/\": \"https://moondeer.blog/uploads/2021/955619b235.jpg\",   \"/artsy-fartsy/\": \"https://moondeer.blog/uploads/2021/76f1f5d0d6.jpg\",   \"/biographical-tripe/\": \"https://moondeer.blog/uploads/2021/92a565154b.jpg\",   \"/bookshelf/\": \"https://moondeer.blog/uploads/2021/27a279361f.jpg\",   \"/categories/artsy-fartsy/\": \"https://moondeer.blog/uploads/2021/76f1f5d0d6.jpg\",   \"/categories/biographical-tripe/\": \"https://moondeer.blog/uploads/2021/92a565154b.jpg\",   \"/categories/critters/\": \"https://moondeer.blog/uploads/2021/0a37500db6.jpg\",   \"/categories/inside-the-art/\": \"https://moondeer.blog/uploads/2021/8c4669346c.jpg\",   \"/categories/music/\": \"https://moondeer.blog/uploads/2021/8d0a055caa.jpg\",   \"/categories/personal-favorites/\": \"https://moondeer.blog/uploads/2021/328c442bd6.jpg\",   \"/categories/perspectives/\": \"https://moondeer.blog/uploads/2021/f5f64b49bb.jpg\",   \"/categories/poetry/\": \"https://moondeer.blog/uploads/2021/23a2035cdc.jpg\",   \"/categories/programming/\": \"https://moondeer.blog/uploads/2021/47e02e5e74.jpg\",   \"/categories/projects/\": \"https://moondeer.blog/uploads/2021/a0c8728c89.jpg\",   \"/categories/stream-of-consciousness/\": \"https://moondeer.blog/uploads/2021/c11b3de2ff.jpg\",   \"/cloud/\": \"https://moondeer.blog/uploads/2021/547d825d8a.jpg\",   \"/critters/\": \"https://moondeer.blog/uploads/2021/0a37500db6.jpg\",   \"/gallery/\": \"https://moondeer.blog/uploads/2021/8585a4a081.jpg\",   \"/inside-the-art/\": \"https://moondeer.blog/uploads/2021/8c4669346c.jpg\",   \"/music/\": \"https://moondeer.blog/uploads/2021/8d0a055caa.jpg\",   \"/personal-favorites/\": \"https://moondeer.blog/uploads/2021/328c442bd6.jpg\",   \"/perspectives/\": \"https://moondeer.blog/uploads/2021/f5f64b49bb.jpg\",   \"/plausible/\": \"https://moondeer.blog/uploads/2021/e71e7d47c1.jpg\",   \"/poetry/\": \"https://moondeer.blog/uploads/2021/23a2035cdc.jpg\",   \"/programming/\": \"https://moondeer.blog/uploads/2021/47e02e5e74.jpg\",   \"/projects/\": \"https://moondeer.blog/uploads/2021/a0c8728c89.jpg\",   \"/stream-of-consciousness/\": \"https://moondeer.blog/uploads/2021/c11b3de2ff.jpg\",   \"TwitterUsername\": \"moondeerdotblog\",   \"default\": \"https://moondeer.blog/uploads/2021/7c412827ad.jpg\" }"
  }
}

Check out all those escaped quotation marks. What we are feeding the plugin as card_twitter_usernameis the string "moondeerdotblog". Cool. That’s what the plugin wants. We are also feeding the plugin a string for card_data. Now the plugin has to try unmarshaling that string into a map (which is what Hugo circles when presented map/table/dictionary/pick-your-programmatical-term-of-choice-for-storing-key-value-pairs). Something gets messed up in translation … Hugo will throw a fit and refuse to build your site. We can do better.

Option Two: When You’re Ready To Tinker

So I’ve already mentioned, under option one, how to navigate to a plugin’s templates and look at what all was installed.

⑴ Go to the Design tab and hit that Edit Custom Themes button.

Edit Custom Theme

⑵ Find the plugin in the list of plugins and themes

List of Themes (Plugin)

⑶ Gaze in wonder at the contents of the plugin’s directory.

Plugin Templates

Guess what. As soon as you chose to install that plugin, you gained god-like power over the contents of its files. You can edit them. You can delete them. You can even add to them. This is what you are about to do. Totally safe. Totally harmless. You are just gonna manifest some chunk of zeros and ones into existence and give ‘em a place to stay.

⑷ Hit that New Template button.

New Template

Looks like we got two fields we need to fill in before we hit Update Template.

Sticking with the plugin-cards example, we are definitely going to create a file whose location begins all data/plugin_cards/data. How the location ends will depend upon how we feel like storing our data. We are no longer confined to the use of JSON. JSON would be totally valid. Our file content would be identical to the chunk of JSON code I plopped up there and identifed as a totally valid JSON object. If we did so, the file location would end with the .json extension, like so:

Plugin Directory JSON Filename

But, Hugo is just as happy with YAML as it is with JSON. You could toss the JSON into this converter and store it as a YAML file. It would look like this:

---
"/2020/": https://moondeer.blog/uploads/2021/24760a1062.jpg
"/2021/": https://moondeer.blog/uploads/2021/98295e13a8.jpg
"/about/": https://moondeer.blog/uploads/2021/955619b235.jpg
"/artsy-fartsy/": https://moondeer.blog/uploads/2021/76f1f5d0d6.jpg
"/biographical-tripe/": https://moondeer.blog/uploads/2021/92a565154b.jpg
"/bookshelf/": https://moondeer.blog/uploads/2021/27a279361f.jpg
"/categories/artsy-fartsy/": https://moondeer.blog/uploads/2021/76f1f5d0d6.jpg
"/categories/biographical-tripe/": https://moondeer.blog/uploads/2021/92a565154b.jpg
"/categories/critters/": https://moondeer.blog/uploads/2021/0a37500db6.jpg
"/categories/inside-the-art/": https://moondeer.blog/uploads/2021/8c4669346c.jpg
"/categories/music/": https://moondeer.blog/uploads/2021/8d0a055caa.jpg
"/categories/personal-favorites/": https://moondeer.blog/uploads/2021/328c442bd6.jpg
"/categories/perspectives/": https://moondeer.blog/uploads/2021/f5f64b49bb.jpg
"/categories/poetry/": https://moondeer.blog/uploads/2021/23a2035cdc.jpg
"/categories/programming/": https://moondeer.blog/uploads/2021/47e02e5e74.jpg
"/categories/projects/": https://moondeer.blog/uploads/2021/a0c8728c89.jpg
"/categories/stream-of-consciousness/": https://moondeer.blog/uploads/2021/c11b3de2ff.jpg
"/cloud/": https://moondeer.blog/uploads/2021/547d825d8a.jpg
"/critters/": https://moondeer.blog/uploads/2021/0a37500db6.jpg
"/gallery/": https://moondeer.blog/uploads/2021/8585a4a081.jpg
"/inside-the-art/": https://moondeer.blog/uploads/2021/8c4669346c.jpg
"/music/": https://moondeer.blog/uploads/2021/8d0a055caa.jpg
"/personal-favorites/": https://moondeer.blog/uploads/2021/328c442bd6.jpg
"/perspectives/": https://moondeer.blog/uploads/2021/f5f64b49bb.jpg
"/plausible/": https://moondeer.blog/uploads/2021/e71e7d47c1.jpg
"/poetry/": https://moondeer.blog/uploads/2021/23a2035cdc.jpg
"/programming/": https://moondeer.blog/uploads/2021/47e02e5e74.jpg
"/projects/": https://moondeer.blog/uploads/2021/a0c8728c89.jpg
"/stream-of-consciousness/": https://moondeer.blog/uploads/2021/c11b3de2ff.jpg
default: https://moondeer.blog/uploads/2021/7c412827ad.jpg

If we did so, the file location would end with the .yaml extension, like so:

Plugin Directory YAML Filename

Last, but not least, we have my new favorite markup language for Hugo data … TOML. As it is with YAML, so it is with TOML. Stick that JSON into this converter and you get:

"/2020/" = "https://moondeer.blog/uploads/2021/24760a1062.jpg"
"/2021/" = "https://moondeer.blog/uploads/2021/98295e13a8.jpg"
"/about/" = "https://moondeer.blog/uploads/2021/955619b235.jpg"
"/artsy-fartsy/" = "https://moondeer.blog/uploads/2021/76f1f5d0d6.jpg"
"/biographical-tripe/" = "https://moondeer.blog/uploads/2021/92a565154b.jpg"
"/bookshelf/" = "https://moondeer.blog/uploads/2021/27a279361f.jpg"
"/categories/artsy-fartsy/" = "https://moondeer.blog/uploads/2021/76f1f5d0d6.jpg"
"/categories/biographical-tripe/" = "https://moondeer.blog/uploads/2021/92a565154b.jpg"
"/categories/critters/" = "https://moondeer.blog/uploads/2021/0a37500db6.jpg"
"/categories/inside-the-art/" = "https://moondeer.blog/uploads/2021/8c4669346c.jpg"
"/categories/music/" = "https://moondeer.blog/uploads/2021/8d0a055caa.jpg"
"/categories/personal-favorites/" = "https://moondeer.blog/uploads/2021/328c442bd6.jpg"
"/categories/perspectives/" = "https://moondeer.blog/uploads/2021/f5f64b49bb.jpg"
"/categories/poetry/" = "https://moondeer.blog/uploads/2021/23a2035cdc.jpg"
"/categories/programming/" = "https://moondeer.blog/uploads/2021/47e02e5e74.jpg"
"/categories/projects/" = "https://moondeer.blog/uploads/2021/a0c8728c89.jpg"
"/categories/stream-of-consciousness/" = "https://moondeer.blog/uploads/2021/c11b3de2ff.jpg"
"/cloud/" = "https://moondeer.blog/uploads/2021/547d825d8a.jpg"
"/critters/" = "https://moondeer.blog/uploads/2021/0a37500db6.jpg"
"/gallery/" = "https://moondeer.blog/uploads/2021/8585a4a081.jpg"
"/inside-the-art/" = "https://moondeer.blog/uploads/2021/8c4669346c.jpg"
"/music/" = "https://moondeer.blog/uploads/2021/8d0a055caa.jpg"
"/personal-favorites/" = "https://moondeer.blog/uploads/2021/328c442bd6.jpg"
"/perspectives/" = "https://moondeer.blog/uploads/2021/f5f64b49bb.jpg"
"/plausible/" = "https://moondeer.blog/uploads/2021/e71e7d47c1.jpg"
"/poetry/" = "https://moondeer.blog/uploads/2021/23a2035cdc.jpg"
"/programming/" = "https://moondeer.blog/uploads/2021/47e02e5e74.jpg"
"/projects/" = "https://moondeer.blog/uploads/2021/a0c8728c89.jpg"
"/stream-of-consciousness/" = "https://moondeer.blog/uploads/2021/c11b3de2ff.jpg"
default = "https://moondeer.blog/uploads/2021/7c412827ad.jpg"

For the purpose interacting with Hugo, I have come to prefer TOML, so most of my documentation will be using TOML to persist data and configure sh$t. If we choose to store our data as TOML we would use the toml extension, kinda like:

Plugin Directory TOML Filename

⑸ With the path to our new file determined and its contents inserted, it is time to hit Update Template.

Plugin Templates with Data File

⑹ Rejoice in never needing to revisit the plugin parameters interface. If, however, you think it would be cool to not have to repeat this process every time you want to update the plugin … check out option three (which is the method I use for feeding data to my plugins from my custom theme).

Option Three: When You Value Persistence

The steps for option three are nearly identical. The difference lies in the directory within which we will create the data file. What we need is a custom theme. If you have one already, go ahead and skip down to the file naming conventions I have adopted. If you do not already have a custom theme, buckle up, here comes some super-easy sh$te you’ll be embarassed about having been intimidated by.

Creating Your First Custom Theme

⑴ Hit the Design tab. Design Tab

⑵ Hit Edit Custom Themes. Edit Custom Theme

⑶ Hit New Theme, give your theme a name, and hit Add Theme.

Add Theme

⑷ Head back to the Design tab, select your new theme from the Custom Theme drop-down, and hit Update Microblog Settings.

Update Microblog Settings

⑸ Hit Edit Custom Themes and find your new theme in the list (to get these screenshots I created My Custom Theme).

List of Themes (Custom Theme)

⑹ Select your new theme from the list to look at all its files.

Custom Theme Files

Boom! You have a custom theme. It has no files. It is basically a duplicate of whatever theme you were already using. Nothing scary about it. You could never, ever touch it and what you’d basically have is a duplicate of whichever builtin theme you have selected. That’s what you’re looking at up thar. I had Marfa selected so we get to see all the files inherited from Marfa. Below Marfa’s files you’ll find the default files that every theme gets to inherit, no matter-f$&king-what.

Default Theme Files

Just like in option two, we can selectively add files and totally not f$&k anything up … so long as we do not locate a new template in a path that obstructs the lookup of an inherited template we wanted to keep.

But for the file location we want to use, the steps from here are identical to steps ⑷ and ⑸ from option two. Let’s look at how we decide to name our file.

File Naming Conventions

The choice between TOML, YAML, and JSON (as described in option two) is still on the table. This choice will determine the file extension for our new template file. The convention I’ve come up with is to take what you’d get in option two and then replace the last forward-slash with an underscore. So, if our data file stored within the plugin’s directory was located at data/plugin_cards/data.toml, we would create a new file in our custom theme locate at data/plugin_cards_data.toml (I originally tried using the same location but the plugin file always overwrites the custom theme file in the merge process).

Here’s how my plugins look for the data they require. If data is found, any data located further down the lookup chain is ignored.

  1. Look for a file located at data/[UNDERSCORED_PLUGIN_NAME]_[FILENAME]
  2. Look for a file located at data/[UNDERSCORED_PLUGIN_NAME]/[FILENAME]
  3. Look for a parameter value entered using the plugin parameter interface
UNDERSCORED_PLUGIN_NAME
If the plugin’s GitHub repository is named plugin-cards, this value would be plugin_cards.
FILENAME
You’ll find this value in the plugin’s README. You needn’t worry about extensions, the plugin does not need to know the extension. So long as it is a valid JSON, YAML, or TOML file, Hugo resolves that sh$t automatically. I have also taken to including a commented template file within the plugin. You may just need to find and edit it, kinda like this one from plugin-favicons:
# Parameters derived from the use of https://realfavicongenerator.net
# to generate favicon assets. 

# General theme color for the site (used by Mobile Safari in iOS 15 to paint the background of the status bar).
# ThemeColor = "#FFFFFF"

[Apple]

# Path to the 180x180 pixel image.
#
# TouchIcon = "apple-touch-icon.png"

# Path to the 57x57 pixel image.
#
# x57 = "/apple-touch-icon-57x57.png"

# Path to the 114x114 pixel image.
#
# x114 = "/apple-touch-icon-114x114.png"

# Path to the 72x72 pixel image.
#
# x72 = "/apple-touch-icon-72x72.png"

# Path to the 144x144 pixel image.
#
# x144 = "/apple-touch-icon-144x144.png"

# Path to the 60x60 pixel image.
#
# x60 = "/apple-touch-icon-60x60.png"

# Path to the 120x120 pixel image.
#
# x120 = "/apple-touch-icon-120x120.png"

# Path to the 76x76 pixel image.
#
# x76 = "/apple-touch-icon-76x76.png"

# Path to the 152x152 pixel image.
#
# x152 = "/apple-touch-icon-152x152.png"

# Path to the Safari pinned tab SVG file.
# You can create a template file and paste in your SVG or include the file 
# in a custom theme GitHub repository. For it to be at the root, the location would
# be static/safari-pinned-tab.svg
#
# SafariPinnedTab = "/safari-pinned-tab.svg"

[Favicon]

# Path to an SVG favicon image.
#
# svg = "/favicon.svg"

# Path to the 196x196 pixel image.
#
# x196 = "/favicon-196x196.png"

# Path to the 128x128 pixel image.
#
# x128 = "/favicon-128x128.png"

# Path to the 96x96 pixel image.
#
# x96 = "/favicon-96x96.png"

# Path to the 32x32 pixel image.
#
# x32 = "favicon-32x32.png"

# Path to the 16x16 pixel image.
#
# x16 = "favicon-16x16.png"

# Path to regular image. If you upload an ico image it gets converted to jpg
#
# ico = "favicon.ico"

# Base64 ico image.
# You can convert .ico to base64 here: https://base64.guru/converter/encode/image/ico
#
# icoBase64 = "base64"

[AndroidChrome]

# Short name for app-like button.
#
# Name = "Short Name"

# Path to the 192x192 pixel image. 
#
# x192 = "android-chrome-192x192.png"

# Path to the 512x512 pixel image.
#
# x512 = "android-chrome-512x512.png"

# Theme color to use in the webmanifest.
#
# ThemeColor = "#FFFFFF"

# Background color to use in the webmanifest.
#
# BackgroundColor = "#FFFFFF"

################################
# Using the AndroidChrome assets
################################

# OPTION 1: Manual File Creation
#
# In this plugin or your custom theme, create template 'static/manifest.json'
#
# Replace bracketed variable names with their values.
#
# {
#     "name": "[AndroidChrome.Name]",
#     "short_name": "[AndroidChrome.Name]",
#     "icons": [
#         {
#             "src": "[AndroidChrome.x192]",
#             "sizes": "192x192",
#             "type": "image/png"
#         },
#         {
#             "src": "[AndroidChrome.x512]",
#             "sizes": "512x512",
#             "type": "image/png"
#         }
#     ],
#     "theme_color": "[AndroidChrome.ThemeColor]",
#     "background_color": "[AndroidChrome.BackgroundColor]",
#     "display": "standalone"
# }

# If you went and stuck the file somewhere else, set this variable and uncomment it.
#
# Webmanifest = "/manifest.json"

# OPTION 2: Automatic File Creation
#
# Create a template in your custom theme located at config/_default/mediaTypes.toml
# and add the following media type:
#
# ["application/manifest+json"]
# suffixes = [ "json", "webmanifest" ]
#
# Create a template in your custom theme located at config/_default/outputFormats.toml
# and add the following output format:
# 
# [WebAppManifest]
# mediaType = "application/manifest+json"
# baseName = "manifest"
# rel = "manifest"
# isPlainText = true
# isHTML = false
# notAlternative = true
#
# Scroll down to the blank theme files in your custom theme and open config.json.
# Look for the 'outputs' key and then the 'home' key. Copy all the current outputs
# for 'home'.
# 
# Create a template in your custom theme located at config/_default/outputs.toml
# Create an entry for 'home' with all those copied output values. Then add one more
# called 'WebAppManifest'. My file looks like this.
#
# home = [
#   "HTML",
#   "RSS",
#   "JSON",
#   "RSD",
#   "ArchiveHTML",
#   "ArchiveJSON",
#   "PhotosJSON",
#   "PodcastXML",
#   "PodcastJSON",
#   "WebAppManifest",
#   "BrowserConfig"
#   ]
#
# You should now be configured to build a json file in your root directory called 'manifest.json'.
# Make sure the 'Webmanifest' variable under option 1 is commented out or set to '/manifest.json'.



[MSTile]

# Short name for app-like button.
#
# ApplicationName = "Short Name"

# Path to the 70x70 pixel image.
#
# x70 = "/mstile-70x70.png"

# Path to the 144x144 pixel image.
#
# x144 = "/mstile-144x144.png"

# Path to the 150x150 pixel image.
#
# x150 = "/mstile-150x150.png"

# Path to the 310x150 pixel image.
#
# Widex150 = "/mstile-310x150.png"

# Path to the 310x310 pixel image.
#
# x310 = "/mstile-310x310.png"

# The tile color behind the 150x150 pixel image.
#
# TileColor = "#DA532C"

################################
# Using the MSTile assets
################################

# OPTION 1: Manual File Creation
#
# In this plugin or your custom theme, create a template 'static/browserconfig.xml'
#
# Replace bracketed variable names with their values.
#
# <?xml version="1.0" encoding="utf-8"?>
# <browserconfig>
#   <msapplication>
#     <tile>
#       <square70x70logo src="[MSTile.x70]"/>
#       <square144x144logo src="[MSTile.x144]"/>
#       <square150x150logo src="[MSTile.x150]"/>
#       <wide310x150logo src="[MSTile.Widex150]"/>
#       <square310x310logo src="[MSTile.x310]"/>
#       <TileColor>[MSTile.TileColor]</TileColor>
#     </tile>
#   </msapplication>
# </browserconfig>

# If you went and stuck the file somewhere else, set this value and uncomment.
#
# BrowserConfig = "/browserconfig.xml"

# OPTION 2: Automatic File Creation
#
# Create a template (or append if you did this for the manifest) in your custom 
# theme located at config/_default/outputFormats.toml and add the following output format:
# 
# [BrowserConfig]
# mediaType = "application/xml"
# baseName = "browserconfig"
# isPlainText = true
# isHTML = false
# notAlternative = true
#
# Scroll down to the blank theme files in your custom theme and open config.json.
# Look for the 'outputs' key and then the 'home' key. Copy all the current outputs
# for 'home'.
# 
# Create a template in your custom theme located at config/_default/outputs.toml
# Create an entry for 'home' with all those copied output values. Then add one more
# called 'BrowserConfig'. My file looks like this.
#
# home = [
#   "HTML",
#   "RSS",
#   "JSON",
#   "RSD",
#   "ArchiveHTML",
#   "ArchiveJSON",
#   "PhotosJSON",
#   "PodcastXML",
#   "PodcastJSON",
#   "WebAppManifest",
#   "BrowserConfig"
#   ]
#
# You should now be configured to build a json file in your root directory called 'manifest.json'.
# Make sure the 'BrowserConfig' variable under option 1 is commented out or set to '/browserconfig.xml'.

Or this one from plugin-lightbox:

# Whether the gallery slide links should wrap or be constrained to a single row. This affects the container's flex-wrap value.
wrap = true

# Custom class to apply to the <div> tag. The gallery.html partial
# always adds the 'gallery' class. This value will be anchorized
# around spaces and joined with 'gallery'
div_class = ""

# Custom style to apply to the <div> tag. The gallery.html partial
# always adds 'display: flex' and `flex-wrap: (no)wrap`. This will
# be added after.
div_style = "gap:0px"

# Custom class to apply to all <a> tags. The gallery.html partial
# always adds the 'gallery-link' class. This value will be anchorized
# around spaces and joined with 'gallery-link'
link_class = ""

# Custom style to apply to all <a> tags.
link_style = "height:20vh;width:20vh;flex-grow:1"

# Default description position for all slides.
desc_position = ""

# Default effect to set for slide transitions. Valid values are
# 'zoom', 'fade', and 'none'. GLightbox defaults to `zoom`.
effect = ""

# Default width to apply to all slides.
width = ""

# Default height to apply to all slides.
height = ""

# Whether slides shall be zoomable by default.
# Glightbox defaults to true.
zoomable = ""

# Whether slides shall be draggable by default.
# Glightbox defaults to true.
draggable = ""

# Custom class to apply to all <video> tags. The gallery.html partial
# always adds the 'gallery-video' class. This value will be anchorized
# around spaces and joined with 'gallery-video'
video_class = ""

# Custom style to apply to all <video> tags.
video_style = "max-height:100%;min-height:100%;object-fit:cover; vertical-align:bottom"

# Whether videos used as link content should loop by default.
loop = true

# Whether videos used as link content should autoplay by default.
autoplay = true

# Whether videos used as link content should preload by default.
# Valid values are 'auto', 'metadata', and 'none'. Ignored when
# autoplay is true
preload = ""

# Custom class to apply to all <img> tags. The gallery.html partial
# always adds the 'gallery-image' class. This value will be anchorized
# around spaces and joined with 'gallery-image'
img_class = ""

# Custom style to apply to all <img> tags. When photo_width has
# been set, img-thumbnail.html will add the following style
# 'width:[photo_width]px; height: auto; max-width: 100%'. This
# would be appended after in such a case.
img_style = "max-height:100%;min-height:100%;object-fit:cover; vertical-align:bottom"

# Default pixel width for fetching thumbnail images via https://micro.blog/photos/ API.
photo_width = 260

Or this one from plugin-social-media-links:

# This file holds the array of social media platforms to link.
#
# The value of Href will be generated by substituting the value 
# of USERNAME (as well as SERVER when set).
#
# Replace [BRACKETED] values and uncomment or create your own entries
# for platforms not listed.
#
[[Platforms]]
Name = "Twitter"
Href = "https://twitter.com/@USERNAME"
#Username = "[USERNAME]"

[[Platforms]]
Name = "Github"
Href = "https://github.com/USERNAME"
#Username = "[USERNAME]"

[[Platforms]]
Name = "Tumblr"
Href = "https://USERNAME.tumblr.com"
#Username = "[USERNAME]"

[[Platforms]]
Name = "Medium"
Href = "https://USERNAME.medium.com"
#Username = "[USERNAME]"

[[Platforms]]
Name = "Facebook"
Href = "https://www.facebook.com/USERNAME"
#Username = "[USERNAME]"

[[Platforms]]
Name = "Instagram"
Href = "https://www.instagram.com/USERNAME"
#Username = "[USERNAME]"

[[Platforms]]
Name = "Mastodon"
Href = "https://SERVER/@USERNAME"
#Server = "[SERVER]"
#Username = "[USERNAME]"

You get the idea. Peace out. ☾𐂂