Skip to content

Commit 8f59abc

Browse files
committed
Refactor
1 parent ead88c6 commit 8f59abc

File tree

2 files changed

+19
-72
lines changed

2 files changed

+19
-72
lines changed

src/Elastic.Markdown/Assets/toc-nav.ts

Lines changed: 17 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import { $$, $ } from 'select-dom';
33
interface TocElements {
44
headings: Element[];
55
tocLinks: HTMLAnchorElement[];
6-
tocNav: HTMLUListElement | null;
7-
markdownContent: Element | null;
6+
tocContainer: HTMLUListElement | null;
87
progressIndicator: HTMLDivElement;
98
}
109

@@ -14,51 +13,23 @@ const HEADING_OFFSET = 28 * 4 + 6 * 4;
1413
function initializeTocElements(): TocElements {
1514
const headings = $$('h2, h3');
1615
const tocLinks = $$('#toc-nav li>a') as HTMLAnchorElement[];
17-
const tocNav = $('#toc-nav ul') as HTMLUListElement;
18-
const markdownContent = $('.markdown-content') || null;
19-
20-
// Create progress indicator
21-
const progressIndicator = document.createElement('div');
22-
progressIndicator.className = 'toc-progress-indicator';
23-
tocNav?.appendChild(progressIndicator);
24-
25-
return { headings, tocLinks, tocNav, markdownContent, progressIndicator };
26-
}
27-
28-
// Add required styles for the progress indicator
29-
function addProgressIndicatorStyles() {
30-
const style = document.createElement('style');
31-
style.textContent = `
32-
#toc-nav ul {
33-
position: relative;
34-
}
35-
.toc-progress-indicator {
36-
position: absolute;
37-
left: calc(var(--spacing) * 2);
38-
width: 1px;
39-
background: var(--color-blue-elastic);
40-
transition: top 250ms ease-out, height 250ms ease-out;
41-
}
42-
`;
43-
document.head.appendChild(style);
16+
const tocContainer = $('#toc-nav ul') as HTMLUListElement;
17+
const progressIndicator = $('.toc-progress-indicator', tocContainer) as HTMLDivElement;
18+
return { headings, tocLinks, tocContainer,progressIndicator };
4419
}
4520

4621
// Find the current TOC links based on visible headings
22+
// It can return multiple links because headings in a tab can have the same position
4723
function findCurrentTocLinks(elements: TocElements): HTMLAnchorElement[] {
4824
let currentTocLinks: HTMLAnchorElement[] = [];
4925
let currentTop: number | null = null;
50-
5126
for (const heading of elements.headings) {
5227
const rect = heading.getBoundingClientRect();
53-
const headingText = heading.textContent?.trim() ?? '';
54-
5528
if (rect.top <= HEADING_OFFSET) {
56-
// If we find a heading at a new height, clear previous links
5729
if (currentTop !== null && Math.abs(rect.top - currentTop) > 1) {
5830
currentTocLinks = [];
5931
}
6032
currentTop = rect.top;
61-
6233
const foundLink = elements.tocLinks.find(link =>
6334
link.getAttribute('href') === `#${heading.closest('section')?.id}`
6435
);
@@ -67,7 +38,6 @@ function findCurrentTocLinks(elements: TocElements): HTMLAnchorElement[] {
6738
}
6839
}
6940
}
70-
7141
return currentTocLinks;
7242
}
7343

