|
|
| |
| const vendors = [ |
| { |
| id: 'abuse-ch', |
| name: 'abuse.ch', |
| logo: 'http://static.photos/technology/200x200/1', |
| description: 'Malware and botnet tracking platform', |
| features: ['Malware Tracking', 'Botnet Monitoring', 'IOC Feeds', 'Threat Intelligence'], |
| pricing: 'Freemium', |
| coverage: ['Network', 'Malware', 'Botnet'], |
| integrations: ['SIEM', 'Firewalls', 'EDR'], |
| freeTrial: true, |
| rating: 4.3 |
| }, |
| { |
| id: 'anomali', |
| name: 'Anomali', |
| logo: 'http://static.photos/technology/200x200/2', |
| description: 'Enterprise threat intelligence platform', |
| features: ['Threat Intelligence', 'Threat Hunting', 'SIEM Integration', 'Automation'], |
| pricing: 'Enterprise', |
| coverage: ['Network', 'Endpoint', 'Cloud'], |
| integrations: ['SIEM', 'Firewalls', 'EDR'], |
| freeTrial: false, |
| rating: 4.2 |
| }, |
| { |
| id: 'arctic-wolf', |
| name: 'Arctic Wolf Networks', |
| logo: 'http://static.photos/technology/200x200/3', |
| description: 'Security operations and threat intelligence', |
| features: ['Managed Detection', 'Threat Intelligence', 'Vulnerability Management', 'Cloud Monitoring'], |
| pricing: 'Subscription-based', |
| coverage: ['Network', 'Endpoint', 'Cloud'], |
| integrations: ['SIEM', 'SOAR', 'EDR'], |
| freeTrial: true, |
| rating: 4.5 |
| }, |
| { |
| id: 'bitdefender', |
| name: 'Bitdefender', |
| logo: 'http://static.photos/technology/200x200/4', |
| description: 'Endpoint protection with threat intelligence', |
| features: ['Endpoint Security', 'Threat Intelligence', 'Network Security', 'Cloud Security'], |
| pricing: 'Subscription-based', |
| coverage: ['Endpoint', 'Network', 'Cloud'], |
| integrations: ['SIEM', 'SOAR', 'EDR'], |
| freeTrial: true, |
| rating: 4.6 |
| }, |
| { |
| id: 'bitsight', |
| name: 'Bitsight', |
| logo: 'http://static.photos/technology/200x200/5', |
| description: 'Security ratings and risk intelligence', |
| features: ['Risk Assessment', 'Threat Intelligence', 'Third-Party Risk', 'Compliance'], |
| pricing: 'Enterprise', |
| coverage: ['Network', 'Web', 'Third-Party'], |
| integrations: ['SIEM', 'GRC', 'SOAR'], |
| freeTrial: false, |
| rating: 4.4 |
| }, |
| { |
| id: 'blocklist-de', |
| name: 'Blocklist.de', |
| logo: 'http://static.photos/technology/200x200/6', |
| description: 'Community-based IP blocklist', |
| features: ['IP Blocklist', 'Brute Force Protection', 'Attack Logs', 'Community Data'], |
| pricing: 'Free', |
| coverage: ['Network', 'IP Reputation'], |
| integrations: ['Firewalls', 'IDS/IPS', 'SIEM'], |
| freeTrial: true, |
| rating: 4.0 |
| }, |
| { |
| id: 'mandiant', |
| name: 'Mandiant Threat Intelligence', |
| logo: 'http://static.photos/technology/200x200/3', |
| description: 'Expert-led threat intelligence services', |
| features: ['Incident Response', 'Threat Intelligence', 'Malware Analysis', 'Vulnerability Research'], |
| pricing: 'Enterprise', |
| coverage: ['Network', 'Endpoint', 'Cloud'], |
| integrations: ['Firewalls', 'SIEM', 'EDR'], |
| freeTrial: false, |
| rating: 4.7 |
| }, |
| { |
| id: 'palo-alto', |
| name: 'Palo Alto Unit 42', |
| logo: 'http://static.photos/technology/200x200/4', |
| description: 'Integrated threat intelligence with next-gen firewalls', |
| features: ['Network Security', 'Cloud Security', 'Threat Intelligence', 'Automated Response'], |
| pricing: 'Bundled with Products', |
| coverage: ['Network', 'Cloud', 'Endpoint'], |
| integrations: ['Firewalls', 'Cortex XSOAR', 'SIEM'], |
| freeTrial: true, |
| rating: 4.5 |
| }, |
| { |
| id: 'fireeye', |
| name: 'FireEye Threat Intelligence', |
| logo: 'http://static.photos/technology/200x200/5', |
| description: 'Comprehensive threat intelligence and analysis', |
| features: ['Malware Analysis', 'Threat Intelligence', 'Incident Response', 'Vulnerability Research'], |
| pricing: 'Enterprise', |
| coverage: ['Network', 'Endpoint', 'Email'], |
| integrations: ['SIEM', 'EDR', 'SOAR'], |
| freeTrial: false, |
| rating: 4.4 |
| }, |
| { |
| id: 'anomali', |
| name: 'Anomali ThreatStream', |
| logo: 'http://static.photos/technology/200x200/6', |
| description: 'Threat intelligence platform for security operations', |
| features: ['Threat Intelligence', 'Threat Hunting', 'SIEM Integration', 'Automation'], |
| pricing: 'Subscription-based', |
| coverage: ['Network', 'Endpoint', 'Cloud'], |
| integrations: ['SIEM', 'Firewalls', 'EDR'], |
| freeTrial: true, |
| rating: 4.3 |
| }, |
| { |
| id: 'flashpoint', |
| name: 'Flashpoint Intelligence', |
| logo: 'http://static.photos/technology/200x200/7', |
| description: 'Business risk intelligence from the deep and dark web', |
| features: ['Dark Web Monitoring', 'Vulnerability Intelligence', 'Brand Protection', 'Fraud Detection'], |
| pricing: 'Enterprise', |
| coverage: ['Dark Web', 'Web', 'Network'], |
| integrations: ['SIEM', 'SOAR', 'TIPS'], |
| freeTrial: false, |
| rating: 4.5 |
| }, |
| { |
| id: 'threatconnect', |
| name: 'ThreatConnect', |
| logo: 'http://static.photos/technology/200x200/8', |
| description: 'Threat intelligence platform (TIP) with automation', |
| features: ['Threat Intelligence', 'Analytics', 'Automation', 'Collaboration'], |
| pricing: 'Subscription-based', |
| coverage: ['Network', 'Endpoint', 'Cloud'], |
| integrations: ['SIEM', 'SOAR', 'EDR'], |
| freeTrial: true, |
| rating: 4.2 |
| }, |
| { |
| id: 'alienvault', |
| name: 'AT&T Alien Labs', |
| logo: 'http://static.photos/technology/200x200/9', |
| description: 'Open threat intelligence community and platform', |
| features: ['Threat Intelligence', 'USM Platform', 'Open Source', 'Community'], |
| pricing: 'Freemium', |
| coverage: ['Network', 'Endpoint', 'Cloud'], |
| integrations: ['SIEM', 'USM', 'OSSIM'], |
| freeTrial: true, |
| rating: 4.0 |
| }, |
| { |
| id: 'wiz', |
| name: 'Wiz', |
| logo: 'http://static.photos/technology/200x200/50', |
| description: 'Cloud security and threat intelligence', |
| features: ['Cloud Security', 'Threat Detection', 'Vulnerability Management', 'Compliance'], |
| pricing: 'Subscription-based', |
| coverage: ['Cloud', 'Container', 'Serverless'], |
| integrations: ['SIEM', 'SOAR', 'CSPM'], |
| freeTrial: true, |
| rating: 4.7 |
| }, |
| { |
| id: 'withsecure', |
| name: 'WithSecure', |
| logo: 'http://static.photos/technology/200x200/51', |
| description: 'Endpoint protection and threat intelligence', |
| features: ['Endpoint Security', 'Threat Intelligence', 'EDR', 'XDR'], |
| pricing: 'Subscription-based', |
| coverage: ['Endpoint', 'Network', 'Cloud'], |
| integrations: ['SIEM', 'SOAR', 'EDR'], |
| freeTrial: true, |
| rating: 4.5 |
| }, |
| { |
| id: 'yeti', |
| name: 'Yeti', |
| logo: 'http://static.photos/technology/200x200/52', |
| description: 'Open-source threat intelligence platform', |
| features: ['Threat Intelligence', 'Malware Analysis', 'IOC Management', 'Collaboration'], |
| pricing: 'Open Source', |
| coverage: ['Network', 'Endpoint', 'Malware'], |
| integrations: ['SIEM', 'SOAR', 'MISP'], |
| freeTrial: true, |
| rating: 4.2 |
| }, |
| { |
| id: 'zerofox', |
| name: 'ZeroFOX', |
| logo: 'http://static.photos/technology/200x200/53', |
| description: 'Digital risk protection platform', |
| features: ['Social Media Protection', 'Threat Intelligence', 'Brand Protection', 'Fraud Detection'], |
| pricing: 'Enterprise', |
| coverage: ['Social Media', 'Web', 'Dark Web'], |
| integrations: ['SIEM', 'SOAR', 'TIPS'], |
| freeTrial: false, |
| rating: 4.4 |
| } |
| ]; |
|
|
| |
| vendors.sort((a, b) => a.name.localeCompare(b.name)); |
| |
| let selectedVendors = []; |
|
|
| |
| const vendorGrid = document.getElementById('vendor-grid'); |
| const comparisonBody = document.getElementById('comparison-body'); |
| const compareBtn = document.getElementById('compare-btn'); |
| const clearBtn = document.getElementById('clear-btn'); |
| const vendorModal = document.getElementById('vendor-modal'); |
| const closeModal = document.getElementById('close-modal'); |
| const modalTitle = document.getElementById('modal-title'); |
| const modalContent = document.getElementById('modal-content'); |
|
|
| |
| document.addEventListener('DOMContentLoaded', () => { |
| renderVendorGrid(); |
| setupEventListeners(); |
| }); |
|
|
| |
| function renderVendorGrid() { |
| vendorGrid.innerHTML = ''; |
| |
| vendors.forEach(vendor => { |
| const isSelected = selectedVendors.includes(vendor.id); |
| |
| const card = document.createElement('div'); |
| card.className = `vendor-card bg-white rounded-xl shadow-md overflow-hidden ${isSelected ? 'ring-2 ring-indigo-500' : ''}`; |
| card.innerHTML = ` |
| <div class="p-6"> |
| <div class="flex items-center mb-4"> |
| <img src="${vendor.logo}" alt="${vendor.name}" class="w-12 h-12 rounded-full object-cover mr-4"> |
| <div> |
| <h3 class="font-bold text-lg">${vendor.name}</h3> |
| <div class="flex items-center"> |
| <div class="flex text-yellow-400 mr-2"> |
| ${renderStars(vendor.rating)} |
| </div> |
| <span class="text-gray-600 text-sm">${vendor.rating}</span> |
| </div> |
| </div> |
| </div> |
| <p class="text-gray-600 mb-4">${vendor.description}</p> |
| <div class="flex flex-wrap mb-4"> |
| ${vendor.features.map(feature => ` |
| <span class="feature-badge bg-indigo-100 text-indigo-800">${feature}</span> |
| `).join('')} |
| </div> |
| <div class="flex justify-between items-center"> |
| <button data-vendor-id="${vendor.id}" class="view-details-btn text-indigo-600 hover:text-indigo-800 font-medium flex items-center"> |
| <i data-feather="info" class="w-4 h-4 mr-1"></i> Details |
| </button> |
| <button data-vendor-id="${vendor.id}" class="compare-btn ${isSelected ? 'bg-red-500 hover:bg-red-600' : 'bg-indigo-600 hover:bg-indigo-700'} text-white font-medium py-1 px-3 rounded-full text-sm flex items-center transition-colors"> |
| <i data-feather="${isSelected ? 'x' : 'plus'}" class="w-4 h-4 mr-1"></i> |
| ${isSelected ? 'Remove' : 'Compare'} |
| </button> |
| </div> |
| </div> |
| `; |
| |
| vendorGrid.appendChild(card); |
| }); |
| |
| feather.replace(); |
| } |
|
|
| |
| function renderStars(rating) { |
| const fullStars = Math.floor(rating); |
| const hasHalfStar = rating % 1 >= 0.5; |
| let stars = ''; |
| |
| for (let i = 0; i < fullStars; i++) { |
| stars += '<i data-feather="star" class="w-4 h-4 fill-current"></i>'; |
| } |
| |
| if (hasHalfStar) { |
| stars += '<i data-feather="star" class="w-4 h-4 fill-current" fill="url(#half-star)"></i>'; |
| } |
| |
| const emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0); |
| for (let i = 0; i < emptyStars; i++) { |
| stars += '<i data-feather="star" class="w-4 h-4"></i>'; |
| } |
| |
| return stars; |
| } |
|
|
| |
| function setupEventListeners() { |
| |
| compareBtn.addEventListener('click', () => { |
| if (selectedVendors.length < 2) { |
| alert('Please select at least 2 vendors to compare'); |
| return; |
| } |
| |
| renderComparisonTable(); |
| document.getElementById('comparison').scrollIntoView({ behavior: 'smooth' }); |
| }); |
| |
| |
| clearBtn.addEventListener('click', () => { |
| selectedVendors = []; |
| renderVendorGrid(); |
| comparisonBody.innerHTML = ''; |
| }); |
| |
| |
| closeModal.addEventListener('click', () => { |
| vendorModal.classList.add('hidden'); |
| }); |
| |
| |
| vendorGrid.addEventListener('click', (e) => { |
| const compareBtn = e.target.closest('.compare-btn'); |
| const detailsBtn = e.target.closest('.view-details-btn'); |
| |
| if (compareBtn) { |
| const vendorId = compareBtn.getAttribute('data-vendor-id'); |
| toggleVendorSelection(vendorId); |
| } |
| |
| if (detailsBtn) { |
| const vendorId = detailsBtn.getAttribute('data-vendor-id'); |
| showVendorDetails(vendorId); |
| } |
| }); |
| } |
|
|
| |
| function toggleVendorSelection(vendorId) { |
| const index = selectedVendors.indexOf(vendorId); |
| |
| if (index === -1) { |
| selectedVendors.push(vendorId); |
| } else { |
| selectedVendors.splice(index, 1); |
| } |
| |
| renderVendorGrid(); |
| } |
|
|
| |
| function showVendorDetails(vendorId) { |
| const vendor = vendors.find(v => v.id === vendorId); |
| |
| if (!vendor) return; |
| |
| modalTitle.textContent = vendor.name; |
| |
| modalContent.innerHTML = ` |
| <div class="flex items-start mb-6"> |
| <img src="${vendor.logo}" alt="${vendor.name}" class="w-20 h-20 rounded-full object-cover mr-6"> |
| <div> |
| <div class="flex items-center mb-2"> |
| <div class="flex text-yellow-400 mr-2"> |
| ${renderStars(vendor.rating)} |
| </div> |
| <span class="text-gray-600">${vendor.rating}/5.0</span> |
| </div> |
| <p class="text-gray-700">${vendor.description}</p> |
| </div> |
| </div> |
| |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> |
| <div> |
| <h4 class="font-bold text-lg mb-3">Features</h4> |
| <ul class="space-y-2"> |
| ${vendor.features.map(feature => ` |
| <li class="flex items-center"> |
| <i data-feather="check" class="w-4 h-4 text-green-500 mr-2"></i> |
| <span>${feature}</span> |
| </li> |
| `).join('')} |
| </ul> |
| </div> |
| |
| <div> |
| <h4 class="font-bold text-lg mb-3">Coverage</h4> |
| <div class="flex flex-wrap gap-2"> |
| ${vendor.coverage.map(cov => ` |
| <span class="px-3 py-1 bg-emerald-100 text-emerald-800 rounded-full text-sm">${cov}</span> |
| `).join('')} |
| </div> |
| |
| <h4 class="font-bold text-lg mt-4 mb-3">Integrations</h4> |
| <div class="flex flex-wrap gap-2"> |
| ${vendor.integrations.map(int => ` |
| <span class="px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm">${int}</span> |
| `).join('')} |
| </div> |
| |
| <div class="mt-4 p-4 bg-gray-50 rounded-lg"> |
| <p class="font-medium">Pricing: <span class="text-gray-700">${vendor.pricing}</span></p> |
| <p class="font-medium mt-2">Free Trial: <span class="text-gray-700">${vendor.freeTrial ? 'Yes' : 'No'}</span></p> |
| </div> |
| </div> |
| </div> |
| `; |
| |
| feather.replace(); |
| vendorModal.classList.remove('hidden'); |
| } |
|
|
| |
| function renderComparisonTable() { |
| const selected = vendors.filter(v => selectedVendors.includes(v.id)); |
| |
| if (selected.length < 2) { |
| comparisonBody.innerHTML = '<tr><td colspan="100%" class="text-center py-4">Please select at least 2 vendors to compare</td></tr>'; |
| return; |
| } |
| |
| |
| comparisonBody.innerHTML = ''; |
| |
| |
| const headerRow = document.querySelector('#comparison thead tr'); |
| headerRow.innerHTML = '<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Feature</th>'; |
| |
| selected.forEach(vendor => { |
| headerRow.innerHTML += ` |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |
| <div class="flex items-center"> |
| <img src="${vendor.logo}" alt="${vendor.name}" class="w-8 h-8 rounded-full mr-2"> |
| ${vendor.name} |
| </div> |
| </th> |
| `; |
| }); |
| |
| |
| const categories = [ |
| { name: 'Features', key: 'features', type: 'list' }, |
| { name: 'Coverage', key: 'coverage', type: 'list' }, |
| { name: 'Integrations', key: 'integrations', type: 'list' }, |
| { name: 'Pricing Model', key: 'pricing', type: 'text' }, |
| { name: 'Free Trial', key: 'freeTrial', type: 'boolean' }, |
| { name: 'Rating', key: 'rating', type: 'rating' } |
| ]; |
| |
| |
| categories.forEach(category => { |
| const row = document.createElement('tr'); |
| row.innerHTML = `<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${category.name}</td>`; |
| |
| selected.forEach(vendor => { |
| const value = vendor[category.key]; |
| |
| let cellContent = ''; |
| if (category.type === 'list') { |
| cellContent = value.map(item => ` |
| <span class="inline-block bg-gray-100 rounded-full px-3 py-1 text-sm font-medium text-gray-700 mr-1 mb-1"> |
| ${item} |
| </span> |
| `).join(''); |
| } else if (category.type === 'boolean') { |
| cellContent = value ? |
| '<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">Yes</span>' : |
| '<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">No</span>'; |
| } else if (category.type === 'rating') { |
| cellContent = ` |
| <div class="flex items-center"> |
| <div class="flex text-yellow-400 mr-2"> |
| ${renderStars(value)} |
| </div> |
| <span class="text-gray-600">${value}</span> |
| </div> |
| `; |
| } else { |
| cellContent = `<span class="text-gray-700">${value}</span>`; |
| } |
| |
| row.innerHTML += `<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${cellContent}</td>`; |
| }); |
| |
| comparisonBody.appendChild(row); |
| }); |
| |
| feather.replace(); |
| } |