feat(directory): enhance cross streets callout, camera photos, and city search integration

This commit is contained in:
2026-09-12 09:47:29 -07:00
parent be8981d024
commit ef36bfb050
7 changed files with 197 additions and 58 deletions
+57 -11
View File
@@ -354,17 +354,47 @@
const agencyMatch = (c.agency || '').toLowerCase().includes(q);
const slugMatch = (c.slug || '').toLowerCase().includes(q);
const notesMatch = (c.notes || '').toLowerCase().includes(q);
return nameMatch || agencyMatch || slugMatch || notesMatch;
const cityMatch = (c.city || '').toLowerCase().includes(q);
const crossMatch = (c.crossStreets || '').toLowerCase().includes(q);
const stateMatch = (c.state || '').toLowerCase() === q;
return nameMatch || agencyMatch || slugMatch || notesMatch || cityMatch || crossMatch || stateMatch;
});
// Filter by state if state dropdown is not ALL
if (state.selectedState && state.selectedState !== 'ALL') {
matchingCams = matchingCams.filter(c => {
if (c.state) return c.state.toUpperCase() === state.selectedState.toUpperCase();
if (state.selectedState === 'CA') return c.id.includes('plm') || c.id.includes('lan') || c.id.includes('cal');
return true;
});
}
// Filter by agency type if not ALL
if (state.selectedType && state.selectedType !== 'ALL') {
matchingCams = matchingCams.filter(c => {
if (c.dept_type) return c.dept_type.toUpperCase() === state.selectedType.toUpperCase();
if (state.selectedType === 'SO') return (c.agency && (c.agency.toLowerCase().includes('sheriff') || c.agency.includes('LASD')));
if (state.selectedType === 'PD') return (c.agency && (c.agency.toLowerCase().includes('police') || c.agency.includes('PD')));
return true;
});
}
} else if (state.selectedState && state.selectedState !== 'ALL') {
matchingCams = allCams.filter(c => {
if (state.selectedState === 'CA') {
return c.id.includes('plm') || c.id.includes('lan') || c.id.includes('cal') || (c.agency && c.agency.includes('LASD'));
let stMatch = false;
if (c.state) stMatch = (c.state.toUpperCase() === state.selectedState.toUpperCase());
else if (state.selectedState === 'CA') stMatch = c.id.includes('plm') || c.id.includes('lan') || c.id.includes('cal');
else if (state.selectedState === 'KY') stMatch = c.id.includes('lex');
else if (state.selectedState === 'GA') stMatch = c.id.includes('atl');
else if (state.selectedState === 'TX') stMatch = c.id.includes('dfw');
if (!stMatch) return false;
if (state.selectedType && state.selectedType !== 'ALL') {
if (c.dept_type) return c.dept_type.toUpperCase() === state.selectedType.toUpperCase();
if (state.selectedType === 'SO') return (c.agency && (c.agency.toLowerCase().includes('sheriff') || c.agency.includes('LASD')));
if (state.selectedType === 'PD') return (c.agency && (c.agency.toLowerCase().includes('police') || c.agency.includes('PD')));
}
if (state.selectedState === 'KY') return c.id.includes('lex');
if (state.selectedState === 'GA') return c.id.includes('atl');
if (state.selectedState === 'TX') return c.id.includes('dfw');
return false;
return true;
});
}
@@ -395,20 +425,26 @@
const photoUrl = meta.photoUrl || cam.photoUrl || null;
const hasPhoto = !!photoUrl;
const crossStreets = cam.crossStreets || (cam.name ? cam.name.split('(')[0].replace(/^.*?-\s*/, '').trim() : 'Intersection Camera');
const badgeHtml = meta.isContested
? `<span class="dir-cam-badge unverified">🟠 CONTESTED</span>`
: (hasPhoto ? `<span class="dir-cam-badge verified">🟢 PHOTO VERIFIED</span>` : `<span class="dir-cam-badge unverified">⚠️ FLOCK RECORDED</span>`);
: (hasPhoto ? `<span class="dir-cam-badge verified">🟢 HARDWARE PHOTO VERIFIED</span>` : `<span class="dir-cam-badge unverified">⚠️ SIGHTING RECORDED</span>`);
const imageContainerHtml = hasPhoto
? `<div class="dir-cam-image-container">
<img src="${photoUrl}" class="dir-cam-img" alt="Camera at ${escapeHtml(cam.name)}" onclick="window.open('${photoUrl}', '_blank')" title="Click to view full photo proof">
<img src="${photoUrl}" class="dir-cam-img" alt="Camera at ${escapeHtml(crossStreets)}" onclick="window.open('${photoUrl}', '_blank')" title="Click to view full photo proof in high resolution">
${badgeHtml}
<div class="dir-cam-img-hover-hint">🔍 Tap to inspect photo proof</div>
</div>`
: `<div class="dir-cam-image-container">
: `<div class="dir-cam-image-container pending">
<div class="dir-cam-placeholder">
<span class="dir-cam-placeholder-icon">📸</span>
<strong style="font-size: 0.82rem; color: #cbd5e1;">Hardware Photo Pending</strong>
<strong style="font-size: 0.84rem; color: #cbd5e1;">Hardware Photo Pending</strong>
<span style="font-size: 0.72rem; color: #94a3b8;">Mounted on utility / signal pole</span>
<button type="button" class="btn-dir-cam-upload-trigger" onclick="window.openCameraHardwareProof('${escapeHtml(cam.id)}')">
<span>+ Upload Photo Proof</span>
</button>
</div>
${badgeHtml}
</div>`;
@@ -418,9 +454,19 @@
${imageContainerHtml}
<div class="dir-cam-body">
<div>
<!-- Cross Streets Prominent Box -->
<div class="dir-cam-cross-box">
<span class="dir-cam-cross-icon">📍</span>
<div class="dir-cam-cross-content">
<span class="dir-cam-cross-label">CROSS STREETS</span>
<strong class="dir-cam-cross-value">${escapeHtml(crossStreets)}</strong>
</div>
</div>
<h4 class="dir-cam-intersection">${escapeHtml(cam.name)}</h4>
<div class="dir-cam-agency-meta">
<span>🏛️ ${escapeHtml(cam.agency || 'Local Law Enforcement')}</span>
${cam.city ? `<span class="dir-cam-city-tag">🗺️ ${escapeHtml(cam.city)}, ${escapeHtml(cam.state || 'CA')}</span>` : ''}
</div>
<div class="dir-cam-specs-row">