| <!DOCTYPE html> |
| <html lang="en" class="dark"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>EventScrape Analytics Hub</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://d3js.org/d3.v7.min.js"></script> |
| <script src="https://cdn.jsdelivr.net/npm/@tsparticles/confetti@3.0.3/tsparticles.confetti.bundle.min.js"></script> |
| <link href="https://cdn.jsdelivr.net/npm/8bitcn-ui@latest/dist/8bitcn-ui.css" rel="stylesheet"> |
| <script src="https://cdn.jsdelivr.net/npm/8bitcn-ui@latest/dist/8bitcn-ui.js"></script> |
| <style> |
| .world-map { |
| width: 100%; |
| height: 600px; |
| background: #000; |
| border: 4px solid #00ff00; |
| image-rendering: pixelated; |
| position: relative; |
| overflow: hidden; |
| } |
| |
| .pixel-map { |
| image-rendering: pixelated; |
| background: #000; |
| } |
| |
| .map-grid { |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| background-image: |
| linear-gradient(#00ff00 1px, transparent 1px), |
| linear-gradient(90deg, #00ff00 1px, transparent 1px); |
| background-size: 20px 20px; |
| opacity: 0.3; |
| pointer-events: none; |
| } |
| |
| .country-pixel { |
| fill: #000; |
| stroke: #00ff00; |
| stroke-width: 2px; |
| image-rendering: pixelated; |
| transition: all 0.2s; |
| } |
| |
| .country-pixel:hover { |
| stroke: #ffff00; |
| stroke-width: 3px; |
| filter: drop-shadow(0 0 4px #ffff00); |
| } |
| |
| .heat-1 { fill: #004400; } |
| .heat-2 { fill: #008800; } |
| .heat-3 { fill: #00cc00; } |
| .heat-4 { fill: #00ff00; } |
| .heat-5 { fill: #88ff00; } |
| .heat-6 { fill: #ffff00; } |
| .heat-7 { fill: #ff8800; } |
| .heat-8 { fill: #ff0000; } |
| |
| .map-legend { |
| position: absolute; |
| bottom: 10px; |
| right: 10px; |
| background: #000; |
| border: 3px solid #00ff00; |
| padding: 8px; |
| image-rendering: pixelated; |
| } |
| |
| .legend-item { |
| display: flex; |
| align-items: center; |
| margin: 4px 0; |
| font-family: 'Courier New', monospace; |
| font-size: 12px; |
| } |
| |
| .legend-color { |
| width: 16px; |
| height: 16px; |
| margin-right: 8px; |
| border: 1px solid #00ff00; |
| image-rendering: pixelated; |
| } |
| |
| .map-tooltip { |
| position: absolute; |
| background: #000; |
| border: 3px solid #ffff00; |
| padding: 8px; |
| font-family: 'Courier New', monospace; |
| font-size: 12px; |
| image-rendering: pixelated; |
| pointer-events: none; |
| opacity: 0; |
| transition: opacity 0.2s; |
| z-index: 100; |
| } |
| |
| .pulse-dot { |
| animation: pixel-pulse 1.5s infinite; |
| image-rendering: pixelated; |
| } |
| |
| @keyframes pixel-pulse { |
| 0% { transform: scale(1); opacity: 1; } |
| 50% { transform: scale(1.3); opacity: 0.7; } |
| 100% { transform: scale(1); opacity: 1; } |
| } |
| .pulse-ring { |
| animation: pulse 1s infinite; |
| image-rendering: pixelated; |
| } |
| |
| @keyframes pulse { |
| 0% { transform: scale(0.8); opacity: 1; } |
| 50% { transform: scale(1.2); opacity: 0.7; } |
| 100% { transform: scale(0.8); opacity: 1; } |
| } |
| |
| .ticker-item { |
| animation: ticker-scroll 20s linear infinite; |
| font-family: 'Courier New', monospace; |
| } |
| |
| @keyframes ticker-scroll { |
| 0% { transform: translateX(100%); } |
| 100% { transform: translateX(-100%); } |
| } |
| |
| .pixel-border { |
| border: 4px solid #00ff00; |
| border-image: repeating-linear-gradient(45deg, #00ff00, #00ff00 4px, #000 4px, #000 8px) 4; |
| image-rendering: pixelated; |
| } |
| |
| .pixel-bg { |
| background: #000; |
| border: 2px solid #00ff00; |
| image-rendering: pixelated; |
| } |
| |
| .pixel-text { |
| font-family: 'Courier New', monospace; |
| text-shadow: 2px 2px 0 #000; |
| letter-spacing: 1px; |
| } |
| |
| .pixel-button { |
| background: #000; |
| border: 3px solid #00ff00; |
| font-family: 'Courier New', monospace; |
| text-shadow: 1px 1px 0 #000; |
| image-rendering: pixelated; |
| transition: all 0.1s; |
| } |
| |
| .pixel-button:hover { |
| background: #00ff00; |
| color: #000; |
| transform: translateY(-2px); |
| box-shadow: 0 4px 0 #008800; |
| } |
| |
| .pixel-button:active { |
| transform: translateY(0); |
| box-shadow: 0 2px 0 #008800; |
| } |
| |
| .pixel-card { |
| background: #000; |
| border: 4px solid #00ff00; |
| box-shadow: 8px 8px 0 #008800; |
| image-rendering: pixelated; |
| } |
| |
| .pixel-nav { |
| background: #000; |
| border-right: 4px solid #00ff00; |
| border-bottom: 4px solid #00ff00; |
| image-rendering: pixelated; |
| } |
| |
| .pixel-checkbox { |
| appearance: none; |
| width: 20px; |
| height: 20px; |
| border: 2px solid #00ff00; |
| background: #000; |
| image-rendering: pixelated; |
| } |
| |
| .pixel-checkbox:checked { |
| background: #00ff00; |
| box-shadow: inset 0 0 0 2px #000; |
| } |
| |
| .pixel-badge { |
| font-family: 'Courier New', monospace; |
| border: 2px solid; |
| padding: 2px 8px; |
| font-size: 12px; |
| image-rendering: pixelated; |
| } |
| |
| body { |
| font-family: 'Courier New', monospace; |
| background: #000 !important; |
| color: #00ff00 !important; |
| image-rendering: pixelated; |
| } |
| |
| .dark body { |
| background: #000 !important; |
| color: #00ff00 !important; |
| } |
| </style> |
| </head> |
| <body class="bg-black text-green-400 transition-colors duration-300 pixel-text"> |
| |
| <div class="fixed top-4 right-4 z-50"> |
| <button id="themeToggle" class="p-3 pixel-button"> |
| <i data-feather="moon" class="hidden dark:block"></i> |
| <i data-feather="sun" class="dark:hidden"></i> |
| </button> |
| </div> |
| |
| <div class="min-h-screen flex"> |
| |
| <aside class="w-64 pixel-nav p-6 fixed h-screen z-40"> |
| <div class="flex items-center space-x-3 mb-8"> |
| <div class="w-10 h-10 bg-green-500 pixel-border flex items-center justify-center"> |
| <i data-feather="activity" class="text-black"></i> |
| </div> |
| <h1 class="text-xl font-bold pixel-text">EVENT_SCRAPE</h1> |
| </div> |
| |
| <nav class="space-y-2"> |
| <a href="#" class="flex items-center space-x-3 p-3 pixel-bg bg-green-500 text-black"> |
| <i data-feather="home"></i> |
| <span>DASHBOARD</span> |
| </a> |
| <a href="#" class="flex items-center space-x-3 p-3 pixel-bg hover:bg-green-500 hover:text-black"> |
| <i data-feather="compass"></i> |
| <span>SCRAPE_RUNS</span> |
| </a> |
| <a href="#" class="flex items-center space-x-3 p-3 pixel-bg hover:bg-green-500 hover:text-black"> |
| <i data-feather="database"></i> |
| <span>DATA_MGMT</span> |
| </a> |
| <a href="#" class="flex items-center space-x-3 p-3 pixel-bg hover:bg-green-500 hover:text-black"> |
| <i data-feather="bar-chart-2"></i> |
| <span>ANALYTICS</span> |
| </a> |
| <a href="#" class="flex items-center space-x-3 p-3 pixel-bg hover:bg-green-500 hover:text-black"> |
| <i data-feather="settings"></i> |
| <span>SETTINGS</span> |
| </a> |
| </nav> |
| |
| |
| <div class="mt-8"> |
| <h3 class="font-semibold mb-4 pixel-text">MAP_LAYERS</h3> |
| <div class="space-y-2"> |
| <label class="flex items-center space-x-3"> |
| <input type="checkbox" checked class="pixel-checkbox" data-layer="events"> |
| <span class="pixel-text">EVENT_COUNT</span> |
| </label> |
| <label class="flex items-center space-x-3"> |
| <input type="checkbox" class="pixel-checkbox" data-layer="music"> |
| <span class="pixel-text">MUSIC_STYLES</span> |
| </label> |
| <label class="flex items-center space-x-3"> |
| <input type="checkbox" class="pixel-checkbox" data-layer="capacity"> |
| <span class="pixel-text">VENUE_CAPACITY</span> |
| </label> |
| </div> |
| </div> |
| </aside> |
| |
| <main class="flex-1 ml-64 p-6"> |
| |
| <header class="mb-8"> |
| <div class="pixel-card p-4 mb-4 overflow-hidden"> |
| <div class="flex items-center space-x-4"> |
| <i data-feather="alert-circle" class="text-red-400"></i> |
| <div class="flex-1 overflow-hidden"> |
| <div class="ticker-container whitespace-nowrap"> |
| <div class="ticker-item inline-block px-4"> |
| [ALERT] HIGH_LATENCY_NORTH_AMERICA • |
| </div> |
| <div class="ticker-item inline-block px-4"> |
| [OK] PLUGIN_v2.3.1_DEPLOYED • |
| </div> |
| <div class="ticker-item inline-block px-4"> |
| [SYNC] REAL_TIME_ACTIVE_ALL_REGIONS • |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </header> |
| |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8"> |
| |
| <div class="glass-effect rounded-xl p-6 relative overflow-hidden"> |
| <div class="absolute top-0 right-0 w-20 h-20 bg-blue-500/10 rounded-full -mr-4 -mt-4"></div> |
| <div class="flex items-center justify-between mb-4"> |
| <h3 class="text-lg font-semibold">Events Scraped</h3> |
| <i data-feather="calendar" class="text-blue-500"></i> |
| </div> |
| <div class="text-3xl font-bold mb-2" id="eventsCounter">2,847,392</div> |
| <div class="text-sm text-green-500 flex items-center"> |
| <i data-feather="trending-up" class="w-4 h-4 mr-1"></i> |
| +12.4% this week |
| </div> |
| </div> |
|
|
| |
| <div class="glass-effect rounded-xl p-6 relative overflow-hidden"> |
| <div class="absolute top-0 right-0 w-20 h-20 bg-purple-500/10 rounded-full -mr-4 -mt-4"></div> |
| <div class="flex items-center justify-between mb-4"> |
| <h3 class="text-lg font-semibold">Plugins Built</h3> |
| <i data-feather="package" class="text-purple-500"></i> |
| </div> |
| <div class="text-3xl font-bold mb-2" id="pluginsCounter">1,284</div> |
| <div class="text-sm text-green-500 flex items-center"> |
| <i data-feather="trending-up" class="w-4 h-4 mr-1"></i> |
| +3 new today |
| </div> |
| </div> |
|
|
| |
| <div class="glass-effect rounded-xl p-6"> |
| <div class="flex items-center justify-between mb-4"> |
| <h3 class="text-lg font-semibold">Cities Covered</h3> |
| <i data-feather="map-pin" class="text-green-500"></i> |
| </div> |
| <div class="text-3xl font-bold mb-2">842</div> |
| <div class="text-sm text-slate-600 dark:text-slate-400">Across 64 countries</div> |
| </div> |
|
|
| |
| <div class="glass-effect rounded-xl p-6"> |
| <div class="flex items-center justify-between mb-4"> |
| <h3 class="text-lg font-semibold">Active Scrapers</h3> |
| <i data-feather="cpu" class="text-orange-500"></i> |
| </div> |
| <div class="text-3xl font-bold mb-2">47</div> |
| <div class="text-sm text-slate-600 dark:text-slate-400">98.3% uptime</div> |
| </div> |
| </div> |
| |
| <div class="pixel-card p-6 mb-8"> |
| <div class="flex items-center justify-between mb-6"> |
| <h2 class="text-xl font-bold pixel-text">GLOBAL_EVENT_HEAT_MAP</h2> |
| <div class="flex space-x-2"> |
| <button class="pixel-button"> |
| <i data-feather="download" class="w-4 h-4 mr-2"></i> |
| EXPORT |
| </button> |
| <button class="pixel-button"> |
| <i data-feather="refresh-cw" class="w-4 h-4 mr-2"></i> |
| REFRESH |
| </button> |
| </div> |
| </div> |
| <div id="worldMap" class="world-map"> |
| <div class="map-grid"></div> |
| <svg id="pixelMap" class="pixel-map" width="100%" height="100%"></svg> |
| <div id="mapTooltip" class="map-tooltip"></div> |
| <div class="map-legend"> |
| <div class="legend-item"> |
| <div class="legend-color heat-1"></div> |
| <span>0-100K</span> |
| </div> |
| <div class="legend-item"> |
| <div class="legend-color heat-3"></div> |
| <span>100K-500K</span> |
| </div> |
| <div class="legend-item"> |
| <div class="legend-color heat-5"></div> |
| <span>500K-1M</span> |
| </div> |
| <div class="legend-item"> |
| <div class="legend-color heat-7"></div> |
| <span>1M+</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-8"> |
| |
| <div class="glass-effect rounded-xl p-6"> |
| <h3 class="text-lg font-bold mb-4">Recent Scrape Runs</h3> |
| <div class="space-y-4"> |
| <div class="flex items-center justify-between p-3 rounded-lg bg-slate-100/50 dark:bg-slate-800/50"> |
| <div class="flex items-center space-x-3"> |
| <div class="w-3 h-3 bg-green-500 rounded-full pulse-ring"></div> |
| <span>North America</span> |
| </div> |
| <div class="text-sm">Quality: 94%</div> |
| </div> |
| <div class="flex items-center justify-between p-3 rounded-lg bg-slate-100/50 dark:bg-slate-800/50"> |
| <div class="flex items-center space-x-3"> |
| <div class="w-3 h-3 bg-yellow-500 rounded-full"></div> |
| <span>Europe</span> |
| </div> |
| <div class="text-sm">Quality: 87%</div> |
| </div> |
| <div class="flex items-center justify-between p-3 rounded-lg bg-slate-100/50 dark:bg-slate-800/50"> |
| <div class="flex items-center space-x-3"> |
| <div class="w-3 h-3 bg-red-500 rounded-full"></div> |
| <span>Asia Pacific</span> |
| </div> |
| <div class="text-sm">Quality: 72%</div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="glass-effect rounded-xl p-6"> |
| <h3 class="text-lg font-bold mb-4">Events by Type</h3> |
| <div class="space-y-3"> |
| <div class="flex items-center justify-between"> |
| <span>Music Concerts</span> |
| <span class="font-semibold">784,239</span> |
| </div> |
| <div class="flex items-center justify-between"> |
| <span>Sports Events</span> |
| <span class="font-semibold">492,184</span> |
| </div> |
| <div class="flex items-center justify-between"> |
| <span>Festivals</span> |
| <span class="font-semibold">318,752</span> |
| </div> |
| <div class="flex items-center justify-between"> |
| <span>Theater & Arts</span> |
| <span class="font-semibold">275,491</span> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <footer class="mt-12 pt-8 border-t border-slate-200 dark:border-slate-700"> |
| <div class="flex flex-col md:flex-row justify-between items-center"> |
| <div class="text-sm text-slate-600 dark:text-slate-400"> |
| © 2024 EventScrape Analytics Hub. All rights reserved. |
| </div> |
| <div class="flex space-x-6 mt-4 md:mt-0"> |
| <span class="text-sm">Last sync: 2 minutes ago</span> |
| <span class="text-sm">Data freshness: 99.8%</span> |
| <span class="text-sm">System status: Operational</span> |
| </div> |
| </div> |
| </footer> |
| </main> |
| </div> |
|
|
| <script> |
| |
| document.getElementById('themeToggle').addEventListener('click', function() { |
| document.documentElement.classList.toggle('dark'); |
| feather.replace(); |
| }); |
| |
| |
| function simulateWebSocketUpdates() { |
| |
| let events = 2847392; |
| setInterval(() => { |
| events += Math.floor(Math.random() * 100); |
| document.getElementById('eventsCounter').textContent = events.toLocaleString(); |
| }, 2000); |
| |
| |
| let plugins = 1284; |
| setInterval(() => { |
| plugins += Math.random() > 0.7 ? 1 : 0; |
| document.getElementById('pluginsCounter').textContent = plugins.toLocaleString(); |
| }, 5000); |
| } |
| |
| function initWorldMap() { |
| const svg = d3.select("#pixelMap"); |
| const tooltip = d3.select("#mapTooltip"); |
| |
| |
| const projection = d3.geoMercator() |
| .scale(120) |
| .translate([400, 300]); |
| |
| const path = d3.geoPath().projection(projection); |
| |
| |
| const sampleData = { |
| "USA": { events: 842000, music: "Rock", capacity: 2850000, cities: 245 }, |
| "GBR": { events: 467000, music: "Pop", capacity: 1280000, cities: 89 }, |
| "DEU": { events: 328000, music: "Electronic", capacity: 920000, cities: 76 }, |
| "FRA": { events: 291000, music: "Hip Hop", capacity: 780000, cities: 68 }, |
| "JPN": { events: 218000, music: "J-Pop", capacity: 640000, cities: 52 }, |
| "CAN": { events: 187000, music: "Indie", capacity: 520000, cities: 45 }, |
| "AUS": { events: 156000, music: "Rock", capacity: 410000, cities: 38 }, |
| "BRA": { events: 134000, music: "Samba", capacity: 380000, cities: 41 }, |
| "ITA": { events: 123000, music: "Opera", capacity: 320000, cities: 35 }, |
| "ESP": { events: 118000, music: "Flamenco", capacity: 290000, cities: 32 } |
| }; |
| |
| |
| function getHeatLevel(events) { |
| if (events > 1000000) return 8; |
| if (events > 800000) return 7; |
| if (events > 600000) return 6; |
| if (events > 400000) return 5; |
| if (events > 200000) return 4; |
| if (events > 100000) return 3; |
| if (events > 50000) return 2; |
| return 1; |
| } |
| |
| |
| const simplifiedWorld = { |
| type: "FeatureCollection", |
| features: [ |
| |
| { type: "Feature", geometry: { type: "Polygon", coordinates: [[[-130, 25], [-130, 50], [-65, 50], [-65, 25], [-130, 25]]] }, properties: { name: "North America", id: "USA" }}, |
| |
| { type: "Feature", geometry: { type: "Polygon", coordinates: [[[-10, 35], [-10, 60], [40, 60], [40, 35], [-10, 35]]] }, properties: { name: "Europe", id: "EUR" }}, |
| |
| { type: "Feature", geometry: { type: "Polygon", coordinates: [[[60, 10], [60, 60], [140, 60], [140, 10], [60, 10]]] }, properties: { name: "Asia", id: "ASIA" }}, |
| |
| { type: "Feature", geometry: { type: "Polygon", coordinates: [[[-80, -55], [-80, 15], [-35, 15], [-35, -55], [-80, -55]]] }, properties: { name: "South America", id: "SAM" }}, |
| |
| { type: "Feature", geometry: { type: "Polygon", coordinates: [[[-20, -35], [-20, 35], [50, 35], [50, -35], [-20, -35]]] }, properties: { name: "Africa", id: "AFR" }}, |
| |
| { type: "Feature", geometry: { type: "Polygon", coordinates: [[[110, -45], [110, -10], [155, -10], [155, -45], [110, -45]]] }, properties: { name: "Australia", id: "AUS" }} |
| ] |
| }; |
| |
| |
| svg.selectAll("path") |
| .data(simplifiedWorld.features) |
| .enter() |
| .append("path") |
| .attr("d", path) |
| .attr("class", "country-pixel") |
| .attr("fill", function(d) { |
| const countryData = sampleData[d.properties.id]; |
| if (countryData) { |
| const heatLevel = getHeatLevel(countryData.events); |
| return `var(--heat-${heatLevel})`; |
| } |
| return "#000"; |
| }) |
| .on("mouseover", function(event, d) { |
| const countryData = sampleData[d.properties.id]; |
| if (countryData) { |
| tooltip |
| .style("opacity", 1) |
| .html(` |
| <div class="font-bold">${d.properties.name}</div> |
| <div>Events: ${countryData.events.toLocaleString()}</div> |
| <div>Top Genre: ${countryData.music}</div> |
| <div>Cities: ${countryData.cities}</div> |
| <div>Capacity: ${countryData.capacity.toLocaleString()}</div> |
| `) |
| .style("left", (event.pageX + 10) + "px") |
| .style("top", (event.pageY - 10) + "px"); |
| } |
| |
| d3.select(this) |
| .style("filter", "drop-shadow(0 0 6px #ffff00)"); |
| }) |
| .on("mousemove", function(event) { |
| tooltip |
| .style("left", (event.pageX + 10) + "px") |
| .style("top", (event.pageY - 10) + "px"); |
| }) |
| .on("mouseout", function() { |
| tooltip.style("opacity", 0); |
| d3.select(this) |
| .style("filter", "none"); |
| }); |
| |
| |
| const majorCities = [ |
| { name: "New York", coords: [-74, 40.7], events: 284000 }, |
| { name: "London", coords: [-0.1, 51.5], events: 198000 }, |
| { name: "Tokyo", coords: [139.7, 35.7], events: 167000 }, |
| { name: "Berlin", coords: [13.4, 52.5], events: 142000 }, |
| { name: "Paris", coords: [2.3, 48.9], events: 128000 }, |
| { name: "Sydney", coords: [151.2, -33.9], events: 98000 }, |
| { name: "São Paulo", coords: [-46.6, -23.6], events: 87000 } |
| ]; |
| |
| svg.selectAll("circle") |
| .data(majorCities) |
| .enter() |
| .append("circle") |
| .attr("cx", d => projection(d.coords)[0]) |
| .attr("cy", d => projection(d.coords)[1]) |
| .attr("r", 4) |
| .attr("class", "pulse-dot") |
| .attr("fill", "#ffff00") |
| .attr("stroke", "#000") |
| .attr("stroke-width", 1); |
| } |
| </body> |
| </html> |