@@ -129,50 +129,66 @@ export interface Props {
129
129
130
130
<script >
131
131
import lodash from "lodash";
132
+ import * as utils from "~/util/DOM";
132
133
133
- const headings = document.querySelectorAll(
134
- "article .heading,.article-metadata h1"
135
- );
136
- const outline = document.querySelector("#outline .content");
134
+ const outline = utils.assertElement("#outline .content");
135
+ const centerColumn = utils.assertElement<HTMLDivElement>(".columns .center");
137
136
137
+ let init = true;
138
138
let topLink: HTMLAnchorElement;
139
- const intersectionObserver = new IntersectionObserver((entries) => {
140
- for (const entry of entries) {
141
- const outlineLink = outline?.querySelector(
142
- `a[href="#${entry.target.id}"]`
143
- );
144
-
145
- if (entry.intersectionRatio > 0) {
146
- outlineLink?.classList.add("in-view");
147
- topLink = outlineLink as HTMLAnchorElement;
148
- } else {
149
- outlineLink?.classList.remove("in-view");
139
+ const scrollOutline = lodash.debounce(
140
+ (smooth = true) => {
141
+ if (init) {
142
+ smooth = false;
143
+ init = false;
144
+
145
+ // Flush debounced outline scroll functions when scrollend is fired (if browser supports it)
146
+ document.addEventListener("scrollend", () => scrollOutline.flush());
147
+ centerColumn.addEventListener("scrollend", () => scrollOutline.flush());
150
148
}
151
- }
152
- });
153
149
154
- headings.forEach((heading) => intersectionObserver.observe(heading));
155
-
156
- const scrollOutline = lodash.debounce(
157
- () => {
158
- outline?.scrollTo({
150
+ outline.scrollTo({
159
151
top: topLink.offsetTop - outline.clientHeight / 2,
160
- behavior: "smooth",
152
+ behavior: smooth === false ? "instant" : "smooth",
161
153
});
162
154
},
163
155
50,
164
156
{ leading: false, trailing: true }
165
157
);
166
158
167
- const centerColumn =
168
- document.querySelector<HTMLDivElement>(".columns .center");
159
+ const intersectionObserver = new IntersectionObserver((entries) => {
160
+ for (const entry of entries) {
161
+ const outlineLink = utils.assertElement<HTMLAnchorElement>(
162
+ `a[href="#${entry.target.id}"]`,
163
+ outline
164
+ );
169
165
170
- document.addEventListener("scroll", scrollOutline);
171
- centerColumn?.addEventListener("scroll", scrollOutline);
166
+ if (entry.intersectionRatio > 0 && outlineLink) {
167
+ outlineLink.classList.add("in-view");
168
+ topLink = outlineLink;
169
+ } else {
170
+ outlineLink.classList.remove("in-view");
171
+ }
172
+ }
173
+ });
174
+
175
+ // Watch headings for intersections
176
+ utils
177
+ .assertElements("article .heading,.article-metadata h1")
178
+ .forEach((heading) => intersectionObserver.observe(heading));
179
+
180
+ // Watch for article scrolling to scroll outline
181
+ document.addEventListener("scroll", () => scrollOutline());
182
+ centerColumn.addEventListener("scroll", () => scrollOutline());
172
183
173
- // Flush debounced outline scroll functions when scrollend is fired (if browser supports it)
174
- document.addEventListener("scrollend", () => scrollOutline.flush());
175
- centerColumn?.addEventListener("scrollend", () => scrollOutline.flush());
184
+ // Force browser to scroll to targeted heading on page load
185
+ const target = centerColumn.querySelector<HTMLHeadingElement>(
186
+ `article ${location.hash}`
187
+ );
188
+ if (target) {
189
+ console.log("SCROLLING TO TARGET ON PAGE LOAD");
190
+ target.scrollIntoView();
191
+ }
176
192
</script >
177
193
178
194
<style lang =" scss" >
0 commit comments