-
Notifications
You must be signed in to change notification settings - Fork 5
TOC expand-collapse icons #659
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,3 +5,4 @@ import "sticky-sidebar"; | |
| import "./util"; | ||
| import "./crate"; | ||
| import "./custom"; | ||
| import "./toc-toggle"; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| /** | ||
| * TOC Navigation Expand/Collapse Toggle | ||
| * | ||
| * This module adds interactive expand/collapse functionality to the table of | ||
| * contents (TOC) navigation sidebar. It allows users to click on parent items | ||
| * to show/hide their children. | ||
| * | ||
| * Features: | ||
| * - Click on items with children to toggle expand/collapse | ||
| * - Auto-expand current page's parent hierarchy | ||
| * - Add .has-children class for browsers without :has() support | ||
| * - ARIA attributes for accessibility | ||
| */ | ||
|
Comment on lines
+1
to
+13
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi. Is it using the implementation from Furo like planned?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not at all.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I should have clarified better: While the patch referenced above is about bringing in alternative navigation definition mechanics, it demonstrates that all the CSS/JS elements to support Furo's navigation runtime mechanics are already included into the assets bundle, so I was wondering if we can use those instead of bringing in a separate implementation about the same topic.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me be more explicit by referring to relevant components of Furo defined in
I didn't dive into finding out how the currently defined navigation can be connected to those Furo mechanics, also because my patch was exploring another direction. If you can make sense how to connect the HTML in
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Furo's
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the pointers!
The main (80%) value is already achieved through this PR, but I can take a look.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Excellent, thanks. Please proceed at your disposal. |
||
|
|
||
| /** | ||
| * Initialize TOC toggle behavior | ||
| */ | ||
| function initTocToggle() { | ||
| // Only initialize if the toc-toggle-icons-enabled class is present | ||
| const sidebar = document.querySelector('.toc-toggle-icons-enabled .bs-docs-sidenav'); | ||
| if (!sidebar) { | ||
| return; | ||
| } | ||
|
|
||
| const tocItems = sidebar.querySelectorAll('.toctree li'); | ||
|
|
||
| tocItems.forEach(item => { | ||
| // Check if item has direct ul children (already rendered) | ||
| const hasDirectChildren = item.querySelector(':scope > ul'); | ||
|
|
||
| // Check if the link suggests this is a parent page (links to index.html or has children) | ||
| const link = item.querySelector(':scope > a'); | ||
| const linkHref = link ? link.getAttribute('href') : ''; | ||
| const linksToIndex = linkHref && (linkHref.endsWith('/index.html') || linkHref.includes('/index.html#')); | ||
|
|
||
| // Check if this item is alone in its parent <ul> (no siblings) | ||
| // Items with children are typically alone in their own <ul> block | ||
| const parentUl = item.parentElement; | ||
| const siblings = parentUl ? parentUl.querySelectorAll(':scope > li') : []; | ||
| const isAloneInUl = siblings.length === 1; | ||
|
|
||
| // Determine if item has or could have children: | ||
| // - Has direct children already rendered, OR | ||
| // - Links to index.html AND is alone in its <ul> (likely a section with children) | ||
| const hasChildren = hasDirectChildren || (linksToIndex && isAloneInUl); | ||
| if (!hasChildren) return; | ||
|
|
||
| // Add .has-children class for browsers without :has() support | ||
| item.classList.add('has-children'); | ||
|
|
||
| // Link was already found above, skip if not found | ||
| if (!link) return; | ||
|
|
||
| // Mark as expanded if in current path | ||
| const isCurrentPath = item.classList.contains('current') || | ||
| item.classList.contains('active'); | ||
| if (isCurrentPath) { | ||
| item.classList.add('expanded'); | ||
| } | ||
|
|
||
| link.setAttribute('aria-expanded', item.classList.contains('expanded').toString()); | ||
|
|
||
| // Add click handler to toggle expansion (only if item has direct children to toggle) | ||
| if (hasDirectChildren) { | ||
| link.addEventListener('click', (e) => { | ||
| // Check if clicking on the icon area (right side) | ||
| const linkRect = link.getBoundingClientRect(); | ||
| const clickX = e.clientX - linkRect.left; | ||
| const linkWidth = linkRect.width; | ||
|
|
||
| // If clicking in the last 30px (icon area), toggle instead of navigate | ||
| if (clickX > linkWidth - 30) { | ||
bmunkholm marked this conversation as resolved.
Show resolved
Hide resolved
bmunkholm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| e.preventDefault(); | ||
| toggleItem(item, link); | ||
| } | ||
| }); | ||
| } | ||
| // For items that link to index.html but don't have children rendered yet, | ||
| // clicking the icon will navigate to the page (normal link behavior) | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Toggle expand/collapse state of a TOC item | ||
| * @param {HTMLElement} item - The list item element | ||
| * @param {HTMLElement} link - The anchor element | ||
| */ | ||
| function toggleItem(item, link) { | ||
| const isExpanded = item.classList.toggle('expanded'); | ||
| link.setAttribute('aria-expanded', isExpanded.toString()); | ||
| } | ||
|
|
||
| // Run after DOM is ready | ||
| if (document.readyState === 'loading') { | ||
| document.addEventListener('DOMContentLoaded', initTocToggle); | ||
| } else { | ||
| // DOM already loaded | ||
| initTocToggle(); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.