Skip to content

Commit c93833c

Browse files
committed
Remove: code formatters, Add: Table of content component on 4x api page
1 parent bf006cd commit c93833c

File tree

4 files changed

+186
-11
lines changed

4 files changed

+186
-11
lines changed

_includes/api/en/4x/menu.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<ul id="menu">
2-
2+
<li><em>On this page</em>
33
<li id="express-api"><a href="#express">express()</a>
44
<ul id="express-menu">
55
<li><em>Methods</em></li>
@@ -204,4 +204,6 @@
204204
</li>
205205
</ul>
206206
</li>
207+
</li>
207208
</ul>
209+
<button id="menu-toggle" title="show table of content">Table of content &#x25BC</button>

css/dark-theme.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,11 @@ html.dark-mode #blog-side-menu-container h3 a{
278278
html.dark-mode #blog-side-menu > li > a{
279279
color: var(--dark_inner_text);
280280
}
281+
282+
@media all and (max-width: 1440px) {
283+
html.dark-mode #menu,
284+
#tags-side-menu,
285+
#blog-side-menu-container {
286+
background-color: var(--second_dark_bg);
287+
}
288+
}

css/style.css

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -705,12 +705,12 @@ footer {
705705
#blog-side-menu-container {
706706
position: fixed;
707707
margin: 0;
708-
padding: 0 10px 0 0;
708+
padding: 0;
709709
top: 153px;
710-
left: 30px;
710+
right: 0;
711711
height: 500px;
712712
text-align: left;
713-
font-size: 13px;
713+
font-size: 1rem;
714714
overflow-y: auto;
715715
}
716716

@@ -840,9 +840,82 @@ h2 a {
840840
}
841841
}
842842

843+
/* table of content btn */
844+
#menu-toggle {
845+
cursor: pointer;
846+
display: none;
847+
margin-block: 1.5rem;
848+
font-size: 1rem;
849+
padding: 0.5rem;
850+
opacity: 0;
851+
}
852+
853+
/* responsive */
854+
855+
@media all and (max-width: 1440px) {
856+
#menu,
857+
#tags-side-menu,
858+
#blog-side-menu-container {
859+
position: sticky;
860+
max-height: 0;
861+
top: 57px;
862+
left: 0;
863+
background-color: #eee;
864+
z-index: 100;
865+
}
866+
867+
#menu.open {
868+
max-height: 50vh;
869+
padding: 1rem;
870+
}
871+
872+
#menu-toggle.show{
873+
display: block;
874+
opacity: 1;
875+
}
876+
877+
#menu-toggle.position-fixed {
878+
position: fixed;
879+
right: 1rem;
880+
top: 57px;
881+
margin-block: 1rem;
882+
border-radius: 50%;
883+
background-color: #eeeeee56;
884+
padding: 1rem;
885+
border: 1px solid rgb(202, 199, 199);
886+
display: flex;
887+
justify-content: center;
888+
align-items: center;
889+
}
890+
891+
.content {
892+
margin: 57px 3% 7%;
893+
}
894+
895+
#menu li {
896+
cursor: pointer;
897+
border-bottom: 1px solid #cdcdcd;
898+
}
899+
900+
#overlay.blurs{
901+
display: block;
902+
}
903+
}
904+
843905
/* responsive */
844906

845907
@media all and (max-width: 1110px) {
908+
#menu,
909+
#tags-side-menu,
910+
#blog-side-menu-container {
911+
position: fixed;
912+
border-bottom: 1px solid #ddd;
913+
}
914+
915+
.content {
916+
margin: 80px 3% 7%;
917+
}
918+
846919
#boxes {
847920
grid-template-columns: 1fr 1fr;
848921
}
@@ -908,12 +981,6 @@ h2 a {
908981
font-weight: normal;
909982
}
910983

