plugin-lightbox (A README Experience)

A plugin for Micro.blog for presenting a slide carousel containing images and/or videos. Its code lives here. It was inspired by Jason Becker’s plugin with which I’m sure you are already familiar.

Slide

GLightbox Injection

The GLightbox Javascript and CSS Stylesheet have been bundled into the plugin. They may be found in their respective directories beneath static/assets.

assets/js/lightbox.js is a template script that creates your GLightbox object using the parameter values configured in the data directory. To understand how my plugins utilize data files, have a look at this post.

Parameters

The key to understanding and setting values for the plugin parameters is to read the commented template files I’ve included.

There is a file for configuring the default values used by partials and shortcodes when creating a gallery. It lives at data/plugin_lightbox/defaults.toml and looks like this:

# 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

This file may be stored in a custom theme at data/plugin_lightbox_defaults.toml to persist the values between plugin updates.

There is also a file for configuring the GLightbox instance. It lives at data/plugin_lightbox/lightbox.toml and looks like this:

# Whether to generate events for analytical consumption. When this
# is true, the following code is added when the lightbox instance
# gets created:
#
# lightbox.on('open', () => {
#   if (typeof dataLayer === 'undefined') { return; }
#   dataLayer.push({'event': 'lightbox_opened'});
# });
#
# lightbox.on('close', () => {
#   if (typeof dataLayer === 'undefined') { return; }
#   dataLayer.push({'event': 'lightbox_closed'});
# });
#
# lightbox.on('slide_changed', ({ prev, current }) => {
#
#   if (typeof dataLayer === 'undefined') { return; }
#
#   // Prev and current are objects that contain the following data
#   // const { slideIndex, slideNode, slideConfig, player, trigger } = current;
#   let event = 'lightbox_slide_changed';
#   let title = current.slideConfig.title;
#   let alt = current.slideConfig.alt;
#   let description = current.slideConfig.description;
#   let type = current.slideConfig.type;
#
#   dataLayer.push({'event': event,
#                   'slide_title': title,
#                   'art_piece':title,
#                   'slide_alt': alt,
#                   'slide_description': description,
#                   'slide_type': type});
#  
# });
#
# Note: This value ranks lower than the plugin parameter value when both are present.
#
GenerateEvents = false

# Name of the selector for example '.glightbox' or 'data-glightbox' 
# or '*[data-glightbox]'
#
Selector = ".glightbox"

# Name of the skin, it will add a class to the lightbox so you 
# can style it with css.
#
Skin = "clean"

# Name of the effect on lightbox open. (zoom, fade, none)
#
OpenEffect = "zoom"

# Name of the effect on lightbox close. (zoom, fade, none)
#
CloseEffect = "zoom"

# Name of the effect on slide change. (slide, fade, zoom, none)
#
SlideEffect = "slide"

# More text for descriptions on mobile devices.
#
MoreText = "See more"

# Number of characters to display on the description before adding
# the moreText link (only for mobiles), if 0 it will display the
# entire description.
#
MoreLength = 60

# Show or hide the close button.
#
CloseButton = true

# Enable or disable the touch navigation (swipe).
#
TouchNavigation = true

# Image follow axis when dragging on mobile.
#
TouchFollowAxis = true

# Enable or disable the keyboard navigation.
#
KeyboardNavigation = true

# Close the lightbox when clicking outside the active slide.
#
CloseOnOutsideClick = true

# Start lightbox at defined index.
#
StartAt = 0

# Default width for inline elements and iframes, you can define a
# specific size on each slide. You can use any unit for example 
# 90% or 100vw for full width
#
Width = "900px"

# Default height for inline elements and iframes, you can define
# a specific size on each slide.You can use any unit for example
# 90% or 100vw For inline elements you can set the height to auto.
#
Height = "506px"

# Default width for videos. Videos are responsive so height is not
# required. The width can be in px % or even vw for example, 500px,
# 90% or 100vw for full width videos
VideosWidth = "960px"

# Global position for slides description, you can define a 
# specific position on each slide (bottom, top, left, right).
#
# DescPosition = "bottom"

# Loop slides on end.
#
Loop = false

# Enable or disable zoomable images you can also use 
# data-zoomable="false" on individual nodes.
#
Zoomable = true

# Enable or disable mouse drag to go prev and next slide 
# (only images and inline content), you can also use 
# data-draggable="false" on individual nodes.
Draggable = true

# Used with draggable. Number of pixels the user has to drag 
# to go to prev or next slide.
#
DragToleranceX = 40

# Used with draggable. Number of pixels the user has to drag up 
# or down to close the lightbox (Set 0 to disable vertical drag).
#
DragToleranceY = 65

# If true the slide will automatically change to prev/next or 
# close if dragToleranceX or dragToleranceY is reached, 
# otherwise it will wait till the mouse is released.
#
DragAutoSnap = false

# Enable or disable preloading.
#
Preload = true

# Set your own svg icons.
#
# SVG = '{}'

