From 24239cfee6dbb5227dd1c93f8ba4c68abe4e48a0 Mon Sep 17 00:00:00 2001 From: Kilian Schulte Date: Mon, 27 Apr 2026 13:27:53 +0200 Subject: [PATCH 1/2] fix pagenav header for tutorial --- site/lib/src/client/global_scripts.dart | 40 +++++++++++++------ .../src/components/layout/client/pagenav.dart | 12 +++++- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/site/lib/src/client/global_scripts.dart b/site/lib/src/client/global_scripts.dart index cd902e9725d..dc6d0ee4bdc 100644 --- a/site/lib/src/client/global_scripts.dart +++ b/site/lib/src/client/global_scripts.dart @@ -318,11 +318,12 @@ void _setUpToc() { _setUpTocActiveObserver(); } +final ValueNotifier showPageTitle = ValueNotifier(true); final ValueNotifier currentPageHeading = ValueNotifier(null); void _setUpTocActiveObserver() { final headings = web.document.querySelectorAll( - 'article .header-wrapper, #site-content-title', + 'article .header-wrapper, article .stepper .step-title, #site-content-title', ); // No need to have toc scrollspy if there is only one non-title heading. @@ -334,7 +335,8 @@ void _setUpTocActiveObserver() { ((JSArray entries) { for (var i = 0; i < entries.length; i++) { final entry = entries[i]; - final headingId = entry.target.querySelector('h1, h2, h3')?.id; + final heading = entry.target.querySelector('h1, h2, h3'); + final headingId = heading?.id; if (headingId == null) return; if (entry.isIntersecting) { @@ -344,18 +346,19 @@ void _setUpTocActiveObserver() { } } - if (visibleAnchors.isNotEmpty) { - var isFirst = true; + var isFirst = true; - // If the page title is visible, set the current header to its contents. - if (visibleAnchors.contains('document-title')) { - currentPageHeading.value = null; - isFirst = false; - } + // If the page title is visible, set the current header to its contents. + if (visibleAnchors.contains('document-title')) { + showPageTitle.value = true; + } else { + showPageTitle.value = false; + } - final tocLinks = web.document.querySelectorAll( - '.toc-list .sidenav-item a', - ); + final tocLinks = web.document.querySelectorAll( + '.toc-list .sidenav-item a', + ); + if (tocLinks.length > 0) { for (var i = 0; i < tocLinks.length; i++) { final tocLink = tocLinks.item(i) as web.Element; final headingId = tocLink.getAttribute('href')?.substring(1); @@ -405,6 +408,11 @@ void _setUpSteppers() { for (var j = 0; j < steps.length; j++) { final step = steps[j]; + final header = step.querySelector('summary h2, summary h3'); + + if (header?.textContent case final title? when step.open) { + currentPageHeading.value = title; + } if (collapsible) { step.addEventListener( @@ -418,6 +426,10 @@ void _setUpSteppers() { otherStep.open = false; } } + + if (header?.textContent case final title?) { + currentPageHeading.value = title; + } } }).toJS, ); @@ -437,6 +449,10 @@ void _setUpSteppers() { final nextStep = steps[j + 1]; nextStep.open = true; _scrollTo(nextStep, smooth: true); + + if (header?.textContent case final title?) { + currentPageHeading.value = title; + } } }).toJS, ); diff --git a/site/lib/src/components/layout/client/pagenav.dart b/site/lib/src/components/layout/client/pagenav.dart index 1477716478e..c4536801ea4 100644 --- a/site/lib/src/components/layout/client/pagenav.dart +++ b/site/lib/src/components/layout/client/pagenav.dart @@ -105,9 +105,17 @@ class _PageNavState extends State { span(classes: 'toc-current', [ ValueListenableBuilder( - listenable: currentPageHeading, + listenable: showPageTitle, builder: (context, value) { - return span([.text(value ?? component.initialHeading)]); + if (value) { + return span([.text(component.initialHeading)]); + } + return ValueListenableBuilder( + listenable: currentPageHeading, + builder: (context, value) { + return span([.text(value ?? component.initialHeading)]); + }, + ); }, ), ]), From 8e875f6f7b3d0756124fa7d0623adc7c0061770f Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Mon, 27 Apr 2026 15:18:35 +0200 Subject: [PATCH 2/2] Apply review suggestions and additional cleanup --- site/lib/src/client/global_scripts.dart | 30 +++++++++---------- .../src/components/layout/client/pagenav.dart | 4 +-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/site/lib/src/client/global_scripts.dart b/site/lib/src/client/global_scripts.dart index dc6d0ee4bdc..fe15df697be 100644 --- a/site/lib/src/client/global_scripts.dart +++ b/site/lib/src/client/global_scripts.dart @@ -323,7 +323,9 @@ final ValueNotifier currentPageHeading = ValueNotifier(null); void _setUpTocActiveObserver() { final headings = web.document.querySelectorAll( - 'article .header-wrapper, article .stepper .step-title, #site-content-title', + 'article .header-wrapper, ' + 'article .stepper .step-title, ' + '#site-content-title', ); // No need to have toc scrollspy if there is only one non-title heading. @@ -337,7 +339,7 @@ void _setUpTocActiveObserver() { final entry = entries[i]; final heading = entry.target.querySelector('h1, h2, h3'); final headingId = heading?.id; - if (headingId == null) return; + if (headingId == null) continue; if (entry.isIntersecting) { visibleAnchors.add(headingId); @@ -346,19 +348,14 @@ void _setUpTocActiveObserver() { } } - var isFirst = true; - - // If the page title is visible, set the current header to its contents. - if (visibleAnchors.contains('document-title')) { - showPageTitle.value = true; - } else { - showPageTitle.value = false; - } + // If the page title is visible, show it instead of the active heading. + showPageTitle.value = visibleAnchors.contains('document-title'); final tocLinks = web.document.querySelectorAll( '.toc-list .sidenav-item a', ); if (tocLinks.length > 0) { + var isFirst = true; for (var i = 0; i < tocLinks.length; i++) { final tocLink = tocLinks.item(i) as web.Element; final headingId = tocLink.getAttribute('href')?.substring(1); @@ -410,11 +407,11 @@ void _setUpSteppers() { final step = steps[j]; final header = step.querySelector('summary h2, summary h3'); - if (header?.textContent case final title? when step.open) { - currentPageHeading.value = title; - } - if (collapsible) { + if (header?.textContent case final title? when step.open) { + currentPageHeading.value = title; + } + step.addEventListener( 'toggle', ((web.Event e) { @@ -450,7 +447,10 @@ void _setUpSteppers() { nextStep.open = true; _scrollTo(nextStep, smooth: true); - if (header?.textContent case final title?) { + final nextHeader = nextStep.querySelector( + 'summary h2, summary h3', + ); + if (nextHeader?.textContent case final title?) { currentPageHeading.value = title; } } diff --git a/site/lib/src/components/layout/client/pagenav.dart b/site/lib/src/components/layout/client/pagenav.dart index c4536801ea4..49ce5b72307 100644 --- a/site/lib/src/components/layout/client/pagenav.dart +++ b/site/lib/src/components/layout/client/pagenav.dart @@ -112,8 +112,8 @@ class _PageNavState extends State { } return ValueListenableBuilder( listenable: currentPageHeading, - builder: (context, value) { - return span([.text(value ?? component.initialHeading)]); + builder: (context, heading) { + return span([.text(heading ?? component.initialHeading)]); }, ); },