crypto-trafic / index.html
bourahima's picture
Add 1 files
bad22a3 verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Crypto Tracker Pro - Analyse des cryptomonnaies</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.gradient-bg {
background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%);
}
.coin-card: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);
}
.dark-mode {
background-color: #1a202c;
color: #f7fafc;
}
.dark-mode .header {
background-color: #2d3748;
}
.dark-mode .coin-card {
background-color: #2d3748;
border-color: #4a5568;
}
.chart-container {
position: relative;
height: 200px;
width: 100%;
}
.trend-indicator {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
}
.trend-up {
background-color: rgba(16, 185, 129, 0.1);
color: #10b981;
}
.trend-down {
background-color: rgba(239, 68, 68, 0.1);
color: #ef4444;
}
.trend-neutral {
background-color: rgba(156, 163, 175, 0.1);
color: #9ca3af;
}
</style>
</head>
<body class="bg-gray-100 font-sans">
<div class="min-h-screen">
<!-- Header -->
<header class="gradient-bg text-white shadow-lg">
<div class="container mx-auto px-4 py-6">
<div class="flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fab fa-bitcoin text-3xl text-yellow-400"></i>
<h1 class="text-2xl font-bold">Crypto Tracker Pro</h1>
</div>
<div class="flex items-center space-x-4">
<button id="refreshBtn" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded-lg flex items-center">
<i class="fas fa-sync-alt mr-2"></i> Actualiser
</button>
<button id="darkModeToggle" class="bg-gray-800 hover:bg-gray-700 px-4 py-2 rounded-lg">
<i class="fas fa-moon"></i>
</button>
</div>
</div>
<div class="mt-8">
<div class="flex flex-col md:flex-row justify-between items-center">
<div>
<h2 class="text-xl font-semibold">Analyse technique des cryptomonnaies</h2>
<p class="text-blue-200">Tendances, moyennes mobiles et indicateurs techniques</p>
</div>
<div class="mt-4 md:mt-0 relative">
<input type="text" id="searchInput" placeholder="Rechercher une crypto..."
class="px-4 py-2 rounded-full w-full md:w-64 focus:outline-none focus:ring-2 focus:ring-blue-400 text-gray-800">
<i class="fas fa-search absolute right-3 top-3 text-gray-500"></i>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="container mx-auto px-4 py-8">
<!-- Market Overview -->
<div class="bg-white rounded-xl shadow-md p-6 mb-8 dark-mode">
<h2 class="text-xl font-bold mb-4">Indicateurs du marché</h2>
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<div class="bg-blue-50 p-4 rounded-lg dark:bg-gray-700">
<div class="flex justify-between items-center">
<div>
<p class="text-gray-600 dark:text-gray-300">Capitalisation totale</p>
<h3 id="totalMarketCap" class="text-2xl font-bold">Chargement...</h3>
<p id="marketCapChange" class="text-sm mt-1">Chargement...</p>
</div>
<i class="fas fa-chart-line text-blue-500 text-3xl"></i>
</div>
</div>
<div class="bg-green-50 p-4 rounded-lg dark:bg-gray-700">
<div class="flex justify-between items-center">
<div>
<p class="text-gray-600 dark:text-gray-300">Volume 24h</p>
<h3 id="totalVolume" class="text-2xl font-bold">Chargement...</h3>
<p id="volumeChange" class="text-sm mt-1">Chargement...</p>
</div>
<i class="fas fa-exchange-alt text-green-500 text-3xl"></i>
</div>
</div>
<div class="bg-purple-50 p-4 rounded-lg dark:bg-gray-700">
<div class="flex justify-between items-center">
<div>
<p class="text-gray-600 dark:text-gray-300">Dominance BTC</p>
<h3 id="btcDominance" class="text-2xl font-bold">Chargement...</h3>
<p id="btcDominanceChange" class="text-sm mt-1">Chargement...</p>
</div>
<i class="fab fa-bitcoin text-purple-500 text-3xl"></i>
</div>
</div>
<div class="bg-yellow-50 p-4 rounded-lg dark:bg-gray-700">
<div class="flex justify-between items-center">
<div>
<p class="text-gray-600 dark:text-gray-300">Indice de peur et avidité</p>
<h3 id="fearGreed" class="text-2xl font-bold">Chargement...</h3>
<p id="fearGreedText" class="text-sm mt-1">Chargement...</p>
</div>
<i class="fas fa-brain text-yellow-500 text-3xl"></i>
</div>
</div>
</div>
</div>
<!-- Crypto List -->
<div class="mb-8">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold">Analyse des cryptomonnaies</h2>
<div class="flex space-x-2">
<button id="sortMarketCap" class="bg-blue-500 text-white px-3 py-1 rounded text-sm">
Par capitalisation
</button>
<button id="sortVolume" class="bg-gray-200 hover:bg-gray-300 px-3 py-1 rounded text-sm dark:bg-gray-700 dark:hover:bg-gray-600">
Par volume
</button>
<button id="sortChange" class="bg-gray-200 hover:bg-gray-300 px-3 py-1 rounded text-sm dark:bg-gray-700 dark:hover:bg-gray-600">
Par variation
</button>
<button id="sortTrend" class="bg-gray-200 hover:bg-gray-300 px-3 py-1 rounded text-sm dark:bg-gray-700 dark:hover:bg-gray-600">
Par tendance
</button>
</div>
</div>
<div id="cryptoList" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Les cartes de cryptomonnaies seront ajoutées ici par JavaScript -->
<div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
<div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
<div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
</div>
</div>
<!-- Favorites Section -->
<div id="favoritesSection" class="mb-8 hidden">
<h2 class="text-xl font-bold mb-4">Vos favoris</h2>
<div id="favoritesList" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Les favoris seront ajoutés ici -->
</div>
</div>
<!-- Loading Indicator -->
<div id="loadingIndicator" class="text-center py-8">
<i class="fas fa-circle-notch fa-spin text-4xl text-blue-500"></i>
<p class="mt-4">Chargement des données...</p>
</div>
</main>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-6">
<div class="container mx-auto px-4">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="mb-4 md:mb-0">
<p>&copy; 2023 Crypto Tracker Pro. Tous droits réservés.</p>
<p class="text-gray-400 text-sm">Données fournies par CoinGecko API et TradingView</p>
</div>
<div class="flex space-x-4">
<a href="#" class="hover:text-blue-300"><i class="fab fa-twitter"></i></a>
<a href="#" class="hover:text-blue-300"><i class="fab fa-github"></i></a>
<a href="#" class="hover:text-blue-300"><i class="fab fa-telegram"></i></a>
</div>
</div>
</div>
</footer>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Configuration
const apiUrl = 'https://api.coingecko.com/api/v3';
const favoritesKey = 'cryptoFavorites';
// Éléments DOM
const cryptoList = document.getElementById('cryptoList');
const favoritesList = document.getElementById('favoritesList');
const favoritesSection = document.getElementById('favoritesSection');
const loadingIndicator = document.getElementById('loadingIndicator');
const refreshBtn = document.getElementById('refreshBtn');
const darkModeToggle = document.getElementById('darkModeToggle');
const searchInput = document.getElementById('searchInput');
const totalMarketCap = document.getElementById('totalMarketCap');
const totalVolume = document.getElementById('totalVolume');
const btcDominance = document.getElementById('btcDominance');
const marketCapChange = document.getElementById('marketCapChange');
const volumeChange = document.getElementById('volumeChange');
const btcDominanceChange = document.getElementById('btcDominanceChange');
const fearGreed = document.getElementById('fearGreed');
const fearGreedText = document.getElementById('fearGreedText');
const sortMarketCap = document.getElementById('sortMarketCap');
const sortVolume = document.getElementById('sortVolume');
const sortChange = document.getElementById('sortChange');
const sortTrend = document.getElementById('sortTrend');
// Variables d'état
let cryptoData = [];
let favorites = JSON.parse(localStorage.getItem(favoritesKey)) || [];
let currentSort = 'market_cap';
let isDarkMode = localStorage.getItem('darkMode') === 'true';
let previousGlobalData = null;
// Initialisation
if (isDarkMode) {
document.body.classList.add('dark-mode');
darkModeToggle.innerHTML = '<i class="fas fa-sun"></i>';
}
fetchData();
// Événements
refreshBtn.addEventListener('click', fetchData);
darkModeToggle.addEventListener('click', toggleDarkMode);
searchInput.addEventListener('input', filterCryptos);
sortMarketCap.addEventListener('click', () => sortCryptos('market_cap'));
sortVolume.addEventListener('click', () => sortCryptos('volume'));
sortChange.addEventListener('click', () => sortCryptos('price_change_percentage_24h'));
sortTrend.addEventListener('click', () => sortCryptos('trend_strength'));
// Fonctions
async function fetchData() {
try {
loadingIndicator.classList.remove('hidden');
cryptoList.innerHTML = `
<div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
<div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
<div class="animate-pulse bg-gray-200 rounded-xl p-6 h-96 dark:bg-gray-700"></div>
`;
// Récupérer les données globales
const globalResponse = await fetch(`${apiUrl}/global`);
const globalData = await globalResponse.json();
updateGlobalData(globalData.data);
// Récupérer l'indice de peur et avidité (simulé)
updateFearGreedIndex();
// Récupérer les cryptomonnaies avec les données de prix historiques
const response = await fetch(`${apiUrl}/coins/markets?vs_currency=eur&order=market_cap_desc&per_page=30&page=1&sparkline=true&price_change_percentage=24h,7d,30d`);
cryptoData = await response.json();
// Ajouter des données techniques simulées (moyennes mobiles et tendances)
cryptoData = await enhanceWithTechnicalData(cryptoData);
renderCryptoList(cryptoData);
updateFavoritesSection();
} catch (error) {
console.error('Erreur lors de la récupération des données:', error);
cryptoList.innerHTML = `
<div class="col-span-3 bg-red-100 border-l-4 border-red-500 text-red-700 p-4">
<p>Erreur lors du chargement des données. Veuillez réessayer.</p>
</div>
`;
} finally {
loadingIndicator.classList.add('hidden');
}
}
async function enhanceWithTechnicalData(cryptoData) {
// Simuler des données techniques pour chaque crypto
return cryptoData.map(crypto => {
// Générer des moyennes mobiles simulées (7 et 30 jours)
const currentPrice = crypto.current_price;
const volatility = currentPrice * 0.1; // 10% de volatilité
// Générer des données de prix historiques simulées si sparkline n'est pas disponible
const sparklineData = crypto.sparkline_in_7d?.price || Array(7).fill(0).map((_, i) => {
const daysAgo = 7 - i;
const trendFactor = crypto.price_change_percentage_7d_in_currency / 100;
return currentPrice * (1 - trendFactor * (daysAgo / 7) + (Math.random() * 0.1 - 0.05));
});
// Calculer les moyennes mobiles
const ma7 = calculateMovingAverage(sparklineData.slice(-7));
const ma30 = calculateMovingAverage(sparklineData);
// Déterminer la tendance
const trendStrength = calculateTrendStrength(sparklineData);
const trendDirection = trendStrength > 0.5 ? 'up' : trendStrength < -0.5 ? 'down' : 'neutral';
return {
...crypto,
technicals: {
ma7,
ma30,
trend_strength: trendStrength,
trend_direction: trendDirection,
sparkline: sparklineData
}
};
});
}
function calculateMovingAverage(data) {
if (!data || data.length === 0) return 0;
const sum = data.reduce((a, b) => a + b, 0);
return sum / data.length;
}
function calculateTrendStrength(data) {
if (!data || data.length < 2) return 0;
const first = data[0];
const last = data[data.length - 1];
const change = last - first;
const range = Math.max(...data) - Math.min(...data);
if (range === 0) return 0;
return change / range; // Retourne une valeur entre -1 et 1
}
function updateGlobalData(data) {
totalMarketCap.textContent = formatCurrency(data.total_market_cap.eur);
totalVolume.textContent = formatCurrency(data.total_volume.eur);
btcDominance.textContent = `${data.market_cap_percentage.btc.toFixed(1)}%`;
// Calculer les variations si nous avons des données précédentes
if (previousGlobalData) {
const marketCapChangeValue = ((data.total_market_cap.eur - previousGlobalData.total_market_cap.eur) / previousGlobalData.total_market_cap.eur) * 100;
const volumeChangeValue = ((data.total_volume.eur - previousGlobalData.total_volume.eur) / previousGlobalData.total_volume.eur) * 100;
const btcDominanceChangeValue = data.market_cap_percentage.btc - previousGlobalData.market_cap_percentage.btc;
marketCapChange.innerHTML = formatChange(marketCapChangeValue);
volumeChange.innerHTML = formatChange(volumeChangeValue);
btcDominanceChange.innerHTML = formatChange(btcDominanceChangeValue, true);
}
previousGlobalData = data;
}
function updateFearGreedIndex() {
// Simuler l'indice de peur et avidité (0-100)
const index = Math.floor(Math.random() * 100);
fearGreed.textContent = index;
let text = "";
let colorClass = "";
if (index >= 75) {
text = "Extrême avidité";
colorClass = "text-red-500";
} else if (index >= 55) {
text = "Avidité";
colorClass = "text-yellow-500";
} else if (index >= 45) {
text = "Neutre";
colorClass = "text-gray-500";
} else if (index >= 25) {
text = "Peur";
colorClass = "text-blue-500";
} else {
text = "Extrême peur";
colorClass = "text-green-500";
}
fearGreed.className = `text-2xl font-bold ${colorClass}`;
fearGreedText.innerHTML = `<span class="${colorClass}">${text}</span>`;
}
function renderCryptoList(data) {
cryptoList.innerHTML = '';
if (data.length === 0) {
cryptoList.innerHTML = `
<div class="col-span-3 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4">
<p>Aucune cryptomonnaie ne correspond à votre recherche.</p>
</div>
`;
return;
}
data.forEach(crypto => {
const isFavorite = favorites.includes(crypto.id);
const priceChange = crypto.price_change_percentage_24h;
const changeClass = priceChange >= 0 ? 'text-green-500' : 'text-red-500';
const changeIcon = priceChange >= 0 ? 'fa-arrow-up' : 'fa-arrow-down';
// Données techniques
const ma7 = crypto.technicals?.ma7 || 0;
const ma30 = crypto.technicals?.ma30 || 0;
const trendDirection = crypto.technicals?.trend_direction || 'neutral';
const trendStrength = crypto.technicals?.trend_strength || 0;
const sparklineData = crypto.technicals?.sparkline || [];
// Créer un canvas pour le graphique
const canvasId = `chart-${crypto.id}`;
const card = document.createElement('div');
card.className = 'coin-card bg-white rounded-xl shadow-md p-6 transition-all duration-300 dark-mode';
card.innerHTML = `
<div class="flex justify-between items-start mb-4">
<div class="flex items-center">
<img src="${crypto.image}" alt="${crypto.name}" class="w-10 h-10 mr-3">
<div>
<h3 class="font-bold">${crypto.name}</h3>
<p class="text-gray-500 text-sm">${crypto.symbol.toUpperCase()}</p>
</div>
</div>
<div class="flex items-center">
<span class="trend-indicator trend-${trendDirection} mr-2">
${trendDirection === 'up' ? '↑' : trendDirection === 'down' ? '↓' : '→'}
${Math.abs(trendStrength * 100).toFixed(0)}%
</span>
<button class="favorite-btn text-${isFavorite ? 'yellow' : 'gray'}-400 hover:text-yellow-500 focus:outline-none" data-id="${crypto.id}">
<i class="fas fa-star"></i>
</button>
</div>
</div>
<div class="chart-container mb-4">
<canvas id="${canvasId}"></canvas>
</div>
<div class="flex justify-between items-end mb-2">
<div>
<p class="text-gray-500 text-sm">Prix</p>
<p class="text-xl font-bold">${formatCurrency(crypto.current_price)}</p>
</div>
<div class="text-right">
<p class="text-gray-500 text-sm">24h</p>
<p class="${changeClass} font-semibold">
<i class="fas ${changeIcon} mr-1"></i>
${Math.abs(priceChange).toFixed(2)}%
</p>
</div>
</div>
<div class="grid grid-cols-2 gap-2 text-sm mb-2">
<div>
<p class="text-gray-500">MA7</p>
<p class="${crypto.current_price > ma7 ? 'text-green-500' : 'text-red-500'}">
${formatCurrency(ma7)}
</p>
</div>
<div class="text-right">
<p class="text-gray-500">MA30</p>
<p class="${crypto.current_price > ma30 ? 'text-green-500' : 'text-red-500'}">
${formatCurrency(ma30)}
</p>
</div>
</div>
<div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
<div class="flex justify-between text-sm">
<div>
<p class="text-gray-500">Capitalisation</p>
<p>${formatCurrency(crypto.market_cap)}</p>
</div>
<div class="text-right">
<p class="text-gray-500">Volume</p>
<p>${formatCurrency(crypto.total_volume)}</p>
</div>
</div>
</div>
`;
cryptoList.appendChild(card);
// Rendre le graphique après que l'élément a été ajouté au DOM
setTimeout(() => {
renderSparklineChart(canvasId, sparklineData, crypto.current_price, ma7, ma30);
}, 100);
});
// Ajouter les événements aux boutons favoris
document.querySelectorAll('.favorite-btn').forEach(btn => {
btn.addEventListener('click', function() {
const cryptoId = this.getAttribute('data-id');
toggleFavorite(cryptoId);
});
});
}
function renderSparklineChart(canvasId, sparklineData, currentPrice, ma7, ma30) {
const ctx = document.getElementById(canvasId).getContext('2d');
const chartColor = isDarkMode ? '#3b82f6' : '#2563eb';
const bgColor = isDarkMode ? 'rgba(59, 130, 246, 0.1)' : 'rgba(37, 99, 235, 0.1)';
// Préparer les données pour le graphique
const labels = Array(sparklineData.length).fill('');
const ma7Data = Array(sparklineData.length).fill(ma7);
const ma30Data = Array(sparklineData.length).fill(ma30);
new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [
{
label: 'Prix',
data: sparklineData,
borderColor: chartColor,
backgroundColor: bgColor,
borderWidth: 2,
fill: true,
tension: 0.4
},
{
label: 'MA7',
data: ma7Data,
borderColor: '#10b981',
borderWidth: 1,
borderDash: [5, 5],
pointRadius: 0,
tension: 0
},
{
label: 'MA30',
data: ma30Data,
borderColor: '#8b5cf6',
borderWidth: 1,
borderDash: [5, 5],
pointRadius: 0,
tension: 0
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
tooltip: {
enabled: false
}
},
scales: {
x: {
display: false
},
y: {
display: false,
suggestedMin: Math.min(...sparklineData) * 0.95,
suggestedMax: Math.max(...sparklineData) * 1.05
}
},
elements: {
point: {
radius: 0
}
}
}
});
}
function toggleFavorite(cryptoId) {
const index = favorites.indexOf(cryptoId);
if (index === -1) {
favorites.push(cryptoId);
} else {
favorites.splice(index, 1);
}
localStorage.setItem(favoritesKey, JSON.stringify(favorites));
renderCryptoList(cryptoData);
updateFavoritesSection();
}
function updateFavoritesSection() {
if (favorites.length === 0) {
favoritesSection.classList.add('hidden');
return;
}
favoritesSection.classList.remove('hidden');
const favoriteCryptos = cryptoData.filter(crypto => favorites.includes(crypto.id));
if (favoriteCryptos.length === 0) {
favoritesList.innerHTML = `
<div class="col-span-3 bg-blue-100 border-l-4 border-blue-500 text-blue-700 p-4">
<p>Vos cryptomonnaies favorites n'ont pas été trouvées dans les résultats actuels.</p>
</div>
`;
return;
}
favoritesList.innerHTML = '';
favoriteCryptos.forEach(crypto => {
const priceChange = crypto.price_change_percentage_24h;
const changeClass = priceChange >= 0 ? 'text-green-500' : 'text-red-500';
const changeIcon = priceChange >= 0 ? 'fa-arrow-up' : 'fa-arrow-down';
// Données techniques
const ma7 = crypto.technicals?.ma7 || 0;
const ma30 = crypto.technicals?.ma30 || 0;
const trendDirection = crypto.technicals?.trend_direction || 'neutral';
const trendStrength = crypto.technicals?.trend_strength || 0;
const sparklineData = crypto.technicals?.sparkline || [];
const canvasId = `fav-chart-${crypto.id}`;
const card = document.createElement('div');
card.className = 'coin-card bg-white rounded-xl shadow-md p-6 transition-all duration-300 dark-mode';
card.innerHTML = `
<div class="flex justify-between items-start mb-4">
<div class="flex items-center">
<img src="${crypto.image}" alt="${crypto.name}" class="w-10 h-10 mr-3">
<div>
<h3 class="font-bold">${crypto.name}</h3>
<p class="text-gray-500 text-sm">${crypto.symbol.toUpperCase()}</p>
</div>
</div>
<div class="flex items-center">
<span class="trend-indicator trend-${trendDirection} mr-2">
${trendDirection === 'up' ? '↑' : trendDirection === 'down' ? '↓' : '→'}
${Math.abs(trendStrength * 100).toFixed(0)}%
</span>
<button class="favorite-btn text-yellow-400 hover:text-yellow-500 focus:outline-none" data-id="${crypto.id}">
<i class="fas fa-star"></i>
</button>
</div>
</div>
<div class="chart-container mb-4">
<canvas id="${canvasId}"></canvas>
</div>
<div class="flex justify-between items-end mb-2">
<div>
<p class="text-gray-500 text-sm">Prix</p>
<p class="text-xl font-bold">${formatCurrency(crypto.current_price)}</p>
</div>
<div class="text-right">
<p class="text-gray-500 text-sm">24h</p>
<p class="${changeClass} font-semibold">
<i class="fas ${changeIcon} mr-1"></i>
${Math.abs(priceChange).toFixed(2)}%
</p>
</div>
</div>
<div class="grid grid-cols-2 gap-2 text-sm mb-2">
<div>
<p class="text-gray-500">MA7</p>
<p class="${crypto.current_price > ma7 ? 'text-green-500' : 'text-red-500'}">
${formatCurrency(ma7)}
</p>
</div>
<div class="text-right">
<p class="text-gray-500">MA30</p>
<p class="${crypto.current_price > ma30 ? 'text-green-500' : 'text-red-500'}">
${formatCurrency(ma30)}
</p>
</div>
</div>
<div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
<div class="flex justify-between text-sm">
<div>
<p class="text-gray-500">Capitalisation</p>
<p>${formatCurrency(crypto.market_cap)}</p>
</div>
<div class="text-right">
<p class="text-gray-500">Volume</p>
<p>${formatCurrency(crypto.total_volume)}</p>
</div>
</div>
</div>
`;
favoritesList.appendChild(card);
// Rendre le graphique après que l'élément a été ajouté au DOM
setTimeout(() => {
renderSparklineChart(canvasId, sparklineData, crypto.current_price, ma7, ma30);
}, 100);
});
// Ajouter les événements aux boutons favoris
document.querySelectorAll('.favorite-btn').forEach(btn => {
btn.addEventListener('click', function() {
const cryptoId = this.getAttribute('data-id');
toggleFavorite(cryptoId);
});
});
}
function filterCryptos() {
const searchTerm = searchInput.value.toLowerCase();
if (!searchTerm) {
renderCryptoList(cryptoData);
return;
}
const filtered = cryptoData.filter(crypto =>
crypto.name.toLowerCase().includes(searchTerm) ||
crypto.symbol.toLowerCase().includes(searchTerm)
);
renderCryptoList(filtered);
}
function sortCryptos(sortBy) {
currentSort = sortBy;
// Mettre à jour l'état des boutons
document.querySelectorAll('[id^="sort"]').forEach(btn => {
btn.classList.remove('bg-blue-500', 'text-white');
btn.classList.add('bg-gray-200', 'dark:bg-gray-700');
});
const activeBtn = document.getElementById(`sort${sortBy.charAt(0).toUpperCase() + sortBy.slice(1).replace('_', ' ').split(' ')[0]}`);
if (activeBtn) {
activeBtn.classList.remove('bg-gray-200', 'dark:bg-gray-700');
activeBtn.classList.add('bg-blue-500', 'text-white');
}
// Trier les données
const sorted = [...cryptoData].sort((a, b) => {
if (sortBy === 'price_change_percentage_24h') {
return b[sortBy] - a[sortBy];
} else if (sortBy === 'trend_strength') {
return (b.technicals?.trend_strength || 0) - (a.technicals?.trend_strength || 0);
} else {
return b[sortBy] - a[sortBy];
}
});
renderCryptoList(sorted);
}
function toggleDarkMode() {
isDarkMode = !isDarkMode;
document.body.classList.toggle('dark-mode');
if (isDarkMode) {
darkModeToggle.innerHTML = '<i class="fas fa-sun"></i>';
localStorage.setItem('darkMode', 'true');
} else {
darkModeToggle.innerHTML = '<i class="fas fa-moon"></i>';
localStorage.setItem('darkMode', 'false');
}
// Re-rendre les graphiques avec les nouvelles couleurs
renderCryptoList(cryptoData);
if (favoritesSection && !favoritesSection.classList.contains('hidden')) {
updateFavoritesSection();
}
}
function formatCurrency(value) {
return new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'EUR',
minimumFractionDigits: value < 1 ? 4 : 2,
maximumFractionDigits: value < 1 ? 6 : 2
}).format(value);
}
function formatChange(value, isPercentage = false) {
if (value === undefined || value === null) return '';
const absValue = Math.abs(value);
const formattedValue = isPercentage ? absValue.toFixed(2) : absValue.toFixed(1);
const arrow = value >= 0 ? '↑' : '↓';
const colorClass = value >= 0 ? 'text-green-500' : 'text-red-500';
return `<span class="${colorClass}">${arrow} ${formattedValue}${isPercentage ? '%' : ''}</span>`;
}
// Actualiser les données toutes les minutes
setInterval(fetchData, 60000);
});
</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=bourahima/crypto-trafic" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>