# Define or adjust lightbox animations.
#
# See the custom animation section of the README:
# https://github.com/biati-digital/glightbox#adding-a-custom-animation
#
# CSSEfects = '{}'

# You can completely change the html of GLightbox. See the 
# Themeable section in the README:
# https://github.com/biati-digital/glightbox#readme.
# 
LightboxHTML = '''
<div id="glightbox-body" class="glightbox-container">
  <div class="gloader visible"></div>
  <div class="goverlay"></div>
  <div class="gcontainer">
    <div id="glightbox-slider" class="gslider"></div>
    <button class="gnext gbtn" tabindex="0" 
            aria-label="Next">{nextSVG}</button>
    <button class="gprev gbtn" tabindex="1" 
            aria-label="Previous">{prevSVG}</button>
    <button class="gclose gbtn" tabindex="2" 
            aria-label="Close">{closeSVG}</button>
  </div>
</div>
'''

# You can completely change the html of the individual slide. 
# See the Themeable section in the README:
# https://github.com/biati-digital/glightbox#readme.
#
SlideHTML = '''
<div class="gslide">
  <div class="gslide-inner-content">
    <div class="ginner-container">
      <div class="gslide-media"></div>
      <div class="gslide-description">
        <div class="gdesc-inner">
          <h4 class="gslide-title"></h4>
          <div class="gslide-desc"></div>
        </div>
      </div>
    </div>
  </div>
</div>
'''

# Autoplay videos on open.
#
AutoplayVideos =  true

# If true video will be focused on play to allow keyboard 
# shortcuts for the player, this will deactivate prev and 
# next arrows to change slide so use it only if you know 
# what you are doing.
#
# AutofocusVideos = false

# Video player options. See the video player options in
# the README: https://github.com/biati-digital/glightbox#video-player
#
# The example given in the README looks like
# this:
# {
#     css: 'https://cdn.plyr.io/3.5.6/plyr.css',
#     js: 'https://cdn.plyr.io/3.5.6/plyr.js',
#     config: {
#       ratio: '16:9', // or '4:3'
#       muted: false,
#       hideControls: true,
#       youtube: {
#         noCookie: true,
#         rel: 0,
#         showinfo: 0,
#         iv_load_policy: 3
#       },
#       vimeo: {
#         byline: false,
#         portrait: false,
#         title: false,
#         speed: true,
#         transparent: false
#       }
#     }
#   }
# Plyr = '{}'

This file may be stored in custom theme at data/plugin_lightbox_lightbox.toml to persist the values between plugin updates.

There is only one parameter you can set via the plugin parameters interface.

If you set the parameter value there, it will take precedence versus setting GenerateEvents in a data file (this is unusual for my plugins. I wanted to make it easy to flip this one switch on and off).

Check out the glightbox README for more details regarding all those optional parameters (and they are all optional).

Shortcodes (and Partials)

When it comes to the included shortcodes, the beast of burden here is definitely layouts/partials/lightbox.html. That’s right. I said partial. I wanted re-useable code … and I wanted it invokeable from within content markdown files as well as from theme templates. The solution was to create templates and include shortcodes that bounced it all over. The parameters for the shortcodes and partials mirror each other with shortcode parameter names being dash-cased and partial parameter names being underscore_cased. Let’s have a look at the ridiculous collection of available parameters.

