Plugins and scripts
The site adds a few scripts of its own to Docsy’s, under assets/js/, loaded
three ways:
- Plugins, through Docsy’s loader
- Hook scripts, through the body-end hook (inventory) and the head-end hook (one script, the Kapa widget’s pre-initialization)
- Shortcode scripts, by the shortcode of the feature that needs them: the registry search form and the config-types accordion, for example
Hooks and shortcodes load a script through the script.html partial: Hugo’s
js.Build bundles each file, and production builds also minify, fingerprint and
add subresource integrity.
Plugins
Site plugins follow Docsy’s custom-script contract under the
otel- prefix. One that renders markup of its own is gated by a shortcode that
owns the markup and marks the page, so the gate follows the content into every
language that serves it; the shim reads the mark. A shortcode in included
content marks the included page, not the page that includes it (Page flags in
included content).
Benchmarks plugin
The benchmarks shortcode charts a repository’s benchmark history, the
data.js that github-action-benchmark publishes on GitHub Pages (its shape:
the action’s source types). The shortcode names the data; three optional
arguments say how to read it. With data_url alone, each benchmark gets a chart
of its own, drawn on the commits it has data for (benchmark names must be unique
within a commit):
{{< benchmarks data_url="param:otel-benchmarks.data_url" >}}
With group_separator, each chart carries several benchmarks as series, which
is how the Collector benchmarks page reads its data:
{{< benchmarks data_url="param:otel-benchmarks.data_url" filter="10kDPS,10kSPS" group_separator="/" series_separator=" - " >}}
With group_separator, charts share the data set’s commit axis, so their series
line up, and get a legend and a series name in the tooltip; without it, each
chart has neither, its title naming the one series.
data_url: the action’sdata.js, ashttps://…or asparam:NAME, a page param holding it, so that the page’s prose can link the same URL through_paramfilter(optional): keep a bench whoseextracontains any of the comma-separated stringsgroup_separator(optional): splitextrainto a group, joined to the bench name as the chart’s title, and a series name; anextrawithout the separator is bothseries_separator(optional): trim the series name at its first occurrence; withoutgroup_separatorthere is no series name, and the argument does nothing
The arguments’ contract, validation included, is the shortcode’s doc comment. Links and text belong in the page’s prose, where each language writes its own; the data link is also an agent’s path to the numbers, since the shortcode’s Markdown output is empty.
The otel-benchmarks plugin behind the shortcode is a fork of the action’s
stock renderer. Its parts:
- Shortcode,
layouts/_shortcodes/benchmarks.html: emits the chart container and records the data URL for the shim and companion; each use renders a chart set where it stands. - Markdown variant,
benchmarks.mdbeside it: empty, so the chart markup stays out of the page’s Markdown output (Agent support). - Shim,
layouts/_partials/scripts/plugins/otel-benchmarks_docsy-shim.html(Adjust a plugin per page): disables the plugin on pages without the shortcode, which keeps the remote data script off every other page (Security). - Companion,
layouts/_partials/scripts/plugins/otel-benchmarks.html(Plugin files): vendors Chart.js on the entry’sversionpin, then loads the data file. The data stays a live remote script so the charts update between site builds, which a fixed integrity hash would forbid. - Script,
assets/js/plugins/otel-benchmarks/(Plugin files): the renderer,index.js, and its helpers for the legend, the content a point shows in the tooltip and the popover, and the popover itself. - Stylesheet,
assets/scss/plugins/otel-benchmarks.scss(Plugin files): the charts’ layout, scoped to the container. The inline copies keep the stock page’sstatic/css/benchmarks.css, whose baremain,buttonandfooterselectors also reach Docsy’s chrome. - Registration,
config/_default/hugo.yaml(Configuration reference): one site-level entry, since the shim decides per page. - Tests,
tests/public/otel-benchmarks.test.mjs: delivery on each page’s built copies; itsPAGEStable is the inventory of the pages on the plugin and of the localized copies still inline, whose conversion #12266 tracks.
Body-end scripts
| Script | Pages | Purpose |
|---|---|---|
blog-sidebar-entry-opener.js | Blog index and pager pages (acts on the first) | Opens the two newest year groups in the sidebar |
imageZoom.js | All | Click-to-zoom for content images |
navScroll.js | All | Meant to scroll the sidebar’s active entry into view; inert today, since the active state is applied after it runs |
tracing.js | Netlify builds, when unpaused | Website telemetry, paused |
Blog sidebar entry opener
blog-sidebar-entry-opener.js is the one body-end script gated to a page and
the one that acts on the sidebar.
Gating to the blog index
The body-end hook renders on every page, so the opener is gated there on the
page’s .Path, which is the same in every locale: {{ if eq .Path "/blog" }}.
A .Path gate can’t single out the first page of a paginated list. Hugo renders
a list’s pager pages from the one section page, so .Path, .RelPermalink and
.Pages are identical on /blog/ and /blog/page/2/, and the current slice is
known only to the pager (.Paginator, or what .Paginate returned). Calling
.Paginator on a list page that Docsy’s template leaves unpaginated, such as an
empty blog, paginates it and publishes a page/1/ alias. The opener therefore
loads on every pager page and skips them at runtime, by testing
location.pathname for /page/.
Acting on the sidebar
The site uses Docsy’s cached sidebar (ui.sidebar_cache_limit: 1): one nav per
sidebar root, shipped hidden (d-none) with no active state. Docsy’s
chrome-nav.js hydrates it at DOMContentLoaded: it applies the active state
and reveals the nav. The blog index, like every section’s landing page, carries
that nav inline in both build kinds, so a body-end
script there runs during parsing, before the reveal, and can set sidebar state
before the sidebar appears; the opener checks its two year groups then. In a
lean build, other pages carry a placeholder instead, which chrome-nav.js fills
after fetching the nav, too late for a body-end script. With JavaScript
disabled, the sidebar stays hidden.