Adds Blog link to both desktop nav (between Architecture and About) and mobile menu (before About & Resources section). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
449 lines
23 KiB
JavaScript
449 lines
23 KiB
JavaScript
/**
|
|
* Tractatus Framework - Responsive Navbar Component
|
|
* Desktop: visible nav links with dropdowns
|
|
* Mobile: slide-out drawer
|
|
*/
|
|
|
|
class TractatusNavbar {
|
|
constructor() {
|
|
this.mobileMenuOpen = false;
|
|
this.openDropdown = null;
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
this.render();
|
|
this.attachEventListeners();
|
|
this.setActivePageIndicator();
|
|
|
|
// Dispatch event to signal navbar is ready
|
|
window.dispatchEvent(new CustomEvent('navbarReady'));
|
|
}
|
|
|
|
render() {
|
|
const navHTML = `
|
|
<nav class="bg-white border-b border-gray-200 sticky top-0 z-50 shadow-sm" id="tractatus-navbar">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="flex justify-between h-16">
|
|
|
|
<!-- Left: Logo + Brand -->
|
|
<div class="flex items-center">
|
|
<a href="/"
|
|
class="flex items-center space-x-2 px-2 py-2 -ml-2 rounded-lg hover:bg-blue-50 transition-all duration-200 group"
|
|
title="Return to homepage">
|
|
<img src="/images/tractatus-icon-new.svg" alt="Tractatus Icon" class="w-8 h-8">
|
|
<span class="text-lg font-bold text-gray-900 group-hover:text-blue-700 transition-colors hidden sm:inline">Tractatus</span>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Centre: Desktop Navigation (hidden on mobile) -->
|
|
<div class="hidden lg:flex items-center space-x-1">
|
|
|
|
<!-- Research Dropdown -->
|
|
<div class="relative" data-dropdown="research">
|
|
<button class="nav-dropdown-btn px-3 py-2 text-sm font-medium text-gray-700 hover:text-blue-700 hover:bg-blue-50 rounded-lg transition flex items-center gap-1">
|
|
Research
|
|
<svg class="w-4 h-4 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
|
|
</svg>
|
|
</button>
|
|
<div class="nav-dropdown-panel hidden absolute left-0 top-full mt-1 w-64 bg-white rounded-lg shadow-lg border border-gray-200 py-2 z-50">
|
|
<a href="/architectural-alignment.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">Academic Paper</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Full academic treatment with proofs</span>
|
|
</a>
|
|
<a href="/architectural-alignment-community.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">Community Paper</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Practical guide for organisations</span>
|
|
</a>
|
|
<a href="/architectural-alignment-policymakers.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">Policymakers Paper</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Regulatory and policy perspective</span>
|
|
</a>
|
|
<div class="border-t border-gray-100 my-1"></div>
|
|
<a href="/researcher.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">For Researchers</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Open questions and collaboration</span>
|
|
</a>
|
|
<a href="/timeline.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">Research Timeline</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Evolution of the research 2025-2026</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Architecture (direct link) -->
|
|
<a href="/architecture.html" class="px-3 py-2 text-sm font-medium text-gray-700 hover:text-blue-700 hover:bg-blue-50 rounded-lg transition">
|
|
Architecture
|
|
</a>
|
|
|
|
<!-- Implementation Dropdown -->
|
|
<div class="relative" data-dropdown="implementation">
|
|
<button class="nav-dropdown-btn px-3 py-2 text-sm font-medium text-gray-700 hover:text-blue-700 hover:bg-blue-50 rounded-lg transition flex items-center gap-1">
|
|
Implementation
|
|
<svg class="w-4 h-4 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
|
|
</svg>
|
|
</button>
|
|
<div class="nav-dropdown-panel hidden absolute left-0 top-full mt-1 w-64 bg-white rounded-lg shadow-lg border border-gray-200 py-2 z-50">
|
|
<a href="/implementer.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">For Implementers</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Integration guide and code examples</span>
|
|
</a>
|
|
<a href="/village-case-study.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">Village Case Study</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Production deployment evidence</span>
|
|
</a>
|
|
<a href="/home-ai.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">Home AI</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Sovereign locally-trained language model</span>
|
|
</a>
|
|
<div class="border-t border-gray-100 my-1"></div>
|
|
<a href="/integrations/agent-lightning.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">Agent Lightning</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Performance optimisation integration</span>
|
|
</a>
|
|
<a href="/leader.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">For Leaders</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Strategic overview and business case</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Blog (direct link) -->
|
|
<a href="/blog.html" class="px-3 py-2 text-sm font-medium text-gray-700 hover:text-blue-700 hover:bg-blue-50 rounded-lg transition">
|
|
Blog
|
|
</a>
|
|
|
|
<!-- About Dropdown -->
|
|
<div class="relative" data-dropdown="about">
|
|
<button class="nav-dropdown-btn px-3 py-2 text-sm font-medium text-gray-700 hover:text-blue-700 hover:bg-blue-50 rounded-lg transition flex items-center gap-1">
|
|
About
|
|
<svg class="w-4 h-4 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
|
|
</svg>
|
|
</button>
|
|
<div class="nav-dropdown-panel hidden absolute left-0 top-full mt-1 w-56 bg-white rounded-lg shadow-lg border border-gray-200 py-2 z-50">
|
|
<a href="/about.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">About Tractatus</span>
|
|
</a>
|
|
<a href="/about/values.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">Values</span>
|
|
</a>
|
|
<a href="/korero-counter-arguments.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition">
|
|
<span class="font-medium">Counter-Arguments</span>
|
|
<span class="block text-xs text-gray-500 mt-0.5">Engaging with criticism</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Right: Secondary links + Language + Menu -->
|
|
<div class="flex items-center gap-2">
|
|
<!-- Desktop secondary links -->
|
|
<div class="hidden lg:flex items-center gap-1">
|
|
<a href="/docs.html" class="px-3 py-2 text-sm text-gray-600 hover:text-blue-700 hover:bg-blue-50 rounded-lg transition">Docs</a>
|
|
<a href="https://github.com/AgenticGovernance/tractatus-framework" target="_blank" rel="noopener noreferrer" class="px-3 py-2 text-sm text-gray-600 hover:text-blue-700 hover:bg-blue-50 rounded-lg transition">GitHub</a>
|
|
<a href="/koha.html" class="px-3 py-1.5 text-sm font-medium text-teal-700 bg-teal-50 hover:bg-teal-100 rounded-lg transition border border-teal-200">Koha</a>
|
|
</div>
|
|
|
|
<!-- Language Selector Container -->
|
|
<div id="language-selector-container"></div>
|
|
|
|
<!-- Mobile menu button (hidden on desktop) -->
|
|
<button id="mobile-menu-btn" class="lg:hidden text-gray-600 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 rounded p-2" aria-label="Toggle menu">
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile Navigation Drawer -->
|
|
<div id="mobile-menu" class="hidden fixed inset-0 z-[9999]">
|
|
<div id="mobile-menu-backdrop" class="absolute inset-0 bg-gray-900/60 backdrop-blur-sm transition-opacity"></div>
|
|
|
|
<div id="mobile-menu-panel" class="absolute right-0 top-0 bottom-0 w-80 max-w-[85vw] bg-white shadow-2xl transform transition-transform duration-300 ease-out overflow-y-auto">
|
|
<div class="flex justify-between items-center px-5 h-16 border-b border-gray-200">
|
|
<div class="flex items-center space-x-2">
|
|
<img src="/images/tractatus-icon-new.svg" alt="Tractatus Icon" class="w-6 h-6">
|
|
<span class="font-bold text-gray-900">Navigation</span>
|
|
</div>
|
|
<button id="mobile-menu-close-btn" class="text-gray-600 hover:text-gray-900 p-2 rounded hover:bg-gray-100 transition" aria-label="Close menu">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<nav class="p-5 space-y-1">
|
|
<!-- Research -->
|
|
<div class="pb-3 mb-3 border-b border-gray-200">
|
|
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2 px-3">Research</p>
|
|
<a href="/architectural-alignment.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Academic Paper</a>
|
|
<a href="/architectural-alignment-community.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Community Paper</a>
|
|
<a href="/architectural-alignment-policymakers.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Policymakers Paper</a>
|
|
<a href="/researcher.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">For Researchers</a>
|
|
<a href="/timeline.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Research Timeline</a>
|
|
</div>
|
|
|
|
<!-- Architecture & Implementation -->
|
|
<div class="pb-3 mb-3 border-b border-gray-200">
|
|
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2 px-3">Architecture & Implementation</p>
|
|
<a href="/architecture.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">System Architecture</a>
|
|
<a href="/implementer.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">For Implementers</a>
|
|
<a href="/village-case-study.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Village Case Study</a>
|
|
<a href="/home-ai.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Home AI</a>
|
|
<a href="/leader.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">For Leaders</a>
|
|
<a href="/integrations/agent-lightning.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-purple-50 hover:text-purple-700 rounded-lg transition">Agent Lightning</a>
|
|
</div>
|
|
|
|
<!-- Blog -->
|
|
<div class="pb-3 mb-3 border-b border-gray-200">
|
|
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2 px-3">Blog</p>
|
|
<a href="/blog.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Latest Posts</a>
|
|
</div>
|
|
|
|
<!-- About & Resources -->
|
|
<div class="pb-3 mb-3 border-b border-gray-200">
|
|
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2 px-3">About</p>
|
|
<a href="/about.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">About Tractatus</a>
|
|
<a href="/about/values.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Values</a>
|
|
<a href="/korero-counter-arguments.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Counter-Arguments</a>
|
|
</div>
|
|
|
|
<!-- Resources -->
|
|
<div class="pb-3 mb-3 border-b border-gray-200">
|
|
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2 px-3">Resources</p>
|
|
<a href="/docs.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Documentation</a>
|
|
<a href="https://github.com/AgenticGovernance/tractatus-framework" target="_blank" rel="noopener noreferrer" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">GitHub</a>
|
|
<a href="/koha.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Support (Koha)</a>
|
|
</div>
|
|
|
|
<!-- Company -->
|
|
<div class="pt-1">
|
|
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2 px-3" data-i18n="navbar.company_heading">Company</p>
|
|
<a href="https://mysovereignty.digital" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition" data-i18n="navbar.company_links.website">MySovereignty</a>
|
|
</div>
|
|
|
|
<!-- Feedback -->
|
|
<div class="pt-3 mt-3 border-t border-gray-200">
|
|
<button id="navbar-feedback-btn" class="w-full text-left block px-3 py-2.5 text-white bg-gradient-to-r from-blue-600 to-blue-700 hover:shadow-lg rounded-lg transition">
|
|
<span class="text-sm font-semibold" data-i18n="navbar.feedback">Give Feedback</span>
|
|
</button>
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
</nav>
|
|
`;
|
|
|
|
const existingNavbar = document.querySelector('nav.bg-white.border-b.border-gray-200.sticky');
|
|
if (existingNavbar) {
|
|
existingNavbar.outerHTML = navHTML;
|
|
} else {
|
|
const placeholder = document.getElementById('navbar-placeholder');
|
|
if (placeholder) {
|
|
placeholder.outerHTML = navHTML;
|
|
} else {
|
|
document.body.insertAdjacentHTML('afterbegin', navHTML);
|
|
}
|
|
}
|
|
}
|
|
|
|
attachEventListeners() {
|
|
// Desktop Dropdowns
|
|
const dropdowns = document.querySelectorAll('[data-dropdown]');
|
|
dropdowns.forEach(dropdown => {
|
|
const btn = dropdown.querySelector('.nav-dropdown-btn');
|
|
const panel = dropdown.querySelector('.nav-dropdown-panel');
|
|
if (!btn || !panel) return;
|
|
|
|
let closeTimeout = null;
|
|
|
|
const openDropdown = () => {
|
|
if (closeTimeout) {
|
|
clearTimeout(closeTimeout);
|
|
closeTimeout = null;
|
|
}
|
|
// Close other dropdowns
|
|
dropdowns.forEach(d => {
|
|
if (d !== dropdown) {
|
|
const p = d.querySelector('.nav-dropdown-panel');
|
|
if (p) p.classList.add('hidden');
|
|
const b = d.querySelector('.nav-dropdown-btn svg');
|
|
if (b) b.style.transform = '';
|
|
}
|
|
});
|
|
panel.classList.remove('hidden');
|
|
const arrow = btn.querySelector('svg');
|
|
if (arrow) arrow.style.transform = 'rotate(180deg)';
|
|
};
|
|
|
|
const closeDropdown = () => {
|
|
closeTimeout = setTimeout(() => {
|
|
panel.classList.add('hidden');
|
|
const arrow = btn.querySelector('svg');
|
|
if (arrow) arrow.style.transform = '';
|
|
}, 150);
|
|
};
|
|
|
|
btn.addEventListener('mouseenter', openDropdown);
|
|
btn.addEventListener('mouseleave', closeDropdown);
|
|
panel.addEventListener('mouseenter', () => {
|
|
if (closeTimeout) {
|
|
clearTimeout(closeTimeout);
|
|
closeTimeout = null;
|
|
}
|
|
});
|
|
panel.addEventListener('mouseleave', closeDropdown);
|
|
|
|
// Keyboard accessibility
|
|
btn.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
const isHidden = panel.classList.contains('hidden');
|
|
// Close all
|
|
dropdowns.forEach(d => {
|
|
const p = d.querySelector('.nav-dropdown-panel');
|
|
if (p) p.classList.add('hidden');
|
|
});
|
|
if (isHidden) {
|
|
panel.classList.remove('hidden');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Close dropdowns on click outside
|
|
document.addEventListener('click', (e) => {
|
|
if (!e.target.closest('[data-dropdown]')) {
|
|
dropdowns.forEach(d => {
|
|
const p = d.querySelector('.nav-dropdown-panel');
|
|
if (p) p.classList.add('hidden');
|
|
const b = d.querySelector('.nav-dropdown-btn svg');
|
|
if (b) b.style.transform = '';
|
|
});
|
|
}
|
|
});
|
|
|
|
// Close dropdowns on Escape
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') {
|
|
dropdowns.forEach(d => {
|
|
const p = d.querySelector('.nav-dropdown-panel');
|
|
if (p) p.classList.add('hidden');
|
|
const b = d.querySelector('.nav-dropdown-btn svg');
|
|
if (b) b.style.transform = '';
|
|
});
|
|
}
|
|
});
|
|
|
|
// Mobile Menu
|
|
const mobileMenuBtn = document.getElementById('mobile-menu-btn');
|
|
const mobileMenuCloseBtn = document.getElementById('mobile-menu-close-btn');
|
|
const mobileMenu = document.getElementById('mobile-menu');
|
|
const mobileMenuPanel = document.getElementById('mobile-menu-panel');
|
|
const mobileMenuBackdrop = document.getElementById('mobile-menu-backdrop');
|
|
|
|
const toggleMobileMenu = () => {
|
|
this.mobileMenuOpen = !this.mobileMenuOpen;
|
|
|
|
if (this.mobileMenuOpen) {
|
|
mobileMenu.classList.remove('hidden');
|
|
setTimeout(() => {
|
|
mobileMenuPanel.classList.remove('translate-x-full');
|
|
mobileMenuPanel.classList.add('translate-x-0');
|
|
}, 10);
|
|
document.body.style.overflow = 'hidden';
|
|
} else {
|
|
mobileMenuPanel.classList.remove('translate-x-0');
|
|
mobileMenuPanel.classList.add('translate-x-full');
|
|
setTimeout(() => {
|
|
mobileMenu.classList.add('hidden');
|
|
}, 300);
|
|
document.body.style.overflow = '';
|
|
}
|
|
};
|
|
|
|
if (mobileMenuPanel) {
|
|
mobileMenuPanel.classList.add('translate-x-full');
|
|
}
|
|
|
|
if (mobileMenuBtn) {
|
|
mobileMenuBtn.addEventListener('click', toggleMobileMenu);
|
|
}
|
|
|
|
if (mobileMenuCloseBtn) {
|
|
mobileMenuCloseBtn.addEventListener('click', toggleMobileMenu);
|
|
}
|
|
|
|
if (mobileMenuBackdrop) {
|
|
mobileMenuBackdrop.addEventListener('click', toggleMobileMenu);
|
|
}
|
|
|
|
// Close mobile menu on navigation
|
|
const mobileLinks = document.querySelectorAll('#mobile-menu a');
|
|
mobileLinks.forEach(link => {
|
|
link.addEventListener('click', () => {
|
|
if (this.mobileMenuOpen) {
|
|
toggleMobileMenu();
|
|
}
|
|
});
|
|
});
|
|
|
|
// Feedback button
|
|
const navbarFeedbackBtn = document.getElementById('navbar-feedback-btn');
|
|
if (navbarFeedbackBtn) {
|
|
navbarFeedbackBtn.addEventListener('click', () => {
|
|
if (this.mobileMenuOpen) {
|
|
toggleMobileMenu();
|
|
}
|
|
window.dispatchEvent(new CustomEvent('openFeedbackModal'));
|
|
});
|
|
}
|
|
}
|
|
|
|
setActivePageIndicator() {
|
|
const currentPath = window.location.pathname;
|
|
|
|
const normalizePath = (path) => {
|
|
if (!path || path.startsWith('http')) return path;
|
|
if (path === '/' || path === '/index.html') return '/';
|
|
return path.replace('.html', '').replace(/\/$/, '');
|
|
};
|
|
|
|
const normalizedCurrent = normalizePath(currentPath);
|
|
|
|
// Desktop nav links
|
|
const desktopLinks = document.querySelectorAll('#tractatus-navbar a[href]');
|
|
desktopLinks.forEach(link => {
|
|
const linkPath = link.getAttribute('href');
|
|
const normalizedLink = normalizePath(linkPath);
|
|
if (normalizedLink === normalizedCurrent && !link.closest('.nav-dropdown-panel')) {
|
|
link.classList.add('text-blue-700', 'bg-blue-50');
|
|
link.classList.remove('text-gray-700', 'text-gray-600');
|
|
}
|
|
});
|
|
|
|
// Mobile nav links
|
|
const mobileLinks = document.querySelectorAll('#mobile-menu a');
|
|
mobileLinks.forEach(link => {
|
|
const linkPath = link.getAttribute('href');
|
|
const normalizedLink = normalizePath(linkPath);
|
|
if (normalizedLink === normalizedCurrent) {
|
|
link.classList.add('border-l-4', 'bg-sky-50', 'text-blue-700', 'font-medium');
|
|
link.style.borderLeftColor = 'var(--tractatus-core-end, #3b82f6)';
|
|
link.classList.remove('text-gray-700');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Auto-initialize when DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', () => new TractatusNavbar());
|
|
} else {
|
|
new TractatusNavbar();
|
|
}
|