- public/index.html — landing page at root - public/pages/ — all feature pages (regulations, loadboard, etc.) - public/js/ — api.js, nav.js, mock data files - All links updated to absolute paths (/pages/, /js/) - Express static path updated to serve from public/ - Seed script path updated for new mock data location - README updated with new project structure and setup guide - Added .env.example template Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
194 lines
12 KiB
JavaScript
194 lines
12 KiB
JavaScript
// =============================================
|
|
// Shared Navigation, Banner, and Footer
|
|
// Include on every page via <script src="/js/nav.js">
|
|
// =============================================
|
|
|
|
function renderNav(activePage) {
|
|
const nav = document.getElementById('main-nav');
|
|
if (!nav) return;
|
|
|
|
const isActive = (id) => id === activePage;
|
|
const linkClass = (id) => isActive(id) ? 'text-amber-400 font-semibold' : 'text-gray-300 hover:text-white';
|
|
const dropLinkClass = (id) => isActive(id) ? 'bg-amber-50 text-amber-700 font-semibold' : 'text-slate-700 hover:bg-slate-50';
|
|
|
|
const regulationsActive = ['regulations','equipment','contacts','calendar'].includes(activePage);
|
|
const roadIntelActive = ['truckstops','bridges','weighstations','alerts'].includes(activePage);
|
|
|
|
nav.innerHTML = `
|
|
<nav class="bg-slate-900 text-white fixed top-0 w-full z-50 shadow-lg">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="flex items-center justify-between h-16">
|
|
<a href="/" class="flex items-center space-x-2 flex-shrink-0">
|
|
<span class="text-2xl">🚛</span>
|
|
<span class="text-xl font-bold text-amber-400 tracking-tight">PilotEdge</span>
|
|
</a>
|
|
|
|
<!-- Desktop Nav -->
|
|
<div class="hidden lg:flex items-center space-x-1">
|
|
<a href="/" class="${linkClass('home')} px-3 py-2 rounded-md text-sm transition-colors">Home</a>
|
|
|
|
<!-- Regulations Dropdown -->
|
|
<div class="relative group">
|
|
<button class="${regulationsActive ? 'text-amber-400 font-semibold' : 'text-gray-300 hover:text-white'} px-3 py-2 rounded-md text-sm transition-colors flex items-center gap-1">
|
|
Regulations
|
|
<svg class="w-3.5 h-3.5 opacity-60" 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="absolute left-0 top-full pt-1 hidden group-hover:block" style="min-width:220px;">
|
|
<div class="bg-white rounded-xl shadow-xl border border-slate-200 py-2">
|
|
<a href="/pages/regulations.html" class="${dropLinkClass('regulations')} block px-4 py-2.5 text-sm transition-colors">
|
|
<div class="font-medium">State Regulations Map</div>
|
|
<div class="text-xs text-slate-400 mt-0.5">Permits & escort thresholds</div>
|
|
</a>
|
|
<a href="/pages/regulations.html#equipment" class="${dropLinkClass('equipment')} block px-4 py-2.5 text-sm transition-colors">
|
|
<div class="font-medium">Equipment Requirements</div>
|
|
<div class="text-xs text-slate-400 mt-0.5">Escort & carrier gear by state</div>
|
|
</a>
|
|
<a href="/pages/contacts.html" class="${dropLinkClass('contacts')} block px-4 py-2.5 text-sm transition-colors">
|
|
<div class="font-medium">DOT Contact Directory</div>
|
|
<div class="text-xs text-slate-400 mt-0.5">Permit office phone & email</div>
|
|
</a>
|
|
<a href="/pages/calendar.html" class="${dropLinkClass('calendar')} block px-4 py-2.5 text-sm transition-colors">
|
|
<div class="font-medium">Seasonal Calendar</div>
|
|
<div class="text-xs text-slate-400 mt-0.5">Restrictions & closures</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Road Intel Dropdown -->
|
|
<div class="relative group">
|
|
<button class="${roadIntelActive ? 'text-amber-400 font-semibold' : 'text-gray-300 hover:text-white'} px-3 py-2 rounded-md text-sm transition-colors flex items-center gap-1">
|
|
Road Intel
|
|
<svg class="w-3.5 h-3.5 opacity-60" 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="absolute left-0 top-full pt-1 hidden group-hover:block" style="min-width:220px;">
|
|
<div class="bg-white rounded-xl shadow-xl border border-slate-200 py-2">
|
|
<a href="/pages/truckstops.html" class="${dropLinkClass('truckstops')} block px-4 py-2.5 text-sm transition-colors">
|
|
<div class="font-medium">Truck Stops & Parking</div>
|
|
<div class="text-xs text-slate-400 mt-0.5">Oversize-friendly locations</div>
|
|
</a>
|
|
<a href="/pages/bridges.html" class="${dropLinkClass('bridges')} block px-4 py-2.5 text-sm transition-colors">
|
|
<div class="font-medium">Bridge Clearances</div>
|
|
<div class="text-xs text-slate-400 mt-0.5">Height & width restrictions</div>
|
|
</a>
|
|
<a href="/pages/weighstations.html" class="${dropLinkClass('weighstations')} block px-4 py-2.5 text-sm transition-colors">
|
|
<div class="font-medium">Weigh Stations</div>
|
|
<div class="text-xs text-slate-400 mt-0.5">Live open/closed status</div>
|
|
</a>
|
|
<a href="/pages/alerts.html" class="${dropLinkClass('alerts')} block px-4 py-2.5 text-sm transition-colors">
|
|
<div class="font-medium">Route & Weather Alerts</div>
|
|
<div class="text-xs text-slate-400 mt-0.5">Closures, construction, wind</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<a href="/pages/loadboard.html" class="${linkClass('loadboard')} px-3 py-2 rounded-md text-sm transition-colors">Load Board</a>
|
|
<a href="/pages/locator.html" class="${linkClass('locator')} px-3 py-2 rounded-md text-sm transition-colors">Find Escorts</a>
|
|
<a href="/pages/documents.html" class="${linkClass('documents')} px-3 py-2 rounded-md text-sm transition-colors">Documents</a>
|
|
|
|
<a href="/pages/order.html" class="ml-2 bg-amber-500 hover:bg-amber-600 text-slate-900 font-bold px-4 py-2 rounded-lg transition-colors shadow-md hover:shadow-lg text-sm">
|
|
Request Service
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Mobile menu button -->
|
|
<button onclick="toggleMobileMenu()" class="lg:hidden text-gray-300 hover:text-white 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>
|
|
|
|
<!-- Mobile Menu -->
|
|
<div id="mobile-menu" class="lg:hidden hidden border-t border-slate-700 px-4 pb-4 max-h-[80vh] overflow-y-auto">
|
|
<a href="/" class="block py-2 px-3 mt-2 rounded ${isActive('home') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">Home</a>
|
|
|
|
<div class="mt-2 mb-1 px-3 text-xs font-semibold text-slate-500 uppercase tracking-wider">Regulations</div>
|
|
<a href="/pages/regulations.html" class="block py-2 px-3 rounded ${isActive('regulations') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">State Regulations Map</a>
|
|
<a href="/pages/regulations.html#equipment" class="block py-2 px-3 rounded ${isActive('equipment') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">Equipment Requirements</a>
|
|
<a href="/pages/contacts.html" class="block py-2 px-3 rounded ${isActive('contacts') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">DOT Contacts</a>
|
|
<a href="/pages/calendar.html" class="block py-2 px-3 rounded ${isActive('calendar') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">Seasonal Calendar</a>
|
|
|
|
<div class="mt-2 mb-1 px-3 text-xs font-semibold text-slate-500 uppercase tracking-wider">Road Intel</div>
|
|
<a href="/pages/truckstops.html" class="block py-2 px-3 rounded ${isActive('truckstops') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">Truck Stops & Parking</a>
|
|
<a href="/pages/bridges.html" class="block py-2 px-3 rounded ${isActive('bridges') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">Bridge Clearances</a>
|
|
<a href="/pages/weighstations.html" class="block py-2 px-3 rounded ${isActive('weighstations') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">Weigh Stations</a>
|
|
<a href="/pages/alerts.html" class="block py-2 px-3 rounded ${isActive('alerts') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">Route & Weather Alerts</a>
|
|
|
|
<div class="mt-2 mb-1 px-3 text-xs font-semibold text-slate-500 uppercase tracking-wider">Services</div>
|
|
<a href="/pages/loadboard.html" class="block py-2 px-3 rounded ${isActive('loadboard') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">Load Board</a>
|
|
<a href="/pages/locator.html" class="block py-2 px-3 rounded ${isActive('locator') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">Find Escorts</a>
|
|
<a href="/pages/documents.html" class="block py-2 px-3 rounded ${isActive('documents') ? 'text-amber-400 bg-slate-800' : 'text-gray-300'}">Document Vault</a>
|
|
|
|
<a href="/pages/order.html" class="block py-2 px-3 mt-3 bg-amber-500 text-slate-900 font-bold rounded-lg text-center">Request Service</a>
|
|
</div>
|
|
</nav>
|
|
`;
|
|
}
|
|
|
|
function toggleMobileMenu() {
|
|
const menu = document.getElementById('mobile-menu');
|
|
if (menu) menu.classList.toggle('hidden');
|
|
}
|
|
|
|
function renderBanner() {
|
|
const banner = document.getElementById('poc-banner');
|
|
if (!banner) return;
|
|
banner.innerHTML = `
|
|
<div class="bg-amber-100 border-b border-amber-300 text-amber-900 text-center text-sm py-2 mt-16 px-4">
|
|
⚠️ <strong>POC / Demo</strong> — All regulation data is simulated for demonstration purposes. Verify with official state DOT sources before real-world use.
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function renderFooter() {
|
|
const footer = document.getElementById('main-footer');
|
|
if (!footer) return;
|
|
footer.innerHTML = `
|
|
<footer class="bg-slate-900 text-gray-400 mt-16">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
<div class="grid md:grid-cols-4 gap-8">
|
|
<div>
|
|
<div class="flex items-center space-x-2 mb-4">
|
|
<span class="text-2xl">🚛</span>
|
|
<span class="text-lg font-bold text-amber-400">PilotEdge</span>
|
|
</div>
|
|
<p class="text-sm">Your complete resource for oversize and overdimensional load hauling. Built by industry professionals, for industry professionals.</p>
|
|
</div>
|
|
<div>
|
|
<h4 class="text-white font-semibold mb-3">Regulations</h4>
|
|
<ul class="space-y-2 text-sm">
|
|
<li><a href="/pages/regulations.html" class="hover:text-white transition-colors">State Regulations Map</a></li>
|
|
<li><a href="/pages/contacts.html" class="hover:text-white transition-colors">DOT Contact Directory</a></li>
|
|
<li><a href="/pages/calendar.html" class="hover:text-white transition-colors">Seasonal Calendar</a></li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h4 class="text-white font-semibold mb-3">Road Intel</h4>
|
|
<ul class="space-y-2 text-sm">
|
|
<li><a href="/pages/truckstops.html" class="hover:text-white transition-colors">Truck Stops & Parking</a></li>
|
|
<li><a href="/pages/bridges.html" class="hover:text-white transition-colors">Bridge Clearances</a></li>
|
|
<li><a href="/pages/weighstations.html" class="hover:text-white transition-colors">Weigh Stations</a></li>
|
|
<li><a href="/pages/alerts.html" class="hover:text-white transition-colors">Route & Weather Alerts</a></li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h4 class="text-white font-semibold mb-3">Services</h4>
|
|
<ul class="space-y-2 text-sm">
|
|
<li><a href="/pages/loadboard.html" class="hover:text-white transition-colors">Load Board</a></li>
|
|
<li><a href="/pages/locator.html" class="hover:text-white transition-colors">Find Escort Vehicles</a></li>
|
|
<li><a href="/pages/documents.html" class="hover:text-white transition-colors">Document Vault</a></li>
|
|
<li><a href="/pages/order.html" class="hover:text-white transition-colors">Request Escort Service</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="border-t border-slate-700 mt-8 pt-6 text-center text-sm">
|
|
© 2026 PilotEdge. All rights reserved. | <span class="text-amber-400">V1 Proof of Concept</span>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
`;
|
|
}
|