Skip to content

Commit 6894011

Browse files
committed
Cross-package indexes, store-based navigation sources, instant scroll
1 parent 6ea2719 commit 6894011

14 files changed

Lines changed: 111 additions & 35 deletions

src/lib/components/api/ApiToc.svelte

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,31 @@
11
<script lang="ts">
2+
import { onDestroy } from 'svelte';
23
import type { APIModule } from '$lib/api/generated';
34
import Icon from '$lib/components/common/Icon.svelte';
45
import { searchTarget } from '$lib/stores/searchNavigation';
56
7+
// Track navigation timeout for cleanup
8+
let navigationTimeout: ReturnType<typeof setTimeout> | null = null;
9+
10+
function clearNavigationTimeout() {
11+
if (navigationTimeout) {
12+
clearTimeout(navigationTimeout);
13+
navigationTimeout = null;
14+
}
15+
}
16+
17+
function setNavigationTimeout() {
18+
clearNavigationTimeout();
19+
navigationTimeout = setTimeout(() => {
20+
isNavigating = false;
21+
navigationTimeout = null;
22+
}, 50); // Short delay for instant scroll
23+
}
24+
25+
onDestroy(() => {
26+
clearNavigationTimeout();
27+
});
28+
629
interface Props {
730
modules: APIModule[];
831
onNavigate?: (id: string) => void;
@@ -74,7 +97,7 @@
7497
function scrollToElement(id: string) {
7598
const element = document.getElementById(id);
7699
if (element) {
77-
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
100+
element.scrollIntoView({ block: 'start' });
78101
activeId = id;
79102
onNavigate?.(id);
80103
}
@@ -86,11 +109,8 @@
86109
function navigateToClass(className: string) {
87110
isNavigating = true;
88111
activeId = className; // Set immediately for visual feedback
89-
searchTarget.set({ name: className, type: 'class' });
90-
// Re-enable observer after scroll animation completes
91-
setTimeout(() => {
92-
isNavigating = false;
93-
}, 500);
112+
searchTarget.set({ name: className, type: 'class', source: 'toc' });
113+
setNavigationTimeout();
94114
}
95115
96116
/**
@@ -99,11 +119,8 @@
99119
function navigateToFunction(funcName: string) {
100120
isNavigating = true;
101121
activeId = funcName; // Set immediately for visual feedback
102-
searchTarget.set({ name: funcName, type: 'function' });
103-
// Re-enable observer after scroll animation completes
104-
setTimeout(() => {
105-
isNavigating = false;
106-
}, 500);
122+
searchTarget.set({ name: funcName, type: 'function', source: 'toc' });
123+
setNavigationTimeout();
107124
}
108125
109126
function getModuleId(moduleName: string): string {
@@ -162,11 +179,14 @@
162179
expandedGroups = newExpanded;
163180
}
164181
165-
// Watch for search/crossref navigation and expand to reveal target
182+
// Watch for external navigation (search, crossref, url) and expand TOC to reveal target
166183
$effect(() => {
167184
const target = $searchTarget;
168185
if (!target) return;
169186
187+
// Skip TOC-initiated navigation (we already handled it)
188+
if (target.source === 'toc') return;
189+
170190
// Find which module contains the target
171191
let modulePath: string | null = null;
172192
@@ -194,10 +214,7 @@
194214
activeId = getModuleId(modulePath);
195215
}
196216
197-
// Re-enable observer after scroll completes
198-
setTimeout(() => {
199-
isNavigating = false;
200-
}, 500);
217+
setNavigationTimeout();
201218
}
202219
});
203220

src/lib/components/api/ClassDoc.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
isExpanded = true;
8989
clearSearchTarget();
9090
tick().then(() => {
91-
tileElement?.scrollIntoView({ behavior: 'smooth', block: 'start' });
91+
tileElement?.scrollIntoView({ block: 'start' });
9292
});
9393
}
9494
// Method inside this class - expand so method can be found

src/lib/components/api/DocstringRenderer.svelte

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@
105105
e.preventDefault();
106106
searchTarget.set({
107107
name: target.name,
108-
type: target.type as 'class' | 'function' | 'method' | 'module'
108+
type: target.type as 'class' | 'function' | 'method' | 'module',
109+
source: 'crossref'
109110
});
110111
goto(fullPath);
111112
});
@@ -387,7 +388,8 @@
387388
// Set search target to trigger expansion/scroll
388389
searchTarget.set({
389390
name: targetName,
390-
type: linkType as 'class' | 'function' | 'method' | 'module'
391+
type: linkType as 'class' | 'function' | 'method' | 'module',
392+
source: 'crossref'
391393
});
392394
}
393395

src/lib/components/api/FunctionDoc.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
isExpanded = true;
9696
clearSearchTarget();
9797
tick().then(() => {
98-
tileElement?.scrollIntoView({ behavior: 'smooth', block: 'start' });
98+
tileElement?.scrollIntoView({ block: 'start' });
9999
});
100100
}
101101
});

src/lib/components/api/ModuleDoc.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
if (target.type === 'module' && target.name === module.name) {
2323
clearSearchTarget();
2424
tick().then(() => {
25-
sectionElement?.scrollIntoView({ behavior: 'smooth', block: 'start' });
25+
sectionElement?.scrollIntoView({ block: 'start' });
2626
});
2727
}
2828
});

src/lib/components/api/TypeRef.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@
7979
8080
searchTarget.set({
8181
name: target.name,
82-
type: target.type as 'class' | 'function' | 'method' | 'module'
82+
type: target.type as 'class' | 'function' | 'method' | 'module',
83+
source: 'crossref'
8384
});
8485
8586
// target.path is relative like pathsim/api#ClassName, prepend base/ for absolute URL

src/lib/components/common/MarkdownRenderer.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,8 @@
287287
// Set search target to trigger expansion/scroll
288288
searchTarget.set({
289289
name: targetName,
290-
type: linkType as 'class' | 'function' | 'method' | 'module'
290+
type: linkType as 'class' | 'function' | 'method' | 'module',
291+
source: 'crossref'
291292
});
292293
}
293294

src/lib/components/common/RstRenderer.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,8 @@
288288
// Set search target to trigger expansion/scroll
289289
searchTarget.set({
290290
name: targetName,
291-
type: linkType as 'class' | 'function' | 'method' | 'module'
291+
type: linkType as 'class' | 'function' | 'method' | 'module',
292+
source: 'crossref'
292293
});
293294
}
294295

src/lib/components/examples/ExamplesToc.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
function scrollTo(id: string) {
4141
const element = document.getElementById(id);
4242
if (element) {
43-
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
43+
element.scrollIntoView({ block: 'start' });
4444
activeId = id;
4545
}
4646
}

src/lib/components/layout/Sidebar.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@
9292
searchTarget.set({
9393
name: result.name,
9494
type: result.type,
95-
parentClass: result.parentClass
95+
parentClass: result.parentClass,
96+
source: 'search'
9697
});
9798
goto(`${base}/${result.path}`);
9899
}

0 commit comments

Comments
 (0)