@@ -82,29 +52,19 @@ function getVisibleHeadings(elements: TocElements) {
8252
// Handle bottom of page scroll behavior
8353
function handleBottomScroll(elements: TocElements) {
8454
const visibleHeadings = getVisibleHeadings(elements);
85-
86-
visibleHeadings.forEach(heading => {
87-
console.log(heading.textContent.trim());
88-
})
89-
9055
if (visibleHeadings.length === 0) return;
91-
9256
const firstHeading = visibleHeadings[0];
9357
const lastHeading = visibleHeadings[visibleHeadings.length - 1];
94-
9558
const firstLink = elements.tocLinks.find(link =>
96-
link.getAttribute('href') === `#${firstHeading.closest('section')?.id}`
59+
link.getAttribute('href') === `#${firstHeading.parentElement?.id}`
9760
)?.closest('li');
98-
9961
const lastLink = elements.tocLinks.find(link =>
100-
link.getAttribute('href') === `#${lastHeading.closest('section')?.id}`
62+
link.getAttribute('href') === `#${lastHeading.parentElement?.id}`
10163
)?.closest('li');
102-
103-
if (firstLink && lastLink && elements.tocNav) {
104-
const tocRect = elements.tocNav.getBoundingClientRect();
64+
if (firstLink && lastLink && elements.tocContainer) {
65+
const tocRect = elements.tocContainer.getBoundingClientRect();
10566
const firstRect = firstLink.getBoundingClientRect();
10667
const lastRect = lastLink.getBoundingClientRect();
107-
10868
updateProgressIndicatorPosition(
10969
elements.progressIndicator,
11070
firstRect.top - tocRect.top,
@@ -113,7 +73,6 @@ function handleBottomScroll(elements: TocElements) {
11373
}
11474
}
11575

116-
// Update progress indicator position and height
11776
function updateProgressIndicatorPosition(
11877
indicator: HTMLDivElement,
11978
top: number,
@@ -123,28 +82,22 @@ function updateProgressIndicatorPosition(
12382
indicator.style.height = `${height}px`;
12483
}
12584

126-
// Main update function for the indicator
12785
function updateIndicator(elements: TocElements) {
128-
if (!elements.markdownContent || !elements.tocNav) return;
86+
if (!elements.tocContainer) return;
12987

13088
const isAtBottom = window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 10;
13189
const currentTocLinks = findCurrentTocLinks(elements);
13290

13391
if (isAtBottom) {
13492
handleBottomScroll(elements);
13593
} else if (currentTocLinks.length > 0) {
136-
const tocRect = elements.tocNav.getBoundingClientRect();
137-
138-
// Find the topmost and bottommost link positions
94+
const tocRect = elements.tocContainer.getBoundingClientRect();
13995
const linkElements = currentTocLinks
14096
.map(link => link.closest('li'))
14197
.filter((li): li is HTMLLIElement => li !== null);
142-
14398
if (linkElements.length === 0) return;
144-
14599
const firstLinkRect = linkElements[0].getBoundingClientRect();
146100
const lastLinkRect = linkElements[linkElements.length - 1].getBoundingClientRect();
147-
148101
updateProgressIndicatorPosition(
149102
elements.progressIndicator,
150103
firstLinkRect.top - tocRect.top,
@@ -153,8 +106,7 @@ function updateIndicator(elements: TocElements) {
153106
}
154107
}
155108

156-
// Handle smooth scrolling for TOC links
157-
function setupTocLinkHandlers(elements: TocElements) {
109+
function setupSmoothScrolling(elements: TocElements) {
158110
elements.tocLinks.forEach(link => {
159111
link.addEventListener('click', (e) => {
160112
const href = link.getAttribute('href');
@@ -172,17 +124,11 @@ function setupTocLinkHandlers(elements: TocElements) {
172124

173125
export function initTocNav() {
174126
const elements = initializeTocElements();
175-
addProgressIndicatorStyles();
176-
177-
// Initialize indicator position
178127
elements.progressIndicator.style.height = '0';
179128
elements.progressIndicator.style.top = '0';
180-
181-
// Set up event listeners
182-
const boundUpdateIndicator = () => updateIndicator(elements);
183-
window.addEventListener('scroll', boundUpdateIndicator);
184-
window.addEventListener('resize', boundUpdateIndicator);
185-
186-
setupTocLinkHandlers(elements);
187-
boundUpdateIndicator();
129+
const update = () => updateIndicator(elements)
130+
window.addEventListener('scroll', update);
131+
window.addEventListener('resize', update);
132+
setupSmoothScrolling(elements);
133+
update();
188134
}

src/Elastic.Markdown/Slices/Layout/_TableOfContents.cshtml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
{
99
<div class="mb-4">
1010
<div class="font-bold mb-2">On this page</div>
11-
<ul class="block w-full">
11+
<ul class="block w-full relative">
12+
<div class="toc-progress-indicator absolute top-0 h-0 left-2 w-[1px] bg-blue-elastic transition-all duration-200 ease-out "></div>
1213
@foreach (var item in Model.PageTocItems)
1314
{
1415
<li class="flex has-[:hover]:border-l-gray-500 items-center ml-2 pl-4 border-l-1 border-l-gray-200 has-[.current]:border-l-blue-elastic!">

0 commit comments

Comments
 (0)