mexicanamerican commited on
Commit
43ceb5f
·
verified ·
1 Parent(s): 0f6afff

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +321 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Crypto
3
- emoji: 🌍
4
- colorFrom: red
5
- colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: crypto
3
+ emoji: 🐳
4
+ colorFrom: blue
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,321 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Crypto Price Tracker</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @keyframes pulse {
11
+ 0% { transform: scale(1); }
12
+ 50% { transform: scale(1.05); }
13
+ 100% { transform: scale(1); }
14
+ }
15
+ .pulse {
16
+ animation: pulse 2s infinite;
17
+ }
18
+ .gradient-bg {
19
+ background: linear-gradient(135deg, #1e3a8a 0%, #0ea5e9 100%);
20
+ }
21
+ .card-hover:hover {
22
+ transform: translateY(-5px);
23
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
24
+ }
25
+ .price-up {
26
+ color: #10b981;
27
+ }
28
+ .price-down {
29
+ color: #ef4444;
30
+ }
31
+ .loading-spinner {
32
+ border-top-color: #3b82f6;
33
+ animation: spin 1s linear infinite;
34
+ }
35
+ @keyframes spin {
36
+ 0% { transform: rotate(0deg); }
37
+ 100% { transform: rotate(360deg); }
38
+ }
39
+ </style>
40
+ </head>
41
+ <body class="min-h-screen gradient-bg text-white">
42
+ <div class="container mx-auto px-4 py-12">
43
+ <header class="text-center mb-12">
44
+ <h1 class="text-4xl md:text-5xl font-bold mb-4">Crypto Price Tracker</h1>
45
+ <p class="text-xl opacity-90">Real-time cryptocurrency prices and market data</p>
46
+ <div class="mt-6 flex justify-center">
47
+ <div class="relative w-full max-w-md">
48
+ <input
49
+ type="text"
50
+ id="searchInput"
51
+ placeholder="Search cryptocurrencies..."
52
+ class="w-full px-4 py-3 rounded-full bg-white/10 border border-white/20 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent text-white placeholder-white/70"
53
+ >
54
+ <button id="searchBtn" class="absolute right-3 top-3 text-white/70 hover:text-white">
55
+ <i class="fas fa-search"></i>
56
+ </button>
57
+ </div>
58
+ </div>
59
+ </header>
60
+
61
+ <div class="flex justify-between items-center mb-6">
62
+ <h2 class="text-2xl font-semibold">Top Cryptocurrencies</h2>
63
+ <div class="flex items-center space-x-2">
64
+ <span class="text-sm">Auto-refresh:</span>
65
+ <label class="relative inline-flex items-center cursor-pointer">
66
+ <input type="checkbox" id="autoRefresh" class="sr-only peer" checked>
67
+ <div class="w-11 h-6 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-500"></div>
68
+ </label>
69
+ </div>
70
+ </div>
71
+
72
+ <div id="loading" class="flex justify-center items-center py-12">
73
+ <div class="loading-spinner h-12 w-12 border-4 border-white/20 rounded-full"></div>
74
+ </div>
75
+
76
+ <div id="cryptoContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 hidden">
77
+ <!-- Crypto cards will be inserted here -->
78
+ </div>
79
+
80
+ <div id="errorMessage" class="hidden text-center py-12">
81
+ <i class="fas fa-exclamation-triangle text-4xl mb-4 text-yellow-400"></i>
82
+ <h3 class="text-2xl font-semibold mb-2">Failed to load data</h3>
83
+ <p class="mb-4">We couldn't fetch cryptocurrency prices. Please check your connection and try again.</p>
84
+ <button id="retryBtn" class="px-6 py-2 bg-white/10 hover:bg-white/20 rounded-full border border-white/20 transition-all">
85
+ <i class="fas fa-sync-alt mr-2"></i> Retry
86
+ </button>
87
+ </div>
88
+
89
+ <div class="mt-12 text-center text-sm opacity-80">
90
+ <p>Data provided by CoinGecko API. Prices update every 60 seconds.</p>
91
+ <p class="mt-2">Last updated: <span id="lastUpdated">-</span></p>
92
+ </div>
93
+ </div>
94
+
95
+ <script>
96
+ // Configuration
97
+ const config = {
98
+ coins: ['bitcoin', 'ethereum', 'binancecoin', 'ripple', 'cardano', 'solana', 'dogecoin', 'polkadot', 'litecoin', 'chainlink'],
99
+ vsCurrency: 'usd',
100
+ autoRefreshInterval: 60000 // 60 seconds
101
+ };
102
+
103
+ // DOM Elements
104
+ const cryptoContainer = document.getElementById('cryptoContainer');
105
+ const loadingElement = document.getElementById('loading');
106
+ const errorMessage = document.getElementById('errorMessage');
107
+ const retryBtn = document.getElementById('retryBtn');
108
+ const searchInput = document.getElementById('searchInput');
109
+ const searchBtn = document.getElementById('searchBtn');
110
+ const autoRefreshToggle = document.getElementById('autoRefresh');
111
+ const lastUpdatedElement = document.getElementById('lastUpdated');
112
+
113
+ // State
114
+ let refreshInterval;
115
+ let allCoinsData = [];
116
+
117
+ // Initialize
118
+ document.addEventListener('DOMContentLoaded', () => {
119
+ fetchCryptoData();
120
+ setupAutoRefresh();
121
+ setupEventListeners();
122
+ });
123
+
124
+ // Event Listeners
125
+ function setupEventListeners() {
126
+ retryBtn.addEventListener('click', fetchCryptoData);
127
+ searchBtn.addEventListener('click', filterCoins);
128
+ searchInput.addEventListener('keyup', (e) => {
129
+ if (e.key === 'Enter') filterCoins();
130
+ });
131
+ autoRefreshToggle.addEventListener('change', setupAutoRefresh);
132
+ }
133
+
134
+ // Auto Refresh
135
+ function setupAutoRefresh() {
136
+ clearInterval(refreshInterval);
137
+ if (autoRefreshToggle.checked) {
138
+ refreshInterval = setInterval(fetchCryptoData, config.autoRefreshInterval);
139
+ }
140
+ }
141
+
142
+ // Fetch Data
143
+ async function fetchCryptoData() {
144
+ try {
145
+ showLoading();
146
+ hideError();
147
+
148
+ const ids = config.coins.join(',');
149
+ const url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=${config.vsCurrency}&ids=${ids}&order=market_cap_desc&per_page=100&page=1&sparkline=true&price_change_percentage=1h,24h,7d`;
150
+
151
+ const response = await fetch(url);
152
+
153
+ if (!response.ok) {
154
+ throw new Error('Network response was not ok');
155
+ }
156
+
157
+ allCoinsData = await response.json();
158
+ renderCryptoCards(allCoinsData);
159
+ updateLastUpdated();
160
+ } catch (error) {
161
+ console.error('Error fetching crypto data:', error);
162
+ showError();
163
+ } finally {
164
+ hideLoading();
165
+ }
166
+ }
167
+
168
+ // Render Crypto Cards
169
+ function renderCryptoCards(coinsData) {
170
+ cryptoContainer.innerHTML = '';
171
+
172
+ coinsData.forEach(coin => {
173
+ const priceChange24h = coin.price_change_percentage_24h;
174
+ const priceChangeClass = priceChange24h >= 0 ? 'price-up' : 'price-down';
175
+ const priceChangeIcon = priceChange24h >= 0 ? 'fa-arrow-up' : 'fa-arrow-down';
176
+
177
+ const card = document.createElement('div');
178
+ card.className = 'bg-white/5 rounded-xl p-6 border border-white/10 transition-all duration-300 card-hover';
179
+ card.innerHTML = `
180
+ <div class="flex justify-between items-start mb-4">
181
+ <div class="flex items-center">
182
+ <img src="${coin.image}" alt="${coin.name}" class="w-10 h-10 mr-3 rounded-full">
183
+ <div>
184
+ <h3 class="font-bold text-lg">${coin.name}</h3>
185
+ <span class="text-sm opacity-80">${coin.symbol.toUpperCase()}</span>
186
+ </div>
187
+ </div>
188
+ <span class="text-xs px-2 py-1 rounded-full bg-white/10">#${coin.market_cap_rank}</span>
189
+ </div>
190
+
191
+ <div class="mb-4">
192
+ <div class="flex items-baseline mb-1">
193
+ <span class="text-2xl font-bold mr-2">$${coin.current_price.toLocaleString()}</span>
194
+ <span class="text-sm ${priceChangeClass}">
195
+ <i class="fas ${priceChangeIcon} mr-1"></i>${Math.abs(priceChange24h).toFixed(2)}%
196
+ </span>
197
+ </div>
198
+ <div class="text-sm opacity-80">Market Cap: $${coin.market_cap.toLocaleString()}</div>
199
+ </div>
200
+
201
+ <div class="h-16 mb-4">
202
+ <canvas class="w-full h-full" id="sparkline-${coin.id}"></canvas>
203
+ </div>
204
+
205
+ <div class="grid grid-cols-3 gap-2 text-center text-sm">
206
+ <div class="bg-white/5 p-2 rounded">
207
+ <div>1h</div>
208
+ <div class="${coin.price_change_percentage_1h_in_currency >= 0 ? 'price-up' : 'price-down'}">
209
+ ${coin.price_change_percentage_1h_in_currency ? coin.price_change_percentage_1h_in_currency.toFixed(2) + '%' : '-'}
210
+ </div>
211
+ </div>
212
+ <div class="bg-white/5 p-2 rounded">
213
+ <div>24h</div>
214
+ <div class="${priceChangeClass}">
215
+ ${priceChange24h.toFixed(2)}%
216
+ </div>
217
+ </div>
218
+ <div class="bg-white/5 p-2 rounded">
219
+ <div>7d</div>
220
+ <div class="${coin.price_change_percentage_7d_in_currency >= 0 ? 'price-up' : 'price-down'}">
221
+ ${coin.price_change_percentage_7d_in_currency.toFixed(2)}%
222
+ </div>
223
+ </div>
224
+ </div>
225
+ `;
226
+
227
+ cryptoContainer.appendChild(card);
228
+
229
+ // Render sparkline after the card is added to DOM
230
+ setTimeout(() => renderSparkline(coin), 100);
231
+ });
232
+
233
+ showCryptoContainer();
234
+ }
235
+
236
+ // Render Sparkline Chart
237
+ function renderSparkline(coin) {
238
+ const canvas = document.getElementById(`sparkline-${coin.id}`);
239
+ if (!canvas) return;
240
+
241
+ const ctx = canvas.getContext('2d');
242
+ const sparklineData = coin.sparkline_in_7d.price;
243
+ const width = canvas.width;
244
+ const height = canvas.height;
245
+
246
+ // Calculate scale factors
247
+ const minPrice = Math.min(...sparklineData);
248
+ const maxPrice = Math.max(...sparklineData);
249
+ const scaleY = height / (maxPrice - minPrice);
250
+ const scaleX = width / (sparklineData.length - 1);
251
+
252
+ // Draw sparkline
253
+ ctx.beginPath();
254
+ ctx.moveTo(0, height - (sparklineData[0] - minPrice) * scaleY);
255
+
256
+ for (let i = 1; i < sparklineData.length; i++) {
257
+ ctx.lineTo(i * scaleX, height - (sparklineData[i] - minPrice) * scaleY);
258
+ }
259
+
260
+ ctx.strokeStyle = coin.price_change_percentage_7d_in_currency >= 0 ? '#10b981' : '#ef4444';
261
+ ctx.lineWidth = 2;
262
+ ctx.stroke();
263
+ }
264
+
265
+ // Filter Coins
266
+ function filterCoins() {
267
+ const searchTerm = searchInput.value.toLowerCase();
268
+
269
+ if (!searchTerm) {
270
+ renderCryptoCards(allCoinsData);
271
+ return;
272
+ }
273
+
274
+ const filteredCoins = allCoinsData.filter(coin =>
275
+ coin.name.toLowerCase().includes(searchTerm) ||
276
+ coin.symbol.toLowerCase().includes(searchTerm)
277
+ );
278
+
279
+ if (filteredCoins.length === 0) {
280
+ cryptoContainer.innerHTML = `
281
+ <div class="col-span-full text-center py-12">
282
+ <i class="fas fa-search text-4xl mb-4 opacity-50"></i>
283
+ <h3 class="text-xl font-semibold">No cryptocurrencies found</h3>
284
+ <p class="opacity-80">Try a different search term</p>
285
+ </div>
286
+ `;
287
+ } else {
288
+ renderCryptoCards(filteredCoins);
289
+ }
290
+ }
291
+
292
+ // UI Helpers
293
+ function showLoading() {
294
+ loadingElement.classList.remove('hidden');
295
+ cryptoContainer.classList.add('hidden');
296
+ }
297
+
298
+ function hideLoading() {
299
+ loadingElement.classList.add('hidden');
300
+ }
301
+
302
+ function showCryptoContainer() {
303
+ cryptoContainer.classList.remove('hidden');
304
+ }
305
+
306
+ function showError() {
307
+ errorMessage.classList.remove('hidden');
308
+ cryptoContainer.classList.add('hidden');
309
+ }
310
+
311
+ function hideError() {
312
+ errorMessage.classList.add('hidden');
313
+ }
314
+
315
+ function updateLastUpdated() {
316
+ const now = new Date();
317
+ lastUpdatedElement.textContent = now.toLocaleTimeString();
318
+ }
319
+ </script>
320
+ <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 <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
321
+ </html>