Skip to content

Commit 0090416

Browse files
committed
Add scrollspy and responsive TOC; theme-init tweaks
Enable smooth scrolling and top padding; make the TOC sidebar sticky with a max-height and add .toc-link.active styling. Add a responsive media query to collapse the TOC into the content flow on smaller screens. Implement a ScrollSpy using IntersectionObserver in docmd-main.js to set active TOC links based on visible headings and wire it into DOMContentLoaded. Update theme-init.js to resolve the 'system' mode to an effective light/dark value and ensure the Highlight.js stylesheet is loaded for the resolved theme; also simplify HTML attribute handling. Removed an overflow:hidden on the main content wrapper to avoid clipping.
1 parent 32da491 commit 0090416

File tree

3 files changed

+82
-15
lines changed

3 files changed

+82
-15
lines changed

src/assets/css/docmd-main.css

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@
5151
--lightbox-text: #fff
5252
}
5353

54+
html {
55+
scroll-behavior: smooth;
56+
scroll-padding-top: 80px;
57+
}
58+
5459
body {
5560
font-family: var(--font-family-sans);
5661
background-color: var(--bg-color);
@@ -212,7 +217,6 @@ body.sidebar-collapsed .main-content-wrapper {
212217
flex-grow: 1;
213218
display: flex;
214219
flex-direction: column;
215-
overflow: hidden
216220
}
217221

218222
.header-left,
@@ -886,11 +890,36 @@ details[open]>.collapsible-summary .collapsible-arrow svg {
886890
}
887891

888892
.toc-sidebar {
889-
width: 180px;
893+
position: -webkit-sticky;
890894
position: sticky;
891895
top: 2rem;
896+
max-height: calc(100vh - 15rem);
892897
overflow-y: auto;
893-
align-self: flex-start
898+
}
899+
900+
.toc-link.active {
901+
font-weight: 700;
902+
color: var(--link-color);
903+
border-left: 2px solid var(--link-color);
904+
padding-left: 8px;
905+
margin-left: -10px;
906+
}
907+
908+
@media (max-width: 1024px) {
909+
.content-layout {
910+
flex-direction: column-reverse;
911+
}
912+
913+
.toc-sidebar {
914+
position: static;
915+
width: 100%;
916+
max-height: none;
917+
margin-bottom: 2rem;
918+
border-left: none;
919+
border-bottom: 1px solid var(--border-color);
920+
padding-left: 0;
921+
padding-bottom: 1rem;
922+
}
894923
}
895924

896925
.docmd-tabs,

src/assets/js/docmd-main.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,43 @@ function syncBodyTheme() {
209209
}
210210
}
211211

212+
// --- Scroll Spy Logic ---
213+
function initializeScrollSpy() {
214+
const tocLinks = document.querySelectorAll('.toc-link');
215+
const headings = document.querySelectorAll('.main-content h2, .main-content h3');
216+
217+
if (tocLinks.length === 0 || headings.length === 0) return;
218+
219+
const observerOptions = {
220+
root: null,
221+
// Trigger when heading crosses the top 10% of screen
222+
rootMargin: '-10% 0px -80% 0px',
223+
threshold: 0
224+
};
225+
226+
const observer = new IntersectionObserver((entries) => {
227+
entries.forEach(entry => {
228+
if (entry.isIntersecting) {
229+
// 1. Clear current active state
230+
tocLinks.forEach(link => link.classList.remove('active'));
231+
232+
// 2. Find link corresponding to this heading
233+
const id = entry.target.getAttribute('id');
234+
const activeLink = document.querySelector(`.toc-link[href="#${id}"]`);
235+
236+
if (activeLink) {
237+
activeLink.classList.add('active');
238+
239+
// Optional: Auto-scroll the TOC sidebar itself if needed
240+
// activeLink.scrollIntoView({ block: 'nearest' });
241+
}
242+
}
243+
});
244+
}, observerOptions);
245+
246+
headings.forEach(heading => observer.observe(heading));
247+
}
248+
212249
// --- Main Execution ---
213250
document.addEventListener('DOMContentLoaded', () => {
214251
syncBodyTheme();
@@ -219,4 +256,5 @@ document.addEventListener('DOMContentLoaded', () => {
219256
initializeCollapsibleNav();
220257
initializeMobileMenus();
221258
initializeSidebarScroll();
259+
initializeScrollSpy();
222260
});

src/templates/partials/theme-init.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
1-
// Source file from the docmd project — https://github.com/docmd-io/docmd
2-
3-
/*
4-
* Initialize the theme from localStorage
5-
*/
1+
/* Source file from the docmd project — https://github.com/docmd-io/docmd */
62

73
(function() {
84
try {
9-
// Determine Theme
105
var localValue = localStorage.getItem('docmd-theme');
116
var configValue = window.DOCMD_DEFAULT_MODE || 'light';
127
var theme = localValue ? localValue : configValue;
138

14-
// Set HTML Attribute (for main CSS variables)
9+
// Set HTML Attribute
1510
document.documentElement.setAttribute('data-theme', theme);
1611

17-
// Handle Highlight.js Theme (if present)
12+
// Resolve 'system' to actual mode for Highlight.js
13+
var effectiveTheme = theme;
14+
if (theme === 'system') {
15+
effectiveTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
16+
}
17+
18+
// Handle Highlight.js Theme
1819
var highlightLink = document.getElementById('highlight-theme');
1920
if (highlightLink) {
2021
var baseHref = highlightLink.getAttribute('data-base-href');
21-
// Check if the current href matches the desired theme
22-
// If not, swap it immediately before the browser renders code blocks
23-
if (baseHref && !highlightLink.href.includes('docmd-highlight-' + theme)) {
24-
highlightLink.href = baseHref + 'docmd-highlight-' + theme + '.css';
22+
if (baseHref) {
23+
// Force load the resolved theme (light/dark)
24+
highlightLink.href = baseHref + 'docmd-highlight-' + effectiveTheme + '.css';
2525
}
2626
}
2727
} catch (e) {

0 commit comments

Comments
 (0)