Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>DealerDetective Pro - Find Dealership Contacts</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script> | |
| <style> | |
| .gradient-bg { | |
| background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); | |
| } | |
| .card-hover { | |
| transition: transform 0.3s ease, box-shadow 0.3s ease; | |
| } | |
| .card-hover:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); | |
| } | |
| .input-focus:focus { | |
| box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5); | |
| } | |
| </style> | |
| </head> | |
| <body class="min-h-screen gradient-bg text-white" id="vanta-bg"> | |
| <div class="container mx-auto px-4 py-12"> | |
| <!-- Header --> | |
| <header class="mb-12 text-center"> | |
| <h1 class="text-4xl md:text-5xl font-bold mb-4">Dealer<span class="text-blue-300">Detective</span> Pro</h1> | |
| <p class="text-xl text-blue-100 max-w-2xl mx-auto">Uncover hidden dealership contacts with our powerful scraping tool</p> | |
| </header> | |
| <!-- Main Card --> | |
| <div class="max-w-3xl mx-auto bg-gray-800 bg-opacity-80 rounded-xl shadow-2xl overflow-hidden card-hover p-6 backdrop-blur-sm"> | |
| <div class="flex items-center mb-6"> | |
| <i data-feather="search" class="w-8 h-8 text-blue-300 mr-3"></i> | |
| <h2 class="text-2xl font-semibold">Dealership URL Scanner</h2> | |
| </div> | |
| <form id="scanForm" class="space-y-6"> | |
| <div> | |
| <label for="dealerUrl" class="block text-sm font-medium text-blue-100 mb-2">Enter Dealership Website URL</label> | |
| <div class="flex"> | |
| <input | |
| type="url" | |
| id="dealerUrl" | |
| placeholder="https://www.example.com" | |
| class="input-focus flex-grow px-4 py-3 rounded-l-lg bg-gray-700 text-white placeholder-gray-400 focus:outline-none" | |
| required | |
| > | |
| <button | |
| type="submit" | |
| class="bg-blue-500 hover:bg-blue-600 px-6 py-3 rounded-r-lg font-medium transition-colors duration-200 flex items-center" | |
| > | |
| <i data-feather="scan" class="w-5 h-5 mr-2"></i> Scan | |
| </button> | |
| </div> | |
| </div> | |
| <div class="flex items-center"> | |
| <input id="deepScan" type="checkbox" class="h-4 w-4 text-blue-500 rounded"> | |
| <label for="deepScan" class="ml-2 text-sm text-blue-100">Enable deep scan (finds hidden staff pages)</label> | |
| </div> | |
| </form> | |
| <div id="loadingIndicator" class="hidden mt-6"> | |
| <div class="flex items-center"> | |
| <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-400"></div> | |
| <span class="ml-3 text-blue-200">Scanning website structure...</span> | |
| </div> | |
| </div> | |
| <div id="resultsSection" class="hidden mt-8"> | |
| <h3 class="text-xl font-medium mb-4 flex items-center"> | |
| <i data-feather="users" class="w-5 h-5 mr-2 text-blue-300"></i> | |
| Found Contacts | |
| </h3> | |
| <div class="bg-gray-900 rounded-lg p-4"> | |
| <div id="contactsList" class="space-y-4"> | |
| <!-- Results will be inserted here --> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Features Section --> | |
| <div class="mt-16 grid md:grid-cols-3 gap-8 max-w-6xl mx-auto"> | |
| <div class="bg-gray-800 bg-opacity-80 p-6 rounded-xl card-hover"> | |
| <div class="w-12 h-12 bg-blue-500 rounded-full flex items-center justify-center mb-4"> | |
| <i data-feather="link" class="w-6 h-6"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold mb-2">URL Analysis</h3> | |
| <p class="text-blue-100">Automatically detects dealership website structure to find staff pages</p> | |
| </div> | |
| <div class="bg-gray-800 bg-opacity-80 p-6 rounded-xl card-hover"> | |
| <div class="w-12 h-12 bg-blue-500 rounded-full flex items-center justify-center mb-4"> | |
| <i data-feather="eye" class="w-6 h-6"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold mb-2">Hidden Page Detection</h3> | |
| <p class="text-blue-100">Finds even unlinked staff pages through smart pattern recognition</p> | |
| </div> | |
| <div class="bg-gray-800 bg-opacity-80 p-6 rounded-xl card-hover"> | |
| <div class="w-12 h-12 bg-blue-500 rounded-full flex items-center justify-center mb-4"> | |
| <i data-feather="download" class="w-6 h-6"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold mb-2">Export Contacts</h3> | |
| <p class="text-blue-100">Download all found contacts in CSV format for easy CRM integration</p> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Initialize Vanta.js background | |
| VANTA.NET({ | |
| el: "#vanta-bg", | |
| mouseControls: true, | |
| touchControls: true, | |
| gyroControls: false, | |
| minHeight: 200.00, | |
| minWidth: 200.00, | |
| scale: 1.00, | |
| scaleMobile: 1.00, | |
| color: 0x3b82f6, | |
| backgroundColor: 0x111827, | |
| points: 12.00, | |
| maxDistance: 24.00, | |
| spacing: 18.00 | |
| }); | |
| // Form submission handler | |
| document.getElementById('scanForm').addEventListener('submit', async function(e) { | |
| e.preventDefault(); | |
| const url = document.getElementById('dealerUrl').value; | |
| const deepScan = document.getElementById('deepScan').checked; | |
| // Show loading indicator | |
| document.getElementById('loadingIndicator').classList.remove('hidden'); | |
| document.getElementById('resultsSection').classList.add('hidden'); | |
| try { | |
| const response = await fetch('https://your-worker-url.workers.dev', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| url: url, | |
| deepScan: deepScan | |
| }) | |
| }); | |
| if (!response.ok) throw new Error('Scan failed'); | |
| const result = await response.json(); | |
| displayResults(result); | |
| } catch (error) { | |
| console.error('Error:', error); | |
| document.getElementById('contactsList').innerHTML = ` | |
| <div class="bg-red-900 text-red-100 p-4 rounded-lg"> | |
| <div class="flex items-center"> | |
| <i data-feather="alert-triangle" class="w-5 h-5 mr-2"></i> | |
| Failed to scan website: ${error.message} | |
| </div> | |
| </div> | |
| `; | |
| feather.replace(); | |
| } finally { | |
| document.getElementById('loadingIndicator').classList.add('hidden'); | |
| document.getElementById('resultsSection').classList.remove('hidden'); | |
| } | |
| }); | |
| function displayResults(data) { | |
| const contactsList = document.getElementById('contactsList'); | |
| if (!data.contacts || data.contacts.length === 0) { | |
| contactsList.innerHTML = ` | |
| <div class="bg-gray-800 p-4 rounded-lg"> | |
| <div class="flex items-center"> | |
| <i data-feather="info" class="w-5 h-5 mr-2"></i> | |
| No contacts found on this website | |
| </div> | |
| </div> | |
| `; | |
| return; | |
| } | |
| let html = ''; | |
| data.contacts.forEach(contact => { | |
| const badges = []; | |
| if (contact.department) badges.push(contact.department); | |
| if (contact.title) badges.push(contact.title); | |
| html += ` | |
| <div class="bg-gray-800 p-4 rounded-lg"> | |
| ${contact.name ? ` | |
| <div class="flex justify-between items-center mb-2"> | |
| <h4 class="font-medium">${contact.name}</h4> | |
| ${badges.length ? ` | |
| <div class="flex space-x-2"> | |
| ${badges.map(badge => | |
| `<span class="bg-blue-500 text-xs px-2 py-1 rounded">${badge}</span>` | |
| ).join('')} | |
| </div> | |
| ` : ''} | |
| </div> | |
| ` : ''} | |
| <div class="text-sm text-gray-300"> | |
| ${contact.email ? ` | |
| <div class="flex items-center mb-1"> | |
| <i data-feather="mail" class="w-4 h-4 mr-2"></i> | |
| ${contact.email} | |
| </div> | |
| ` : ''} | |
| ${contact.phone ? ` | |
| <div class="flex items-center"> | |
| <i data-feather="phone" class="w-4 h-4 mr-2"></i> | |
| ${contact.phone} | |
| </div> | |
| ` : ''} | |
| </div> | |
| </div> | |
| `; | |
| }); | |
| html += ` | |
| <div class="flex justify-end mt-4"> | |
| <button | |
| class="bg-blue-500 hover:bg-blue-600 px-4 py-2 rounded-lg text-sm font-medium flex items-center" | |
| onclick="exportContacts(${JSON.stringify(data.contacts)})" | |
| > | |
| <i data-feather="download" class="w-4 h-4 mr-2"></i> | |
| Export All Contacts (${data.contacts.length}) | |
| </button> | |
| </div> | |
| `; | |
| contactsList.innerHTML = html; | |
| feather.replace(); | |
| } | |
| function exportContacts(contacts) { | |
| let csv = 'Name,Email,Phone,Title,Department\n'; | |
| contacts.forEach(c => { | |
| csv += `"${c.name || ''}","${c.email || ''}","${c.phone || ''}","${c.title || ''}","${c.department || ''}"\n`; | |
| }); | |
| const blob = new Blob([csv], { type: 'text/csv' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.setAttribute('hidden', ''); | |
| a.setAttribute('href', url); | |
| a.setAttribute('download', 'dealer_contacts.csv'); | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| } | |
| // Initialize feather icons | |
| feather.replace(); | |
| // Replace with your actual Cloudflare Worker URL | |
| const WORKER_URL = 'https://your-worker-url.workers.dev'; | |
| </script> | |
| </body> | |
| </html> | |