Skip to content

Commit 2104cd1

Browse files
committed
TCR-772 : fix(sidebar): handle bottom-of-page and short document highlighting
- Add isAtBottom() function to detect when user scrolls near page bottom - When at bottom, select last heading above viewport center - Fixes issue where bottom sections never get highlighted - Ensures accurate highlighting for short documents
1 parent 4690c25 commit 2104cd1

File tree

1 file changed

+35
-4
lines changed

1 file changed

+35
-4
lines changed

docs/.vuepress/theme/sidebar/Sidebar.vue

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,23 @@ const throttle = (func, delay) => {
9595
}
9696
}
9797
98+
// Check if user has scrolled to the bottom of the page
99+
const isAtBottom = () => {
100+
const scrollHeight = document.documentElement.scrollHeight
101+
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
102+
const clientHeight = document.documentElement.clientHeight
103+
// Consider "at bottom" if within 100px of the bottom
104+
return scrollHeight - scrollTop - clientHeight < 100
105+
}
106+
98107
// Update sidebar active state based on the topmost visible heading
99108
const updateSidebarActiveState = () => {
100109
const sidebar = document.querySelector('.sidebar')
101110
if (!sidebar) return
102111
103112
const sidebarAnchors = sidebar.querySelectorAll('a')
104113
const sidebarAnchorsContainer = sidebar.querySelectorAll('.collapsible.sidebar-sub-header')
114+
const pageAnchors = document.querySelectorAll('.header-anchor')
105115
106116
// Get all visible headings sorted by their position (topmost first)
107117
const sortedVisibleHeadings = Array.from(visibleHeadings.value).sort((a, b) => {
@@ -110,12 +120,33 @@ const updateSidebarActiveState = () => {
110120
return aRect.top - bRect.top
111121
})
112122
113-
// Select the topmost visible heading
114-
const topmostHeading = sortedVisibleHeadings[0]
123+
let targetHeading = null
124+
125+
// If at bottom of page, select the last heading that's above the viewport center
126+
if (isAtBottom() && pageAnchors.length > 0) {
127+
const viewportCenter = window.innerHeight / 2
128+
const allAnchorsArray = Array.from(pageAnchors)
129+
130+
// Find all headings that are above the viewport center
131+
const headingsAboveCenter = allAnchorsArray.filter(anchor => {
132+
const rect = anchor.getBoundingClientRect()
133+
return rect.top < viewportCenter
134+
})
135+
136+
// Select the last one (closest to bottom)
137+
if (headingsAboveCenter.length > 0) {
138+
targetHeading = headingsAboveCenter[headingsAboveCenter.length - 1]
139+
}
140+
}
141+
142+
// If not at bottom or no heading found, use the topmost visible heading
143+
if (!targetHeading && sortedVisibleHeadings.length > 0) {
144+
targetHeading = sortedVisibleHeadings[0]
145+
}
115146
116-
if (!topmostHeading) return
147+
if (!targetHeading) return
117148
118-
const currentAnchor = topmostHeading.getAttribute('data-anchor')
149+
const currentAnchor = targetHeading.getAttribute('data-anchor')
119150
120151
// Update active class on sidebar links
121152
sidebarAnchors.forEach(a => a.classList.remove('active'))

0 commit comments

Comments
 (0)