Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions assets/js/critical/sidebar-active.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@
// (section, version, language, variant) and cached, so the server no longer emits per-page
// `active` classes or an expanded collapse trail; this script applies them from the current
// location. It runs in the critical bundle so the highlight lands before first paint.
//
// Matching is exact first, nearest-ancestor second: a link whose path equals the current
// path always wins, and only when no link matches exactly does the longest link that is a
// path ancestor of the current page take over (flagged `aria-current="true"` rather than
// "page"). The ancestor pass is what keeps the trail highlighted for pages the menu cannot
// contain - a page built with `build.list = never`, or one generated by a content adapter,
// is absent from the page collections the menu is built from, so it has no entry of its own.
// Without the fallback nothing matched at all and the sidebar rendered with no active item
// and every group collapsed. Ancestor matching compares against `path + "/"`, so
// `/docs/guides` never claims `/docs/guides-advanced/`, and it skips links to the site root,
// which would otherwise claim every page on the site.
//
// Ancestor matching is a property of the link's href, so it needs no opt-in marker in the
// markup: every link in the nav is a candidate. Do not reintroduce one.
(function () {
'use strict'

Expand All @@ -15,7 +29,10 @@
var best = null
var bestLength = -1
var bestExact = false
nav.querySelectorAll('a[href]').forEach(function (link) {
// The brand logo is inside the <nav> but is not a menu entry: it points at the site
// home, so as an ancestor candidate it would match every page under it and light up
// the logo whenever nothing better was found.
nav.querySelectorAll('a[href]:not(.sidebar-brand)').forEach(function (link) {
var href = link.getAttribute('href')
if (!href || href.charAt(0) === '#') return
var url
Expand All @@ -28,8 +45,11 @@
bestLength = path.length
bestExact = true
}
} else if (!bestExact && link.getAttribute('data-sidebar-match') === 'prefix') {
var prefix = path === '/' ? '/' : path + '/'
} else if (!bestExact && path !== '/') {
// A link to the site root is an ancestor of every page, so it carries no locality:
// honouring it would light up a "Home"/"Overview" entry on pages that sit outside
// the menu entirely. Such a link still wins when it matches the path exactly.
var prefix = path + '/'
if (pathname.indexOf(prefix) === 0 && path.length > bestLength) {
best = link
bestLength = path.length
Expand Down
10 changes: 1 addition & 9 deletions layouts/_partials/assets/sidebar.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
<li class="mb-1">
<a class="sidebar-item text-decoration-none rounded w-100"
{{- if $collapsible }} data-sidebar-label="{{ $groupTitle }}"{{ end }}
{{ with $href }}href="{{ . }}" data-sidebar-match="prefix"{{ end }}>
{{ with $href }}href="{{ . }}"{{ end }}>
{{- with $pre -}}
{{- if hasPrefix . "<i" -}}
{{ . | safeHTML }}
Expand Down Expand Up @@ -220,7 +220,6 @@
{{- $data := .menu -}}
{{- $pre := .pre -}}
{{- $collapsible := .collapsible | default false -}}
{{- $prefixMatch := .prefixMatch | default false -}}
{{- $filename := .filename -}}
{{- $title = partial "utilities/TitleCase.html" (dict "page" $page "text" $title) -}}
{{- $titleText := $title -}}
Expand Down Expand Up @@ -259,9 +258,6 @@
{{- if and $collapsible $title $link -}}
{{- $link = $link | replaceRE `(<a)\s` (printf `${1} data-sidebar-label="%s" ` ($title | htmlEscape)) -}}
{{- end -}}
{{- if and $prefixMatch $link -}}
{{- $link = $link | replaceRE `(<a)\s` `${1} data-sidebar-match="prefix" ` -}}
{{- end -}}
{{ if $link }}
{{ print $link | safeHTML }}
{{ else }}
Expand All @@ -274,9 +270,6 @@
<li>
{{ $class := "sidebar-item text-decoration-none rounded small w-100" }}
{{ $link := partial "assets/link.html" (dict "href" $href "text" $itemText "class" $class "page" $page "exact" true "icon-mode" "svg") }}{{/* icon-mode "svg": same reason as the icon call sites - see the header comment. */}}
{{- if and $prefixMatch $link -}}
{{- $link = $link | replaceRE `(<a)\s` `${1} data-sidebar-match="prefix" ` -}}
{{- end -}}
{{ if $link }}
{{ print $link | safeHTML }}
{{ else }}
Expand Down Expand Up @@ -391,7 +384,6 @@
"menu" $args.menu
"pre" .pre
"collapsible" $collapsible
"prefixMatch" true
"filename" $args.filename
) }}
{{- end -}}
Expand Down