feat(navbar): implement active state detection for navbar navigation

- Simplify navbar to textbook-focused design: Labs, Kits, PDF + GitHub tools
- Move 'Edit this page', 'Report issue' from buried TOC to accessible GitHub dropdown
- Add CSS styling for navbar active states with crimson highlighting
- Implement JavaScript active state detection handling .qmd→.html URL conversion
- Fix URL matching for localhost development environment
- Ensure proper visual feedback when navigating between Labs/Kits sections
- Maintain clean, academic navbar design appropriate for textbook format
This commit is contained in:
Vijay Janapa Reddi
2025-08-03 16:35:46 -04:00
parent 9f04d96202
commit b33329a4a2
3 changed files with 117 additions and 60 deletions

View File

@@ -53,4 +53,43 @@ document.addEventListener('DOMContentLoaded', function() {
});
}, delay);
});
// Handle navbar active states
function setNavbarActiveState() {
const currentUrl = window.location.href;
const currentPath = window.location.pathname;
const navbarLinks = document.querySelectorAll('.navbar-nav .nav-link');
navbarLinks.forEach(link => {
// Remove existing active classes
link.classList.remove('active');
link.removeAttribute('aria-current');
const href = link.getAttribute('href');
if (href && !href.includes('mlsysbook.ai')) { // Skip external PDF link
let linkUrl = href;
// If it's a relative path, make it absolute for comparison
if (!href.startsWith('http')) {
linkUrl = window.location.origin + '/' + href.replace(/^\//, '');
}
// Convert .qmd to .html for comparison since that's what gets rendered
linkUrl = linkUrl.replace(/\.qmd$/, '.html');
// Check for exact match
if (currentUrl === linkUrl || currentPath === new URL(linkUrl).pathname) {
link.classList.add('active');
link.setAttribute('aria-current', 'page');
console.log('Setting active:', link.textContent.trim(), 'Current:', currentUrl, 'Link:', linkUrl);
}
}
});
}
// Set initial active state
setNavbarActiveState();
// Also check after a brief delay in case page is still loading
setTimeout(setNavbarActiveState, 500);
});

View File

