Skip to content

Commit fc7e128

Browse files
authored
Move the in-page nav into the main content (#504)
Closes canjs/canjs#4744
1 parent bc1bdb3 commit fc7e128

16 files changed

+372
-177
lines changed

make-example.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ var siteConfig = {
2828
// we get an error without this, here, though
2929
"steal-stache": "^4.0.1",
3030
"steal-conditional": "^0.3.6",
31-
"bit-docs-html-codepen-link": "^1.0.0"
31+
"bit-docs-html-codepen-link": "^1.0.0",
32+
"bit-docs-html-toc": "^1.1.1"
3233
},
3334
staticDist: [
3435
path.join(__dirname, "dist", "static")

static/canjs.js

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,108 @@ function init() {
156156
sidebarViewModel.selectedPageName = window.docObject.name;
157157
}
158158

159+
// Set up the client-side TOC
160+
var tocContainer = document.querySelector("#toc-sidebar nav");
161+
var oldToc = document.querySelector("bit-toc");
162+
if (oldToc) {
163+
tocContainer.removeChild(oldToc);
164+
}
165+
var newToc = document.createElement("bit-toc");
166+
newToc.depth = parseInt(window.docObject.outline, 10) || 1;
167+
newToc.headingsContainerSelector = "body";
168+
newToc.scrollSelector = "#toc-sidebar";
169+
newToc.highlight = function() {
170+
var articleRect = this.article.getBoundingClientRect();
171+
var buttons = this.buttons;
172+
var positions = this.titles.map(function(header, i) {
173+
return {
174+
header: header,
175+
rect: header.getBoundingClientRect(),
176+
button: buttons[i]
177+
};
178+
});
179+
positions.push({ rect: { top: articleRect.top + this.article.scrollHeight - this.article.scrollTop } });
180+
positions.slice(0, positions.length - 1).forEach(function(position, index) {
181+
position.button.classList.remove('completed', 'active');
182+
var curRect = position.rect;
183+
var curDistance = curRect.top;// was - articleRect.top
184+
var nextRect = positions[index + 1].rect;
185+
var nextDistance = nextRect.top;// was - articleRect.top
186+
if (nextDistance >= 0 && nextDistance <= articleRect.height && curDistance >= 0 && curDistance <= articleRect.height) {
187+
var lastPosition = positions[index - 1];
188+
if (lastPosition) {
189+
lastPosition.button.classList.add('completed');
190+
}
191+
position.button.classList.add('active');
192+
} else if (nextDistance < articleRect.height / 2) {
193+
position.button.classList.add('completed');
194+
} else if (nextDistance >= articleRect.height / 2 && curDistance < articleRect.height / 2) {
195+
var lastPosition = positions[index - 1];
196+
if (lastPosition) {
197+
lastPosition.button.classList.add('completed');
198+
}
199+
position.button.classList.add('active');
200+
}
201+
});
202+
203+
// Get the last element in the nav that’s highlighted
204+
var activeOrCompleted = this.querySelectorAll(".active,.completed");
205+
var lastActiveOrCompleted = activeOrCompleted[activeOrCompleted.length - 1];
206+
if (lastActiveOrCompleted) {
207+
lastActiveOrCompleted = lastActiveOrCompleted.querySelector('a');
208+
209+
// Check to see if it’s in viewport
210+
var lastActiveOrCompletedRect = lastActiveOrCompleted.getBoundingClientRect();
211+
var sidebarElement = this.outlineScrollElement;
212+
var topInset = sidebarElement.getBoundingClientRect().top;// Main nav height
213+
var viewportHeight = window.innerHeight;
214+
var lastActiveOrCompletedRectIsInViewport = (
215+
lastActiveOrCompletedRect.bottom <= viewportHeight &&
216+
lastActiveOrCompletedRect.left >= 0 &&
217+
lastActiveOrCompletedRect.left <= window.innerWidth &&
218+
lastActiveOrCompletedRect.top >= topInset &&
219+
lastActiveOrCompletedRect.top <= viewportHeight
220+
);
221+
if (lastActiveOrCompletedRectIsInViewport === false) {
222+
// Scroll the sidebar so the highlighted element is in the viewport
223+
var visibleSidebarHeight = sidebarElement.offsetHeight;// Not the entire height, just what’s visible in the viewport
224+
var amountScrolledDownSidebar = sidebarElement.scrollTop;
225+
var additionalScrollAmount = lastActiveOrCompletedRect.top - viewportHeight;
226+
var amountToScroll = topInset + (visibleSidebarHeight / 2) + additionalScrollAmount + amountScrolledDownSidebar;
227+
sidebarElement.scrollTop = amountToScroll;
228+
}
229+
}
230+
};
231+
newToc.setupHighlighting = function() {
232+
233+
// Add a class to li elements with a ul element inside them
234+
tocContainer.querySelectorAll("li > ul").forEach(function(childUl) {
235+
childUl.parentElement.classList.add("nested");
236+
});
237+
238+
// Highlighting
239+
this.article = document.querySelector(this.containerSelector);
240+
var highlight = debounce(this.highlight.bind(this),1);
241+
window.addEventListener("scroll",highlight);
242+
this.teardowns.push(function() {
243+
window.removeEventListener("scroll", highlight);
244+
}.bind(this));
245+
this.highlight();
246+
};
247+
tocContainer.appendChild(newToc);
248+
249+
// Show the “On this page” title
250+
var onThisPage = document.querySelector("#toc-sidebar h1");
251+
onThisPage.classList.remove("hide");
252+
253+
// After the TOC loads, determine whether the “On this page” title should show
254+
setTimeout(function() {
255+
if (tocContainer.contains(newToc) === false) {
256+
// Hide the “On this page” title
257+
onThisPage.classList.add("hide");
258+
}
259+
});
260+
159261
hasShownSearch = true;
160262
}
161263

@@ -277,8 +379,9 @@ function navigate(href, updateLocation) {
277379
window.location.reload();
278380
}
279381

280-
// Scroll to the top of the page
382+
// Scroll to the top of the page & TOC sidebar
281383
setPageScrollTop(0);
384+
$('#toc-sidebar').scrollTop(0);
282385

283386
var $article = $content.find("article");
284387
var currentPage = $content.filter("#everything").attr("data-current-page");

static/canjs.less

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
/*---------- COMPONENTS ----------*/
1212
@import "sidebar.less";
13+
@import "toc.less";
1314
@import "content.less";
1415
@import "header.less";
1516
@import "home.less";

static/img/icon-forums-gray.svg

Lines changed: 3 additions & 15 deletions
Loading

static/img/icon-github-gray.svg

Lines changed: 3 additions & 14 deletions
Loading

static/img/icon-meetup-gray.svg

Lines changed: 8 additions & 52 deletions
Loading

static/img/icon-rss-gray.svg

Lines changed: 8 additions & 13 deletions
Loading

static/img/icon-slack-gray.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 7 additions & 15 deletions
Loading

0 commit comments

Comments
 (0)