911-
#menu,
912-
#tags-side-menu,
913-
#blog-side-menu-container {
914-
display: none;
915-
}
916-
917984
.content {
918985
padding-left: 0;
919986
}
@@ -1020,6 +1087,16 @@ h2 a {
10201087
#boxes {
10211088
grid-template-columns: 1fr;
10221089
}
1090+
1091+
#menu-toggle.position-fixed {
1092+
left: 0;
1093+
top: 57px;
1094+
margin-block: 0rem;
1095+
width: 100vw;
1096+
padding: 0.5rem;
1097+
border-radius: 0;
1098+
background-color: #eeeeeec9;
1099+
}
10231100
}
10241101

10251102
@media all and (max-width: 420px) {

js/menu.js

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,92 @@ overlay?.addEventListener("click", () => {
115115

116116
document
117117
.querySelector(`.submenu-content a[href="${document.location.pathname}"]`)
118-
?.classList.add("current");
118+
?.classList.add("current");
119+
120+
// TOC
121+
const tocScreen = window.matchMedia("(max-width: 1440px)");
122+
let isTocScreen = tocScreen.matches;
123+
const toggleBtn = document.getElementById("menu-toggle");
124+
const menuList = document.getElementById("menu");
125+
// ! important note add scroll observer element common to all pages that include TOC component 👇🏻 remove id to "scroll-obsever"
126+
const firstHeader = document.getElementById("express");
127+
let observer;
128+
129+
130+
// Scroll observer (perform better than window scroll event listener)
131+
function createScrollObserver() {
132+
if (observer) observer.disconnect();
133+
134+
let options = {
135+
root: null, // Observe relative to viewport
136+
rootMargin: "-57px 0px 0px 0px", // Slight offset to ensure intersection triggers correctly
137+
threshold: 0, // Trigger when the element is fully out of view (i.e. behind header)
138+
};
139+
140+
observer = new IntersectionObserver(handleIntersect, options);
141+
// observe intersection of TOC btn with header bar
142+
observer.observe(firstHeader);
143+
}
144+
145+
// Update button visibility based on screen size
146+
function updateButtonVisibility() {
147+
if (isTocScreen) {
148+
toggleBtn?.classList.add("show");
149+
createScrollObserver();
150+
} else {
151+
toggleBtn?.classList.remove("show");
152+
if (observer) observer.disconnect();
153+
}
154+
}
155+
156+
function handleIntersect(entries) {
157+
const [entry] = entries
158+
const clientWidth = entry.boundingClientRect.width
159+
// first header in invisible then show floating TOC btn
160+
if(!entry.isIntersecting) {
161+
if(toggleBtn) {
162+
if(clientWidth >= 540) {
163+
toggleBtn.innerHTML = "&#x25BC";
164+
} else {
165+
toggleBtn.innerHTML = "Table of content &#x25BC";
166+
};
167+
}
168+
toggleBtn?.classList.add("position-fixed");
169+
};
170+
// first header is visible then show static TOC btn
171+
if(entry.isIntersecting) {
172+
if(toggleBtn) toggleBtn.innerHTML = "Table of content &#x25BC";
173+
toggleBtn?.classList.remove("position-fixed");
174+
};
175+
};
176+
177+
// Show button on page load
178+
updateButtonVisibility();
179+
180+
// Listen for changes in screen size
181+
tocScreen.addEventListener("change", (event) => {
182+
isTocScreen = event.matches;
183+
updateButtonVisibility();
184+
});
185+
186+
// Toggle menu on button click
187+
toggleBtn?.addEventListener("click", () => {
188+
menuList?.classList.toggle("open");
189+
overlay?.classList.toggle("blurs");
190+
document.body.classList.toggle("no-scroll");
191+
if (isTocScreen) {
192+
toggleBtn?.classList.remove("show");
193+
}
194+
});
195+
196+
// Close menu on link click
197+
document.querySelectorAll("#menu a").forEach((link) => {
198+
link.addEventListener("click", function () {
199+
menuList?.classList.remove("open");
200+
overlay?.classList.remove("blurs");
201+
document.body.classList.remove("no-scroll");
202+
if (isTocScreen) {
203+
toggleBtn?.classList.add("show");
204+
}
205+
});
206+
});

0 commit comments

Comments
 (0)