Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Crypto Trends Dashboard</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script> | |
<style> | |
.gradient-bg { | |
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); | |
} | |
.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); | |
} | |
.trend-up { | |
color: #10b981; | |
} | |
.trend-down { | |
color: #ef4444; | |
} | |
.pulse { | |
animation: pulse 2s infinite; | |
} | |
@keyframes pulse { | |
0% { | |
opacity: 1; | |
} | |
50% { | |
opacity: 0.5; | |
} | |
100% { | |
opacity: 1; | |
} | |
} | |
</style> | |
</head> | |
<body class="gradient-bg min-h-screen text-white"> | |
<div class="container mx-auto px-4 py-8"> | |
<header class="text-center mb-12"> | |
<h1 class="text-4xl font-bold mb-2">Crypto Trends Dashboard</h1> | |
<p class="text-xl opacity-75">Top & Bottom Performers (24h) with 1-Year Trends</p> | |
<div class="mt-6 flex justify-center"> | |
<div class="relative"> | |
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
<i class="fas fa-search text-gray-400"></i> | |
</div> | |
<input id="searchInput" type="text" class="bg-gray-800 text-white rounded-full py-2 pl-10 pr-4 focus:outline-none focus:ring-2 focus:ring-blue-500 w-64" placeholder="Search crypto..."> | |
</div> | |
</div> | |
</header> | |
<div class="mb-8 flex justify-between items-center"> | |
<h2 class="text-2xl font-semibold">Market Overview</h2> | |
<div class="flex items-center space-x-4"> | |
<span id="lastUpdated" class="text-sm opacity-75">Loading data...</span> | |
<button id="refreshBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-full flex items-center transition"> | |
<i class="fas fa-sync-alt mr-2"></i> Refresh | |
</button> | |
</div> | |
</div> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-12"> | |
<div class="bg-gray-800 bg-opacity-50 rounded-xl p-6 shadow-lg"> | |
<h3 class="text-xl font-semibold mb-4 flex items-center"> | |
<i class="fas fa-arrow-up mr-2 text-green-400"></i> Top 10 Gainers (24h) | |
</h3> | |
<div id="topGainers" class="space-y-4"> | |
<div class="flex justify-center items-center py-12"> | |
<div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div> | |
</div> | |
</div> | |
</div> | |
<div class="bg-gray-800 bg-opacity-50 rounded-xl p-6 shadow-lg"> | |
<h3 class="text-xl font-semibold mb-4 flex items-center"> | |
<i class="fas fa-arrow-down mr-2 text-red-400"></i> Bottom 10 Losers (24h) | |
</h3> | |
<div id="bottomLosers" class="space-y-4"> | |
<div class="flex justify-center items-center py-12"> | |
<div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div id="trendModal" class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden"> | |
<div class="bg-gray-900 rounded-xl p-6 max-w-4xl w-full mx-4 max-h-screen overflow-y-auto"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 id="modalTitle" class="text-2xl font-bold"></h3> | |
<button id="closeModal" class="text-gray-400 hover:text-white"> | |
<i class="fas fa-times text-2xl"></i> | |
</button> | |
</div> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6"> | |
<div> | |
<h4 class="text-lg font-semibold mb-2">Current Price</h4> | |
<p id="modalPrice" class="text-3xl font-bold"></p> | |
</div> | |
<div> | |
<h4 class="text-lg font-semibold mb-2">24h Change</h4> | |
<p id="modalChange" class="text-3xl font-bold"></p> | |
</div> | |
</div> | |
<div class="h-96"> | |
<canvas id="trendChart"></canvas> | |
</div> | |
<div class="mt-6 grid grid-cols-2 md:grid-cols-4 gap-4"> | |
<div class="bg-gray-800 p-4 rounded-lg"> | |
<p class="text-sm opacity-75">Market Cap</p> | |
<p id="modalMarketCap" class="font-semibold"></p> | |
</div> | |
<div class="bg-gray-800 p-4 rounded-lg"> | |
<p class="text-sm opacity-75">Volume (24h)</p> | |
<p id="modalVolume" class="font-semibold"></p> | |
</div> | |
<div class="bg-gray-800 p-4 rounded-lg"> | |
<p class="text-sm opacity-75">ATH</p> | |
<p id="modalATH" class="font-semibold"></p> | |
</div> | |
<div class="bg-gray-800 p-4 rounded-lg"> | |
<p class="text-sm opacity-75">Circulating Supply</p> | |
<p id="modalSupply" class="font-semibold"></p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
// Sample data - in a real app, you would fetch this from an API | |
const cryptoData = [ | |
{ | |
id: "bitcoin", | |
name: "Bitcoin", | |
symbol: "BTC", | |
current_price: 42000, | |
price_change_percentage_24h: 5.2, | |
market_cap: 800000000000, | |
total_volume: 25000000000, | |
ath: 69000, | |
circulating_supply: 19400000, | |
sparkline: Array.from({length: 365}, (_, i) => 30000 + Math.random() * 15000 - i * 50) | |
}, | |
{ | |
id: "ethereum", | |
name: "Ethereum", | |
symbol: "ETH", | |
current_price: 2500, | |
price_change_percentage_24h: 4.8, | |
market_cap: 300000000000, | |
total_volume: 15000000000, | |
ath: 4800, | |
circulating_supply: 120000000, | |
sparkline: Array.from({length: 365}, (_, i) => 1800 + Math.random() * 1000 - i * 30) | |
}, | |
{ | |
id: "solana", | |
name: "Solana", | |
symbol: "SOL", | |
current_price: 120, | |
price_change_percentage_24h: 8.5, | |
market_cap: 50000000000, | |
total_volume: 3000000000, | |
ath: 260, | |
circulating_supply: 420000000, | |
sparkline: Array.from({length: 365}, (_, i) => 80 + Math.random() * 50 - i * 5) | |
}, | |
{ | |
id: "cardano", | |
name: "Cardano", | |
symbol: "ADA", | |
current_price: 0.6, | |
price_change_percentage_24h: 6.3, | |
market_cap: 21000000000, | |
total_volume: 1000000000, | |
ath: 3.10, | |
circulating_supply: 35000000000, | |
sparkline: Array.from({length: 365}, (_, i) => 0.4 + Math.random() * 0.3 - i * 0.01) | |
}, | |
{ | |
id: "ripple", | |
name: "XRP", | |
symbol: "XRP", | |
current_price: 0.55, | |
price_change_percentage_24h: 3.9, | |
market_cap: 28000000000, | |
total_volume: 2000000000, | |
ath: 3.40, | |
circulating_supply: 50000000000, | |
sparkline: Array.from({length: 365}, (_, i) => 0.35 + Math.random() * 0.25 - i * 0.005) | |
}, | |
{ | |
id: "polkadot", | |
name: "Polkadot", | |
symbol: "DOT", | |
current_price: 7.2, | |
price_change_percentage_24h: 7.1, | |
market_cap: 8500000000, | |
total_volume: 500000000, | |
ath: 55, | |
circulating_supply: 1200000000, | |
sparkline: Array.from({length: 365}, (_, i) => 5 + Math.random() * 3 - i * 0.2) | |
}, | |
{ | |
id: "dogecoin", | |
name: "Dogecoin", | |
symbol: "DOGE", | |
current_price: 0.09, | |
price_change_percentage_24h: 4.2, | |
market_cap: 12000000000, | |
total_volume: 800000000, | |
ath: 0.73, | |
circulating_supply: 132000000000, | |
sparkline: Array.from({length: 365}, (_, i) => 0.06 + Math.random() * 0.04 - i * 0.001) | |
}, | |
{ | |
id: "avalanche", | |
name: "Avalanche", | |
symbol: "AVAX", | |
current_price: 35, | |
price_change_percentage_24h: 9.8, | |
market_cap: 13000000000, | |
total_volume: 900000000, | |
ath: 144, | |
circulating_supply: 370000000, | |
sparkline: Array.from({length: 365}, (_, i) => 22 + Math.random() * 15 - i * 0.5) | |
}, | |
{ | |
id: "chainlink", | |
name: "Chainlink", | |
symbol: "LINK", | |
current_price: 18, | |
price_change_percentage_24h: 6.7, | |
market_cap: 10000000000, | |
total_volume: 700000000, | |
ath: 52, | |
circulating_supply: 550000000, | |
sparkline: Array.from({length: 365}, (_, i) => 12 + Math.random() * 8 - i * 0.3) | |
}, | |
{ | |
id: "polygon", | |
name: "Polygon", | |
symbol: "MATIC", | |
current_price: 0.85, | |
price_change_percentage_24h: 5.9, | |
market_cap: 8000000000, | |
total_volume: 600000000, | |
ath: 2.92, | |
circulating_supply: 9300000000, | |
sparkline: Array.from({length: 365}, (_, i) => 0.6 + Math.random() * 0.4 - i * 0.01) | |
}, | |
{ | |
id: "terra", | |
name: "Terra Classic", | |
symbol: "LUNC", | |
current_price: 0.00012, | |
price_change_percentage_24h: -8.5, | |
market_cap: 700000000, | |
total_volume: 50000000, | |
ath: 119, | |
circulating_supply: 5800000000000, | |
sparkline: Array.from({length: 365}, (_, i) => 0.0005 - Math.random() * 0.0004 - i * 0.00001) | |
}, | |
{ | |
id: "ftx-token", | |
name: "FTX Token", | |
symbol: "FTT", | |
current_price: 1.2, | |
price_change_percentage_24h: -7.2, | |
market_cap: 400000000, | |
total_volume: 30000000, | |
ath: 84, | |
circulating_supply: 330000000, | |
sparkline: Array.from({length: 365}, (_, i) => 5 - Math.random() * 4 - i * 0.1) | |
}, | |
{ | |
id: "celsius", | |
name: "Celsius", | |
symbol: "CEL", | |
current_price: 0.15, | |
price_change_percentage_24h: -6.8, | |
market_cap: 350000000, | |
total_volume: 20000000, | |
ath: 8, | |
circulating_supply: 2300000000, | |
sparkline: Array.from({length: 365}, (_, i) => 0.5 - Math.random() * 0.4 - i * 0.01) | |
}, | |
{ | |
id: "voyager", | |
name: "Voyager Token", | |
symbol: "VGX", | |
current_price: 0.08, | |
price_change_percentage_24h: -5.9, | |
market_cap: 220000000, | |
total_volume: 15000000, | |
ath: 12, | |
circulating_supply: 2800000000, | |
sparkline: Array.from({length: 365}, (_, i) => 0.3 - Math.random() * 0.25 - i * 0.005) | |
}, | |
{ | |
id: "helium", | |
name: "Helium", | |
symbol: "HNT", | |
current_price: 2.5, | |
price_change_percentage_24h: -4.7, | |
market_cap: 330000000, | |
total_volume: 25000000, | |
ath: 55, | |
circulating_supply: 130000000, | |
sparkline: Array.from({length: 365}, (_, i) => 8 - Math.random() * 6 - i * 0.2) | |
}, | |
{ | |
id: "arweave", | |
name: "Arweave", | |
symbol: "AR", | |
current_price: 9, | |
price_change_percentage_24h: -3.8, | |
market_cap: 600000000, | |
total_volume: 40000000, | |
ath: 89, | |
circulating_supply: 66000000, | |
sparkline: Array.from({length: 365}, (_, i) => 30 - Math.random() * 22 - i * 0.7) | |
}, | |
{ | |
id: "axie-infinity", | |
name: "Axie Infinity", | |
symbol: "AXS", | |
current_price: 7.5, | |
price_change_percentage_24h: -4.2, | |
market_cap: 900000000, | |
total_volume: 70000000, | |
ath: 165, | |
circulating_supply: 120000000, | |
sparkline: Array.from({length: 365}, (_, i) => 25 - Math.random() * 18 - i * 0.6) | |
}, | |
{ | |
id: "stepn", | |
name: "STEPN", | |
symbol: "GMT", | |
current_price: 0.25, | |
price_change_percentage_24h: -5.1, | |
market_cap: 400000000, | |
total_volume: 30000000, | |
ath: 4, | |
circulating_supply: 1600000000, | |
sparkline: Array.from({length: 365}, (_, i) => 0.8 - Math.random() * 0.6 - i * 0.02) | |
}, | |
{ | |
id: "luna", | |
name: "Terra", | |
symbol: "LUNA", | |
current_price: 0.8, | |
price_change_percentage_24h: -6.3, | |
market_cap: 500000000, | |
total_volume: 35000000, | |
ath: 120, | |
circulating_supply: 600000000, | |
sparkline: Array.from({length: 365}, (_, i) => 3 - Math.random() * 2.5 - i * 0.08) | |
} | |
]; | |
// Sort by 24h change | |
const sortedBy24hChange = [...cryptoData].sort((a, b) => b.price_change_percentage_24h - a.price_change_percentage_24h); | |
const top10 = sortedBy24hChange.slice(0, 10); | |
const bottom10 = sortedBy24hChange.slice(-10).reverse(); | |
// Format numbers | |
function formatNumber(num) { | |
if (num >= 1000000000) { | |
return '$' + (num / 1000000000).toFixed(2) + 'B'; | |
} | |
if (num >= 1000000) { | |
return '$' + (num / 1000000).toFixed(2) + 'M'; | |
} | |
if (num >= 1000) { | |
return '$' + (num / 1000).toFixed(2) + 'K'; | |
} | |
return '$' + num.toFixed(2); | |
} | |
function formatLargeNumber(num) { | |
if (num >= 1000000000000) { | |
return (num / 1000000000000).toFixed(2) + 'T'; | |
} | |
if (num >= 1000000000) { | |
return (num / 1000000000).toFixed(2) + 'B'; | |
} | |
if (num >= 1000000) { | |
return (num / 1000000).toFixed(2) + 'M'; | |
} | |
if (num >= 1000) { | |
return (num / 1000).toFixed(2) + 'K'; | |
} | |
return num.toFixed(2); | |
} | |
// Render crypto cards | |
function renderCryptoCards(containerId, cryptos) { | |
const container = document.getElementById(containerId); | |
container.innerHTML = ''; | |
cryptos.forEach(crypto => { | |
const isPositive = crypto.price_change_percentage_24h >= 0; | |
const changeClass = isPositive ? 'trend-up' : 'trend-down'; | |
const changeIcon = isPositive ? 'fa-arrow-up' : 'fa-arrow-down'; | |
const card = document.createElement('div'); | |
card.className = 'bg-gray-800 bg-opacity-70 rounded-xl p-4 flex items-center justify-between transition cursor-pointer hover:bg-opacity-90 card-hover'; | |
card.innerHTML = ` | |
<div class="flex items-center"> | |
<div class="bg-gray-700 rounded-full w-10 h-10 flex items-center justify-center mr-4"> | |
<span class="font-semibold">${crypto.symbol}</span> | |
</div> | |
<div> | |
<h4 class="font-semibold">${crypto.name}</h4> | |
<p class="text-sm opacity-75">${crypto.symbol}</p> | |
</div> | |
</div> | |
<div class="text-right"> | |
<p class="font-bold">${formatNumber(crypto.current_price)}</p> | |
<p class="${changeClass}"> | |
<i class="fas ${changeIcon} mr-1"></i> | |
${Math.abs(crypto.price_change_percentage_24h).toFixed(2)}% | |
</p> | |
</div> | |
`; | |
card.addEventListener('click', () => openTrendModal(crypto)); | |
container.appendChild(card); | |
}); | |
} | |
// Open trend modal | |
let trendChart = null; | |
function openTrendModal(crypto) { | |
const modal = document.getElementById('trendModal'); | |
const isPositive = crypto.price_change_percentage_24h >= 0; | |
const changeClass = isPositive ? 'trend-up' : 'trend-down'; | |
document.getElementById('modalTitle').textContent = `${crypto.name} (${crypto.symbol})`; | |
document.getElementById('modalPrice').textContent = formatNumber(crypto.current_price); | |
document.getElementById('modalChange').className = `text-3xl font-bold ${changeClass}`; | |
document.getElementById('modalChange').innerHTML = ` | |
${isPositive ? '+' : ''}${crypto.price_change_percentage_24h.toFixed(2)}% | |
<i class="fas ${isPositive ? 'fa-arrow-up' : 'fa-arrow-down'} ml-1"></i> | |
`; | |
document.getElementById('modalMarketCap').textContent = formatNumber(crypto.market_cap); | |
document.getElementById('modalVolume').textContent = formatNumber(crypto.total_volume); | |
document.getElementById('modalATH').textContent = formatNumber(crypto.ath); | |
document.getElementById('modalSupply').textContent = formatLargeNumber(crypto.circulating_supply) + ' ' + crypto.symbol; | |
// Create chart | |
const ctx = document.getElementById('trendChart').getContext('2d'); | |
if (trendChart) { | |
trendChart.destroy(); | |
} | |
const chartColor = isPositive ? 'rgba(16, 185, 129, 0.8)' : 'rgba(239, 68, 68, 0.8)'; | |
const bgColor = isPositive ? 'rgba(16, 185, 129, 0.2)' : 'rgba(239, 68, 68, 0.2)'; | |
trendChart = new Chart(ctx, { | |
type: 'line', | |
data: { | |
labels: Array.from({length: 12}, (_, i) => { | |
const date = new Date(); | |
date.setMonth(date.getMonth() - (11 - i)); | |
return date.toLocaleString('default', {month: 'short'}); | |
}), | |
datasets: [{ | |
label: 'Price', | |
data: crypto.sparkline.filter((_, i) => i % 30 === 0), // Show monthly points | |
borderColor: chartColor, | |
backgroundColor: bgColor, | |
borderWidth: 2, | |
fill: true, | |
tension: 0.4, | |
pointRadius: 0 | |
}] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
plugins: { | |
legend: { | |
display: false | |
}, | |
tooltip: { | |
mode: 'index', | |
intersect: false, | |
callbacks: { | |
label: function(context) { | |
return `${crypto.symbol}: ${formatNumber(context.raw)}`; | |
} | |
} | |
} | |
}, | |
scales: { | |
x: { | |
grid: { | |
display: false | |
}, | |
ticks: { | |
color: 'rgba(255, 255, 255, 0.7)' | |
} | |
}, | |
y: { | |
grid: { | |
color: 'rgba(255, 255, 255, 0.1)' | |
}, | |
ticks: { | |
color: 'rgba(255, 255, 255, 0.7)', | |
callback: function(value) { | |
return formatNumber(value); | |
} | |
} | |
} | |
} | |
} | |
}); | |
modal.classList.remove('hidden'); | |
} | |
// Close modal | |
document.getElementById('closeModal').addEventListener('click', () => { | |
document.getElementById('trendModal').classList.add('hidden'); | |
}); | |
// Refresh data | |
document.getElementById('refreshBtn').addEventListener('click', () => { | |
const btn = document.getElementById('refreshBtn'); | |
btn.innerHTML = '<i class="fas fa-sync-alt animate-spin mr-2"></i> Refreshing'; | |
btn.disabled = true; | |
// Simulate API call delay | |
setTimeout(() => { | |
renderCryptoCards('topGainers', top10); | |
renderCryptoCards('bottomLosers', bottom10); | |
updateLastUpdated(); | |
btn.innerHTML = '<i class="fas fa-sync-alt mr-2"></i> Refresh'; | |
btn.disabled = false; | |
}, 1000); | |
}); | |
// Search functionality | |
document.getElementById('searchInput').addEventListener('input', (e) => { | |
const searchTerm = e.target.value.toLowerCase(); | |
if (searchTerm.length > 0) { | |
const filteredTop = top10.filter(c => | |
c.name.toLowerCase().includes(searchTerm) || | |
c.symbol.toLowerCase().includes(searchTerm) | |
); | |
const filteredBottom = bottom10.filter(c => | |
c.name.toLowerCase().includes(searchTerm) || | |
c.symbol.toLowerCase().includes(searchTerm) | |
); | |
renderCryptoCards('topGainers', filteredTop); | |
renderCryptoCards('bottomLosers', filteredBottom); | |
} else { | |
renderCryptoCards('topGainers', top10); | |
renderCryptoCards('bottomLosers', bottom10); | |
} | |
}); | |
// Update last updated time | |
function updateLastUpdated() { | |
const now = new Date(); | |
document.getElementById('lastUpdated').textContent = `Last updated: ${now.toLocaleTimeString()}`; | |
} | |
// Initialize | |
document.addEventListener('DOMContentLoaded', () => { | |
renderCryptoCards('topGainers', top10); | |
renderCryptoCards('bottomLosers', bottom10); | |
updateLastUpdated(); | |
}); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=myelemes/my-dooooos" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |