109 lines
4.4 KiB
HTML
109 lines
4.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>State DOT Contacts | PilotEdge</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
</head>
|
|
<body class="bg-slate-50 min-h-screen flex flex-col">
|
|
|
|
<div id="main-nav"></div>
|
|
<div id="poc-banner"></div>
|
|
|
|
<!-- Page Header -->
|
|
<section class="bg-slate-900 text-white pt-24 pb-12 px-4">
|
|
<div class="max-w-7xl mx-auto">
|
|
<h1 class="text-3xl md:text-4xl font-bold mb-3">State DOT Contact Directory</h1>
|
|
<p class="text-lg text-gray-400 max-w-3xl">Find permit office phone numbers, state police non-emergency lines, and online portal links for every state.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Search / Filter Bar -->
|
|
<section class="max-w-7xl mx-auto px-4 py-8 w-full">
|
|
<div class="bg-white rounded-2xl shadow-lg p-6">
|
|
<label for="state-search" class="block text-sm font-semibold text-slate-700 mb-2">Search States</label>
|
|
<input
|
|
type="text"
|
|
id="state-search"
|
|
placeholder="Type a state name to filter…"
|
|
class="w-full border border-slate-300 rounded-lg px-4 py-3 focus:ring-2 focus:ring-amber-400 focus:border-amber-400 outline-none text-slate-900"
|
|
>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Contact Cards Grid -->
|
|
<section class="max-w-7xl mx-auto px-4 pb-12 w-full">
|
|
<div id="contacts-grid" class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
<!-- Populated by JS -->
|
|
</div>
|
|
<p id="no-results" class="hidden text-center text-slate-500 py-12 text-lg">No states match your search.</p>
|
|
</section>
|
|
|
|
<div id="main-footer"></div>
|
|
|
|
<script src="mock-data.js"></script>
|
|
<script src="mock-data-extended.js"></script>
|
|
<script src="nav.js"></script>
|
|
<script>
|
|
renderNav('contacts');
|
|
renderBanner();
|
|
renderFooter();
|
|
|
|
const grid = document.getElementById('contacts-grid');
|
|
const noResults = document.getElementById('no-results');
|
|
const searchInput = document.getElementById('state-search');
|
|
|
|
function buildCard(abbr, c) {
|
|
return `
|
|
<div class="bg-white rounded-2xl shadow-lg p-6 flex flex-col" data-state="${c.name.toLowerCase()}">
|
|
<h3 class="text-lg font-bold text-slate-900 mb-1">${c.name} <span class="text-slate-400 font-medium text-sm">(${abbr})</span></h3>
|
|
<div class="mt-3 space-y-2 text-sm text-slate-700 flex-1">
|
|
<p class="flex items-start gap-2">
|
|
<span class="shrink-0">📞</span>
|
|
<span><span class="font-medium">Permit Office:</span> <a href="tel:${c.permit.replace(/[^+\d]/g, '')}" class="text-amber-600 hover:text-amber-700 font-semibold">${c.permit}</a></span>
|
|
</p>
|
|
<p class="flex items-start gap-2">
|
|
<span class="shrink-0">🚔</span>
|
|
<span><span class="font-medium">State Police:</span> <a href="tel:${c.police.replace(/[^+\d]/g, '')}" class="text-amber-600 hover:text-amber-700 font-semibold">${c.police}</a></span>
|
|
</p>
|
|
<p class="flex items-start gap-2">
|
|
<span class="shrink-0">✉️</span>
|
|
<span><span class="font-medium">Email:</span> <a href="mailto:${c.email}" class="text-amber-600 hover:text-amber-700 font-semibold break-all">${c.email}</a></span>
|
|
</p>
|
|
<p class="flex items-start gap-2">
|
|
<span class="shrink-0">🕐</span>
|
|
<span><span class="font-medium">Hours:</span> ${c.hours}</span>
|
|
</p>
|
|
</div>
|
|
<a href="${c.portal}" target="_blank" rel="noopener noreferrer"
|
|
class="mt-4 inline-flex items-center justify-center gap-1 bg-amber-500 hover:bg-amber-600 text-slate-900 font-bold text-sm px-4 py-2 rounded-lg transition-colors shadow-md">
|
|
Visit Permit Portal <span class="text-xs">↗</span>
|
|
</a>
|
|
</div>`;
|
|
}
|
|
|
|
function renderCards(filter) {
|
|
const term = (filter || '').toLowerCase();
|
|
let html = '';
|
|
let count = 0;
|
|
|
|
Object.keys(MOCK_STATE_CONTACTS).forEach(abbr => {
|
|
const c = MOCK_STATE_CONTACTS[abbr];
|
|
if (!term || c.name.toLowerCase().includes(term) || abbr.toLowerCase().includes(term)) {
|
|
html += buildCard(abbr, c);
|
|
count++;
|
|
}
|
|
});
|
|
|
|
grid.innerHTML = html;
|
|
noResults.classList.toggle('hidden', count > 0);
|
|
}
|
|
|
|
searchInput.addEventListener('input', () => renderCards(searchInput.value));
|
|
|
|
renderCards();
|
|
</script>
|
|
</body>
|
|
</html>
|