feat: Consolidate navbar — Framework dropdown + mobile accordion

Merge Architecture link and Implementation dropdown into single "Framework"
dropdown on desktop (5 → 4 top-level items). Replace flat mobile drawer
sections with collapsible accordion (chevron toggle, auto-expand active
section). Remove Company section and Give Feedback button from mobile.
Koha promoted to standalone teal link in mobile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
TheFlow 2026-02-09 17:55:08 +13:00
parent 61c1ff2e53
commit 32563adf1b

View file

@ -72,20 +72,20 @@ class TractatusNavbar {
</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">
<!-- Framework Dropdown (Architecture + Implementation) -->
<div class="relative" data-dropdown="framework">
<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
Framework
<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="/architecture.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">System Architecture</span>
<span class="block text-xs text-gray-500 mt-0.5">Technical architecture overview</span>
</a>
<div class="border-t border-gray-100 my-1"></div>
<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>
@ -179,60 +179,78 @@ class TractatusNavbar {
</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>
<!-- Research (collapsible) -->
<div class="mobile-nav-section border-b border-gray-200 pb-1 mb-1" data-section="research">
<button class="mobile-nav-section-btn flex items-center justify-between w-full px-3 py-2.5 text-xs font-semibold text-gray-500 uppercase tracking-wider hover:bg-gray-50 rounded-lg transition">
Research
<svg class="w-4 h-4 transition-transform duration-200" 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="mobile-nav-section-content overflow-hidden max-h-0 transition-all duration-200">
<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>
</div>
<!-- Framework (collapsible) -->
<div class="mobile-nav-section border-b border-gray-200 pb-1 mb-1" data-section="framework">
<button class="mobile-nav-section-btn flex items-center justify-between w-full px-3 py-2.5 text-xs font-semibold text-gray-500 uppercase tracking-wider hover:bg-gray-50 rounded-lg transition">
Framework
<svg class="w-4 h-4 transition-transform duration-200" 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="mobile-nav-section-content overflow-hidden max-h-0 transition-all duration-200">
<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="/integrations/agent-lightning.html" class="block px-3 py-2 text-sm text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Agent Lightning</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>
</div>
</div>
<!-- Blog (direct link) -->
<div class="border-b border-gray-200 pb-1 mb-1">
<a href="/blog.html" class="block px-3 py-2.5 text-sm font-medium text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">Blog</a>
</div>
<!-- About (collapsible) -->
<div class="mobile-nav-section border-b border-gray-200 pb-1 mb-1" data-section="about">
<button class="mobile-nav-section-btn flex items-center justify-between w-full px-3 py-2.5 text-xs font-semibold text-gray-500 uppercase tracking-wider hover:bg-gray-50 rounded-lg transition">
About
<svg class="w-4 h-4 transition-transform duration-200" 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="mobile-nav-section-content overflow-hidden max-h-0 transition-all duration-200">
<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>
</div>
<!-- Resources (collapsible) -->
<div class="mobile-nav-section border-b border-gray-200 pb-1 mb-1" data-section="resources">
<button class="mobile-nav-section-btn flex items-center justify-between w-full px-3 py-2.5 text-xs font-semibold text-gray-500 uppercase tracking-wider hover:bg-gray-50 rounded-lg transition">
Resources
<svg class="w-4 h-4 transition-transform duration-200" 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="mobile-nav-section-content overflow-hidden max-h-0 transition-all duration-200">
<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>
</div>
</div>
<!-- Koha (standalone prominent link) -->
<div class="pt-1">
<a href="/koha.html" class="block px-3 py-2.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>
</nav>
</div>
@ -393,37 +411,62 @@ class TractatusNavbar {
});
});
// Feedback button
const navbarFeedbackBtn = document.getElementById('navbar-feedback-btn');
if (navbarFeedbackBtn) {
navbarFeedbackBtn.addEventListener('click', () => {
if (this.mobileMenuOpen) {
toggleMobileMenu();
// Mobile accordion sections
const mobileSections = document.querySelectorAll('.mobile-nav-section');
mobileSections.forEach(section => {
const btn = section.querySelector('.mobile-nav-section-btn');
const content = section.querySelector('.mobile-nav-section-content');
const chevron = btn ? btn.querySelector('svg') : null;
if (!btn || !content) return;
btn.addEventListener('click', () => {
const isCollapsed = content.classList.contains('max-h-0');
if (isCollapsed) {
content.classList.remove('max-h-0');
content.classList.add('max-h-96');
if (chevron) chevron.style.transform = 'rotate(180deg)';
} else {
content.classList.remove('max-h-96');
content.classList.add('max-h-0');
if (chevron) chevron.style.transform = '';
}
window.dispatchEvent(new CustomEvent('openFeedbackModal'));
});
}
});
// Auto-expand mobile section containing current page
this.autoExpandActiveSection();
}
normalizePath(path) {
if (!path || path.startsWith('http')) return path;
if (path === '/' || path === '/index.html') return '/';
return path.replace('.html', '').replace(/\/$/, '');
}
setActivePageIndicator() {
const currentPath = window.location.pathname;
const normalizedCurrent = this.normalizePath(currentPath);
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
// Desktop nav links — highlight top-level links and dropdown trigger buttons
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');
const normalizedLink = this.normalizePath(linkPath);
if (normalizedLink === normalizedCurrent) {
// Highlight the link itself if it's a direct top-level link (not inside dropdown panel)
if (!link.closest('.nav-dropdown-panel')) {
link.classList.add('text-blue-700', 'bg-blue-50');
link.classList.remove('text-gray-700', 'text-gray-600');
}
// Also highlight the parent dropdown button if this link is inside a dropdown
const dropdownContainer = link.closest('[data-dropdown]');
if (dropdownContainer) {
const dropdownBtn = dropdownContainer.querySelector('.nav-dropdown-btn');
if (dropdownBtn) {
dropdownBtn.classList.add('text-blue-700');
dropdownBtn.classList.remove('text-gray-700');
}
}
}
});
@ -431,7 +474,7 @@ class TractatusNavbar {
const mobileLinks = document.querySelectorAll('#mobile-menu a');
mobileLinks.forEach(link => {
const linkPath = link.getAttribute('href');
const normalizedLink = normalizePath(linkPath);
const normalizedLink = this.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)';
@ -439,6 +482,33 @@ class TractatusNavbar {
}
});
}
autoExpandActiveSection() {
const currentPath = window.location.pathname;
const normalizedCurrent = this.normalizePath(currentPath);
const mobileSections = document.querySelectorAll('.mobile-nav-section');
mobileSections.forEach(section => {
const content = section.querySelector('.mobile-nav-section-content');
const chevron = section.querySelector('.mobile-nav-section-btn svg');
if (!content) return;
const links = content.querySelectorAll('a[href]');
let hasActive = false;
links.forEach(link => {
const linkPath = link.getAttribute('href');
if (this.normalizePath(linkPath) === normalizedCurrent) {
hasActive = true;
}
});
if (hasActive) {
content.classList.remove('max-h-0');
content.classList.add('max-h-96');
if (chevron) chevron.style.transform = 'rotate(180deg)';
}
});
}
}
// Auto-initialize when DOM is ready