Skip to content

Commit bc6b432

Browse files
Merge pull request rails#51504 from MooseCowBear/navigation-highlight
Add navbar highlighting to guides when scrolling [ci skip]
2 parents 80fa112 + 1e13e91 commit bc6b432

File tree

2 files changed

+147
-6
lines changed

2 files changed

+147
-6
lines changed

guides/assets/javascripts/guides.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
backToTop.addEventListener("click", function(e) {
5353
e.preventDefault();
5454
window.scrollTo({ top: 0, behavior: "smooth" });
55+
resetNavPosition();
5556
});
5657

5758
var toggleBackToTop = function() {
@@ -102,5 +103,87 @@
102103
}, 3000);
103104
e.clearSelection();
104105
});
106+
107+
var mainColElems = Array.from(document.getElementById("mainCol").children);
108+
var subCol = document.querySelector("#subCol");
109+
var navLinks = subCol.querySelectorAll("a");
110+
var DESKTOP_THRESHOLD = 1024;
111+
112+
var matchingNavLink = function (elem) {
113+
if(!elem) return;
114+
var index = mainColElems.indexOf(elem);
115+
116+
var match;
117+
while (index >= 0 && !match) {
118+
var link = mainColElems[index].querySelector(".anchorlink");
119+
if (link) {
120+
match = subCol.querySelector('[href="' + link.getAttribute("href") + '"]');
121+
}
122+
index--;
123+
}
124+
return match;
125+
}
126+
127+
var removeHighlight = function () {
128+
for (var i = 0, n = navLinks.length; i < n; i++) {
129+
navLinks[i].classList.remove("active");
130+
}
131+
}
132+
133+
var updateHighlight = function (elem) {
134+
if (window.innerWidth > DESKTOP_THRESHOLD && !elem?.classList.contains("active")) {
135+
removeHighlight();
136+
if (!elem) return;
137+
elem.classList.add("active");
138+
elem.scrollIntoView({ block: 'center', inline: 'end' });
139+
}
140+
}
141+
142+
var resetNavPosition = function () {
143+
var chapters = subCol.querySelector(".chapters");
144+
chapters?.scroll({ top: 0 });
145+
}
146+
147+
var belowBottomHalf = function (i) {
148+
return i.boundingClientRect.bottom > (i.rootBounds.bottom + i.rootBounds.top) / 2;
149+
}
150+
151+
var prevElem = function (elem) {
152+
var index = mainColElems.indexOf(elem);
153+
if (index <= 0) {
154+
return null;
155+
}
156+
return mainColElems[index - 1];
157+
}
158+
159+
var PAGE_LOAD_BUFFER = 1000;
160+
161+
var navHighlight = function (entries) {
162+
entries.forEach(function (entry) {
163+
if (entry.isIntersecting) {
164+
updateHighlight(matchingNavLink(entry.target));
165+
} else if (entry.time >= PAGE_LOAD_BUFFER && belowBottomHalf(entry)) {
166+
updateHighlight(matchingNavLink(prevElem(entry.target)));
167+
}
168+
});
169+
}
170+
171+
var observer = new IntersectionObserver(navHighlight, {
172+
threshold: 0,
173+
rootMargin: "0% 0px -95% 0px"
174+
});
175+
176+
mainColElems.forEach(function (elem) {
177+
observer.observe(elem);
178+
})
179+
180+
observer.observe(document.getElementById("feature"));
181+
182+
subCol.addEventListener("click", function(e) {
183+
var link = e.target.closest("a");
184+
if (link) {
185+
setTimeout(function() { updateHighlight(link) }, 100);
186+
}
187+
})
105188
});
106189
}).call(this);

guides/assets/stylesrc/_main.scss

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,9 @@ body.guide {
726726
}
727727

728728
ol.chapters {
729+
padding-inline-start: 3.5em;
730+
padding-inline-end: 1em;
731+
729732
&::-webkit-scrollbar
730733
{
731734
width: 6px;
@@ -760,6 +763,12 @@ body.guide {
760763
li {
761764
font-weight: bold;
762765

766+
a {
767+
position: relative;
768+
display: block;
769+
word-wrap: break-word;
770+
}
771+
763772
a,
764773
a:link,
765774
a:visited {
@@ -777,19 +786,68 @@ body.guide {
777786
margin-top: 0.5em;
778787
margin-bottom: 0.75em;
779788
padding-inline-start: 1em;
780-
@include media('>desktop') {
781-
max-width: 310px;
782-
width: 310px;
783-
}
789+
padding-inline-end: 0.25em;
784790

785791
li {
786792
font-weight: 400;
787-
@include media('>desktop') {
788-
width: 310px;
793+
794+
a.active::after { // highlight
795+
@include media('>desktop') {
796+
width: 328px;
797+
}
798+
left: -3em;
799+
}
800+
801+
a.active::before { // red square
802+
left: -2.5em;
803+
top: 7px;
789804
}
790805
} // li
791806
} // ul
807+
808+
a::after { // highlight
809+
content: '';
810+
position: absolute;
811+
display: block;
812+
height: calc(100% + 10px);
813+
@include media('>desktop') {
814+
width: 352px;
815+
}
816+
top: 50%;
817+
transform: translateY(-50%);
818+
left: -3.5em;
819+
border-radius: 8px;
820+
background-color: $stop-bkgnd;
821+
opacity: 0;
822+
transition: opacity 0.2s ease-in-out;
823+
}
824+
825+
a.active::after {
826+
opacity: 1;
827+
}
828+
829+
a::before { // red square
830+
content: '';
831+
display: block;
832+
position: absolute;
833+
height: 10px;
834+
width: 10px;
835+
top: 6px;
836+
left: -3em;
837+
border-radius: 3px;
838+
background-color: $rf-brand;
839+
opacity: 0;
840+
transition: opacity 0.2s ease-in-out;
841+
}
842+
843+
a.active::before {
844+
opacity: 1;
845+
}
792846
} // li
847+
848+
> li:first-child {
849+
margin-top: 0.5em;
850+
}
793851
} // ol
794852
}
795853
}

0 commit comments

Comments
 (0)