href
The URL for the slide content. This is required unless a src parameter value has been provided.
src
The URL for the link content. This is required unless an href parameter value has been provided.
link-class / link_class
Custom class to apply to the anchor tag. Default is undefined. glightbox is always applied.
link-style / link_style
Custom style to apply to the anchor tag. Default is undefined.
gallery
The name of the slide's gallery. Default is undefined.
title
The slide's title. Default is undefined.
description
The slide's description. Default is undefined.
desc-position / desc_position
(bottom, top, left, right) Where the slide's description should be positioned. Default is bottom.
type
(image, video, inline?, iframe?) The slide type. Default infers from source … and the last two options I'm not so sure about.
effect
(zoom, fade, none) The animation effect the slide should use. Default is zoom.
width
The custom width for this slide. Default is 900px.
height
The custom height for this slide. Default is 506px.
zoomable
Whether this slide should be zoomable. Default is true.
draggable
Whether this slide should be draggable. Default is true.
sizes
Specifies image sizes for different page layouts. Default is undefined.
srcset
Specifies a list of image files to use in different situations. Default is undefined.
video-class / video_class
Custom class to apply to the video tag. Default is undefined.
video-style / video_style
Custom style to apply to the video tag. Default is undefined.
loop
Whether the link video should loop. Default is true.
autoplay
Whether the link video should be set to autoplay. Default is true.
preload
Value for the link video's preload attribute. This ignored when set to autoplay. Default is undefined.
alt
Specifies an alternate text for an image. Default is undefined.
img-class / img_class
Custom class to apply to the img tag. Default is undefined.
img-style / img_style
Custom style to apply to the img tag. Default is undefined.
photo-width / photo_width
Specifies a pixel width for a thumbnail image to be fetched using the https://micro.blog/photos/ API. Default is undefined.
wrap
Whether the gallery links should wrap or be constrained to a single row. Default istrue.
div-class / div_class
Custom class to apply to the div. Default isundefined. 'gallery' is always applied.
div-style / div_style
Custom style to apply to the div in additon to the flex declaration and wrap specification. Default isundefined.
link-class / link_class
Custom class to apply to all anchor tags. Default isundefined. gallery-link and glightbox are always applied.
link-style / link_style
Custom style to apply to all anchor tags. Default isundefined.
gallery
The name of the gallery. This is required.
desc-position / desc_position
(bottom, top, left, right) Where all slides descriptions should be positioned. Default is bottom.
effect
(zoom, fade, none) The animation effect all slide should use. Default is zoom.
width
The custom width for all slides. Default is 900px.
height
The custom height for all slides. Default is 506px.
zoomable
Whether slides should be zoomable. Default istrue.
draggable
Whether slides should be draggable. Default istrue.
video-class / video_class
Custom class to apply to all video tags. Default isundefined. gallery-video is always applied.
video-style / video_style
Custom style to apply to all video tags. Default isundefined.
loop
Whether link videos should loop. Default istrue.
autoplay
Whether link videos should be set to autoplay. Default istrue.
preload
Value for link video preload attributes. This ignored when set to autoplay. Default isundefined.
img-class / img_class
Custom class to apply to all img tags. Default isundefined. gallery-image is always applied.
img-style / img_style
Custom style to apply to all img tags. Default isundefined.
photo-width / photo_width
Specifies a pixel width for a thumbnail image to be fetched using the https://micro.blog/photos/ API. Default isundefined.
scheme
Shortcode-only parameter used to get around the autolinking when passing a string of JSON from the markdown file. This should be https or http .
host
Shortcode-only parameter used to get around the autolinking when passing a string of JSON from the markdown file. This should be HOSTNAME.
slide-data / slide_data
The shortcode parameter expects a string containing a JSON array of slide JSON objects. The JSON should use the underscore version of the keys as defined below. When passing the JSON string to the shortcode, use relative URL values and provide scheme and host values as described above. The partial parameter expects this same data but already unmarshalled into a valid Slice.
href
The URL for the slide content. This is required unless a src parameter value has been provided.
src
The URL for the link content. This is required unless an href parameter value has been provided.
link_style
Custom style to apply to the anchor tag. Default is undefined.
gallery
The name of the slide's gallery. Default is undefined.
title
The slide's title. Default is undefined.
description
The slide's description. Default is undefined.
desc_position
(bottom, top, left, right) Where the slide's description should be positioned. Default is bottom.
type
(image, video, inline?, iframe?) The slide type. Default infers from source … and the last two options I'm not sure about.
effect
(zoom, fade, none) The animation effect the slide should use. Default is zoom.
width
The custom width for this slide. Default is 900px.
height
The custom height for this slide. Default is 506px.
zoomable
Whether this slide should be zoomable. Default is true.
draggable
Whether this slide should be draggable. Default is true.
sizes
Specifies image sizes for different page layouts. Default isundefined.
srcset
Specifies a list of image files to use in different situations. Default isundefined.
video_style
Custom style to apply to the video tag. Default isundefined.
loop
Whether the link video should loop. Default istrue.
autoplay
Whether the link video should be set to autoplay. Default istrue.
preload
Value for the link video's preload attribute. This ignored when set to autoplay. Default isundefined.
alt
Specifies an alternate text for an image. Default isundefined.
img_style
Custom style to apply to the img tag. Default isundefined.
photo_width
Specifies a pixel width for a thumbnail image to be fetched using the https://micro.blog/photos/ API. Default isundefined.

Okay, That’s A Lot

Some of y’all will be relieved to discover that I also include a shortcode mimicking Becker’s glightbox shortcode. It takes the following parameters:

src
An image URL for the slide. This is required.
img-width
Specifies a pixel width for a thumbnail image to be fetched using the https://micro.blog/photos/ API. Default is260px.
gallery
The name of the slide's gallery. Default is undefined.
title
The slide's title. Default is undefined.
description
The slide's description. Default is undefined.
alt
Specifies an alternate text for an image. Default isundefined.

Okay, One More

There is a special flavor of the gallery shortcode named gallery-markdown. It is identical to the gallery shortcode with the exception that you do not provide slide data as a parameter. It is used as a paired tag with inner content comprised of markdown images (such as one might find exported from Ulysses). The caption and src values are parsed from the markdown and used to create the slide objects.

Use Cases

Say you’re in a Ulysses sheet and wanna drop some images in a gallery. You can be all:

From Ulysses

and then the result will be all:

From Ulysses Result Cold Race War

Or, you could be … that one other guy … that just thinks it’s cool to be able to stick this directly into your Micro.blog post:

Micro.blog Post

And end up with this:

JSON String Result

For a look at how one might use the gallery partial directly, check out my plugin that does just that.

But don’t get overwhelmed by all the options. You can keep simple, be all: