Really-amin's picture
Update INDEX.html
b5dc8a3 verified
raw
history blame
22.6 kB
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🚀 داشبورد هوشمند کریپتو</title>
<link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary: #667eea;
--secondary: #764ba2;
--success: #10b981;
--danger: #ef4444;
--warning: #f59e0b;
--dark: #1e293b;
--light: #f8fafc;
}
body {
font-family: 'Vazirmatn', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
/* Header */
.header {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border-radius: 20px;
padding: 30px;
margin-bottom: 30px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}
.header-title {
font-size: 32px;
font-weight: 800;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 15px;
}
.status-badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: rgba(16, 185, 129, 0.2);
border-radius: 20px;
font-size: 14px;
}
.status-dot {
width: 10px;
height: 10px;
background: var(--success);
border-radius: 50%;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
/* Stats Grid */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border-radius: 15px;
padding: 25px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}
.stat-label {
font-size: 14px;
opacity: 0.8;
margin-bottom: 10px;
}
.stat-value {
font-size: 32px;
font-weight: 800;
margin-bottom: 10px;
}
.stat-change {
font-size: 14px;
font-weight: 600;
}
.stat-change.positive { color: var(--success); }
.stat-change.negative { color: var(--danger); }
/* Tabs */
.tabs {
display: flex;
gap: 10px;
margin-bottom: 30px;
flex-wrap: wrap;
}
.tab-btn {
padding: 12px 24px;
background: rgba(255, 255, 255, 0.1);
border: none;
border-radius: 12px;
color: white;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
.tab-btn:hover {
background: rgba(255, 255, 255, 0.2);
}
.tab-btn.active {
background: rgba(255, 255, 255, 0.3);
}
/* Content Sections */
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
/* Card Grid */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.coin-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border-radius: 15px;
padding: 20px;
cursor: pointer;
transition: all 0.3s;
}
.coin-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3);
}
.coin-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.coin-symbol {
font-size: 24px;
font-weight: 800;
}
.coin-rank {
background: rgba(255, 255, 255, 0.2);
padding: 4px 12px;
border-radius: 10px;
font-size: 12px;
}
.coin-price {
font-size: 28px;
font-weight: 800;
margin-bottom: 10px;
}
.coin-change {
font-size: 16px;
font-weight: 600;
}
/* News Card */
.news-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border-radius: 15px;
padding: 20px;
cursor: pointer;
transition: all 0.3s;
}
.news-card:hover {
background: rgba(255, 255, 255, 0.15);
}
.news-title {
font-size: 18px;
font-weight: 700;
margin-bottom: 10px;
}
.news-meta {
display: flex;
justify-content: space-between;
font-size: 14px;
opacity: 0.8;
}
/* Sentiment Gauge */
.sentiment-container {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border-radius: 20px;
padding: 30px;
text-align: center;
}
.sentiment-value {
font-size: 64px;
font-weight: 900;
margin: 20px 0;
}
.sentiment-label {
font-size: 24px;
font-weight: 700;
margin-bottom: 20px;
}
.gauge {
width: 100%;
height: 40px;
background: linear-gradient(to right, #ef4444, #f59e0b, #10b981);
border-radius: 20px;
position: relative;
margin: 30px 0;
}
.gauge-pointer {
position: absolute;
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
top: 10px;
transform: translateX(-50%);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
/* Chart Container */
.chart-container {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border-radius: 20px;
padding: 30px;
margin-top: 30px;
}
.chart-title {
font-size: 20px;
font-weight: 700;
margin-bottom: 20px;
}
/* Loading */
.loading {
text-align: center;
padding: 40px;
font-size: 18px;
}
/* Responsive */
@media (max-width: 768px) {
.stats-grid {
grid-template-columns: 1fr;
}
.card-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<div class="header">
<div class="header-title">
<span>🚀</span>
<span>داشبورد هوشمند کریپتو</span>
<span class="status-badge">
<span class="status-dot"></span>
آنلاین
</span>
</div>
</div>
<!-- Market Stats -->
<div class="stats-grid" id="marketStats">
<div class="stat-card">
<div class="stat-label">کل ارزش بازار</div>
<div class="stat-value" id="totalMarketCap">$0</div>
<div class="stat-change positive" id="marketCapChange">+0%</div>
</div>
<div class="stat-card">
<div class="stat-label">حجم معاملات 24 ساعت</div>
<div class="stat-value" id="totalVolume">$0</div>
</div>
<div class="stat-card">
<div class="stat-label">تسلط بیت‌کوین</div>
<div class="stat-value" id="btcDominance">0%</div>
</div>
<div class="stat-card">
<div class="stat-label">تعداد ارزها</div>
<div class="stat-value" id="activeCryptos">0</div>
</div>
</div>
<!-- Tabs -->
<div class="tabs">
<button class="tab-btn active" onclick="switchTab('trending')">🔥 ترندها</button>
<button class="tab-btn" onclick="switchTab('top')">💎 برترین‌ها</button>
<button class="tab-btn" onclick="switchTab('news')">📰 اخبار</button>
<button class="tab-btn" onclick="switchTab('sentiment')">📊 احساسات</button>
<button class="tab-btn" onclick="switchTab('blockchain')">⛓️ بلاکچین</button>
</div>
<!-- Trending Tab -->
<div id="trending" class="tab-content active">
<h2 style="margin-bottom: 20px;">🔥 ارزهای ترند</h2>
<div class="card-grid" id="trendingGrid">
<div class="loading">در حال بارگذاری...</div>
</div>
</div>
<!-- Top Coins Tab -->
<div id="top" class="tab-content">
<h2 style="margin-bottom: 20px;">💎 برترین ارزها</h2>
<div class="card-grid" id="topGrid">
<div class="loading">در حال بارگذاری...</div>
</div>
</div>
<!-- News Tab -->
<div id="news" class="tab-content">
<h2 style="margin-bottom: 20px;">📰 آخرین اخبار</h2>
<div class="card-grid" id="newsGrid">
<div class="loading">در حال بارگذاری...</div>
</div>
</div>
<!-- Sentiment Tab -->
<div id="sentiment" class="tab-content">
<h2 style="margin-bottom: 20px;">📊 احساسات بازار</h2>
<div class="sentiment-container">
<div class="sentiment-label">شاخص ترس و طمع</div>
<div class="sentiment-value" id="sentimentValue">50</div>
<div class="sentiment-label" id="sentimentLabel">خنثی</div>
<div class="gauge">
<div class="gauge-pointer" id="gaugePointer" style="left: 50%;"></div>
</div>
</div>
<div class="chart-container">
<div class="chart-title">تاریخچه 7 روز اخیر</div>
<canvas id="sentimentChart" height="100"></canvas>
</div>
</div>
<!-- Blockchain Tab -->
<div id="blockchain" class="tab-content">
<h2 style="margin-bottom: 20px;">⛓️ آمار بلاکچین</h2>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">قیمت گس اتریوم</div>
<div class="stat-value" id="ethGas">0 Gwei</div>
</div>
<div class="stat-card">
<div class="stat-label">آخرین بلاک اتریوم</div>
<div class="stat-value" id="ethBlock">0</div>
</div>
<div class="stat-card">
<div class="stat-label">قیمت گس BSC</div>
<div class="stat-value" id="bscGas">0 Gwei</div>
</div>
<div class="stat-card">
<div class="stat-label">آخرین بلاک BSC</div>
<div class="stat-value" id="bscBlock">0</div>
</div>
</div>
</div>
</div>
<script>
let currentTab = 'trending';
// Switch tabs
function switchTab(tabName) {
currentTab = tabName;
// Update active tab button
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.classList.remove('active');
});
event.target.classList.add('active');
// Update active content
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
document.getElementById(tabName).classList.add('active');
// Load data for the tab
loadTabData(tabName);
}
// Load tab data
async function loadTabData(tabName) {
switch(tabName) {
case 'trending':
await loadTrending();
break;
case 'top':
await loadTopCoins();
break;
case 'news':
await loadNews();
break;
case 'sentiment':
await loadSentiment();
break;
case 'blockchain':
await loadBlockchain();
break;
}
}
// Load market overview
async function loadMarketOverview() {
try {
const response = await fetch('/api/crypto/market-overview');
const data = await response.json();
document.getElementById('totalMarketCap').textContent = formatCurrency(data.total_market_cap);
document.getElementById('totalVolume').textContent = formatCurrency(data.total_volume_24h);
document.getElementById('btcDominance').textContent = data.btc_dominance.toFixed(1) + '%';
document.getElementById('activeCryptos').textContent = data.active_cryptocurrencies.toLocaleString();
const changeElement = document.getElementById('marketCapChange');
const change = data.market_cap_change_24h;
changeElement.textContent = (change > 0 ? '+' : '') + change.toFixed(2) + '%';
changeElement.className = 'stat-change ' + (change > 0 ? 'positive' : 'negative');
} catch (error) {
console.error('Error loading market overview:', error);
}
}
// Load trending coins
async function loadTrending() {
try {
const response = await fetch('/api/crypto/prices/trending?limit=12');
const coins = await response.json();
const grid = document.getElementById('trendingGrid');
grid.innerHTML = coins.map(coin => createCoinCard(coin)).join('');
} catch (error) {
console.error('Error loading trending:', error);
}
}
// Load top coins
async function loadTopCoins() {
try {
const response = await fetch('/api/crypto/prices/top?limit=20');
const coins = await response.json();
const grid = document.getElementById('topGrid');
grid.innerHTML = coins.map(coin => createCoinCard(coin)).join('');
} catch (error) {
console.error('Error loading top coins:', error);
}
}
// Load news
async function loadNews() {
try {
const response = await fetch('/api/crypto/news/latest?limit=12');
const news = await response.json();
const grid = document.getElementById('newsGrid');
grid.innerHTML = news.map(article => `
<div class="news-card" onclick="window.open('${article.url}', '_blank')">
<div class="news-title">${article.title}</div>
<div class="news-meta">
<span>${article.source}</span>
<span>${formatTime(article.published_at)}</span>
</div>
</div>
`).join('');
} catch (error) {
console.error('Error loading news:', error);
}
}
// Load sentiment
async function loadSentiment() {
try {
const [current, history] = await Promise.all([
fetch('/api/crypto/sentiment/current').then(r => r.json()),
fetch('/api/crypto/sentiment/history?hours=168').then(r => r.json())
]);
// Update current sentiment
document.getElementById('sentimentValue').textContent = current.fear_greed_index;
document.getElementById('sentimentLabel').textContent = current.classification;
// Update gauge pointer
const pointer = document.getElementById('gaugePointer');
pointer.style.left = current.fear_greed_index + '%';
// Update chart
if (history.history && history.history.length > 0) {
updateSentimentChart(history.history);
}
} catch (error) {
console.error('Error loading sentiment:', error);
}
}
// Load blockchain stats
async function loadBlockchain() {
try {
const [gas, stats] = await Promise.all([
fetch('/api/crypto/blockchain/gas').then(r => r.json()),
fetch('/api/crypto/blockchain/stats').then(r => r.json())
]);
document.getElementById('ethGas').textContent = gas.ethereum.gas_price_gwei + ' Gwei';
document.getElementById('ethBlock').textContent = stats.ethereum.latest_block.toLocaleString();
document.getElementById('bscGas').textContent = gas.bsc.gas_price_gwei + ' Gwei';
document.getElementById('bscBlock').textContent = stats.bsc.latest_block.toLocaleString();
} catch (error) {
console.error('Error loading blockchain:', error);
}
}
// Create coin card HTML
function createCoinCard(coin) {
const changeClass = coin.price_change_24h >= 0 ? 'positive' : 'negative';
const changeSymbol = coin.price_change_24h >= 0 ? '+' : '';
return `
<div class="coin-card">
<div class="coin-header">
<div class="coin-symbol">${coin.symbol}</div>
<div class="coin-rank">#${coin.rank}</div>
</div>
<div style="font-size: 14px; opacity: 0.8; margin-bottom: 10px;">${coin.name}</div>
<div class="coin-price">$${formatNumber(coin.price)}</div>
<div class="coin-change ${changeClass}">
${changeSymbol}${coin.price_change_24h.toFixed(2)}%
</div>
</div>
`;
}
// Update sentiment chart
function updateSentimentChart(data) {
const ctx = document.getElementById('sentimentChart');
new Chart(ctx, {
type: 'line',
data: {
labels: data.map(d => new Date(d.timestamp).toLocaleDateString('fa-IR')),
datasets: [{
label: 'شاخص ترس و طمع',
data: data.map(d => d.value),
borderColor: 'rgba(255, 255, 255, 0.8)',
backgroundColor: 'rgba(255, 255, 255, 0.1)',
tension: 0.4,
fill: true,
borderWidth: 3
}]
},
options: {
responsive: true,
plugins: {
legend: { display: false }
},
scales: {
y: {
beginAtZero: true,
max: 100,
ticks: { color: 'rgba(255, 255, 255, 0.8)' },
grid: { color: 'rgba(255, 255, 255, 0.1)' }
},
x: {
ticks: { color: 'rgba(255, 255, 255, 0.8)' },
grid: { color: 'rgba(255, 255, 255, 0.1)' }
}
}
}
});
}
// Helper functions
function formatNumber(num) {
if (num >= 1e9) return (num / 1e9).toFixed(2) + 'B';
if (num >= 1e6) return (num / 1e6).toFixed(2) + 'M';
if (num >= 1e3) return (num / 1e3).toFixed(2) + 'K';
return num.toFixed(2);
}
function formatCurrency(num) {
return '$' + formatNumber(num);
}
function formatTime(timestamp) {
const date = new Date(timestamp);
const now = new Date();
const diff = Math.floor((now - date) / 1000);
if (diff < 60) return 'همین الان';
if (diff < 3600) return Math.floor(diff / 60) + ' دقیقه پیش';
if (diff < 86400) return Math.floor(diff / 3600) + ' ساعت پیش';
return Math.floor(diff / 86400) + ' روز پیش';
}
// Initialize
document.addEventListener('DOMContentLoaded', () => {
loadMarketOverview();
loadTrending();
// Auto refresh every 30 seconds
setInterval(() => {
loadMarketOverview();
loadTabData(currentTab);
}, 30000);
});
</script>
</body>
</html>