@@ -39,10 +39,10 @@ a {
}
}
// Sidebar link styles - strong typography matching TOC
// Sidebar link styles - readable but secondary to main content
.sidebar-navigation .sidebar-item a {
color: #2c3e50; // Strong dark color like TOC
font-weight: 500; // Medium weight for consistency
color: #495057; // Readable but not competing with main content
font-weight: 400; // Normal weight - supportive not dominant
display: block;
padding: 4px 8px; // More padding for better touch targets
margin: 1px 0; // Small margin for breathing room
@@ -50,33 +50,33 @@ a {
transition: all 0.15s ease;
&:hover {
color: $crimson; // Crimson hover like TOC
color: $crimson; // Crimson hover for interaction
background-color: rgba($crimson, 0.08);
font-weight: 600; // Bold on hover like TOC
font-weight: 500; // Medium weight on hover
text-decoration: none;
transform: translateX(2px);
}
// Strong active state like TOC
// Clear active state without overpowering
&.active,
&[aria-current="page"] {
color: $crimson;
font-weight: 600; // Bold for active state
font-weight: 500; // Medium weight for active state
background-color: rgba($crimson, 0.12);
}
}
// Section headers - strong like TOC main sections
// Section headers - clear hierarchy but not overpowering
.sidebar-navigation .sidebar-item a[data-bs-toggle="collapse"] {
font-weight: 600; // Bold like TOC main sections
color: #1a252f; // Very dark like TOC main sections
font-size: 0.95rem; // Slightly larger for hierarchy
letter-spacing: 0.02em; // Subtle spacing for readability
font-weight: 500; // Medium weight - clear but supportive
color: #2c3e50; // Dark but not competing with main content
font-size: 0.9rem; // Slightly larger for hierarchy
letter-spacing: 0.01em; // Subtle spacing for readability
&:hover {
color: $crimson; // Crimson hover
background-color: rgba($crimson, 0.08);
font-weight: 700; // Extra bold on hover
font-weight: 600; // Bold on hover but not excessive
text-decoration: none;
transform: translateX(2px);
}
@@ -99,14 +99,14 @@ a {
}
}
// Content area link styles - consistent with navigation
// Content area link styles - balanced with navigation
.content a {
color: $link-color;
font-weight: 500; // Medium weight for consistency
font-weight: 400; // Normal weight - content should be primary focus
&:hover {
color: $link-hover-color;
font-weight: 600; // Bold on hover like navigation
font-weight: 500; // Medium weight on hover
text-decoration: underline;
}
}
@@ -232,11 +232,11 @@ nav[role="doc-toc"] {
box-shadow: none !important;
}
// All links - consistent with main content typography
// All links - readable but secondary to main content
a,
.nav-link {
color: #2c3e50; // Strong, dark color like main content
font-weight: 500; // Stronger weight for consistency
color: #495057; // Readable but not competing with main content
font-weight: 400; // Normal weight - supportive navigation
text-decoration: none;
display: block;
padding: 0.2rem 0; // Slightly more padding
@@ -249,53 +249,53 @@ nav[role="doc-toc"] {
box-shadow: none !important;
&:hover {
color: $crimson; // Crimson hover like main content
font-weight: 600;
color: $crimson; // Crimson hover for interaction
font-weight: 500; // Medium weight on hover
}
}
// Main sections (H2) - strong like main content headers
// Main sections (H2) - clear but not overpowering
> ul > li {
margin-bottom: 0.6rem;
margin-bottom: 0.5rem;
> a {
font-weight: 600; // Bold like main headers
color: #1a252f; // Very dark, strong presence
font-size: 0.95rem; // Slightly larger
margin-bottom: 0.3rem;
letter-spacing: 0.02em; // Subtle spacing for readability
font-weight: 500; // Medium weight - clear hierarchy
color: #2c3e50; // Dark but balanced
font-size: 0.9rem; // Appropriate size
margin-bottom: 0.25rem;
letter-spacing: 0.01em; // Subtle spacing
}
}
// Sub-sections (H3) - medium weight, readable
// Sub-sections (H3) - supportive weight
ul ul {
margin-left: 0.75rem;
margin-top: 0.3rem;
margin-top: 0.25rem;
li {
margin-bottom: 0.2rem;
margin-bottom: 0.15rem;
}
a {
font-size: 0.85rem; // Slightly larger
color: #34495e; // Darker, more readable
font-weight: 500; // Medium weight
padding: 0.15rem 0;
font-size: 0.8rem; // Appropriate size
color: #6c757d; // Lighter but readable
font-weight: 400; // Normal weight
padding: 0.1rem 0;
}
// Deep nesting (H4+) - still strong enough
// Deep nesting (H4+) - subtle but readable
ul a {
font-size: 0.8rem;
color: #5a6c7d; // Still readable but lighter
font-weight: 450; // Slightly lighter but not too light
font-size: 0.75rem;
color: #8e959c; // Light but still readable
font-weight: 400; // Normal weight
}
}
// Active section - clean crimson highlight, no lines
// Active section - clear but balanced crimson highlight
.active,
.nav-link.active {
color: $crimson !important;
font-weight: 500 !important;
font-weight: 500 !important; // Medium weight for active state
border: none !important;
border-left: none !important;
border-right: none !important;
@@ -618,4 +618,33 @@ figcaption.quarto-float-caption-top {
}
}
// Navbar active states for Labs, Kits, PDF
.navbar-nav .nav-link {
color: #6c757d !important;
font-weight: 400;
transition: all 0.2s ease;
&:hover {
color: $crimson !important;
font-weight: 500;
}
&.active, &[aria-current="page"] {
color: $crimson !important;
font-weight: 500;
}
}
// Ensure navbar right side (Labs, Kits, PDF) get active states
.navbar .navbar-nav .nav-item .nav-link {
&:hover {
color: $crimson !important;
}
&.active {
color: $crimson !important;
font-weight: 500;
}
}

View File

@@ -26,13 +26,6 @@ project:
preview:
browser: true
navigate: true
render:
- index.qmd
- contents/frontmatter/foreword.qmd
- contents/frontmatter/about/about.qmd
- contents/frontmatter/changelog/changelog.qmd
- contents/frontmatter/acknowledgements/acknowledgements.qmd
- contents/core/introduction/introduction.qmd
website:
# High-level navigation enhancements
@@ -40,7 +33,7 @@ website:
reader-mode: false
back-to-top-navigation: true
bread-crumbs: true
# Announcement bar configuration
announcement:
icon: megaphone
@@ -94,13 +87,13 @@ website:
aria-label: "Donate & Support"
- icon: github
menu:
- text: "🐛 Report Issue"
href: https://github.com/harvard-edge/cs249r_book/issues
- text: "🤝 Contribute Code"
href: https://github.com/harvard-edge/cs249r_book/blob/main/docs/contribute.md
- text: "✏️ Edit this page"
href: https://github.com/harvard-edge/cs249r_book
- text: "🐛 Report an issue"
href: https://github.com/harvard-edge/cs249r_book/issues/new
- text: "💬 Discussions"
href: https://github.com/harvard-edge/cs249r_book/discussions
- text: "🔍 View Source"
- text: "🔍 View source"
href: https://github.com/harvard-edge/cs249r_book
favicon: assets/images/icons/favicon.png
@@ -123,9 +116,7 @@ website:
- href: contents/frontmatter/about/about.qmd
- href: contents/frontmatter/changelog/changelog.qmd
- href: contents/frontmatter/acknowledgements/acknowledgements.qmd
- text: "---"
- href: contents/frontmatter/socratiq/socratiq.qmd
- text: "---"
# <!------------------------------------------------->
# <!-- Division: Mainmatter — Part I: Systems Foundations -->
@@ -195,9 +186,7 @@ website:
contents:
#- href: contents/core/frontiers/frontiers.qmd
- href: contents/core/conclusion/conclusion.qmd
- text: "---"
# <!------------------------------------------------->
# <!-- Division: Mainmatter — Part VII: Laboratory Exercises Overview -->
# <!------------------------------------------------->
@@ -371,7 +360,7 @@ filters:
- ../config/lua/sidenote.lua # ⚠️ INFO: In HTML, this should not needed.
- ../config/lua/inject_parts.lua
- ../config/lua/inject_quizzes.lua
# - pandoc-ext/diagram
- pandoc-ext/diagram
- ../config/lua/inject_crossrefs.lua # ⚠️ WARNING: This must come before custom-numbered-blocks (relies on \ref{...})
- custom-numbered-blocks
- ../config/lua/margin-connections.lua # ⚠️ WARNING: This filter must come after custom-numbered-blocks