Skip to content

Commit 7e0d17d

Browse files
Revert to official CoinGecko widget
Reverts the custom price ticker to the official CoinGecko widget and removes the semi-white background.
1 parent 131392f commit 7e0d17d

File tree

3 files changed

+30
-127
lines changed

3 files changed

+30
-127
lines changed

src/components/Header/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ const Header = () => {
6161
)}
6262
</AnimatePresence>
6363

64-
<div className="w-full border-t border-alien-gold/20 border-b border-alien-gold/20 bg-black/60">
64+
<div className="w-full border-t border-alien-gold/20 border-b border-alien-gold/20 bg-transparent">
6565
<PriceTicker />
6666
</div>
6767
</header>

src/components/PriceTicker.tsx

Lines changed: 28 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,40 @@
11

2-
import React, { useEffect, useMemo, useState } from 'react';
2+
import React, { useEffect } from 'react';
33

4-
// A fully controlled, ultra-smooth ticker (no external widget)
5-
// - Fetches selected coins from CoinGecko public API
6-
// - Uses pure CSS animation you can precisely control (duration)
4+
// Use official CoinGecko marquee widget
5+
// Ensures the script is loaded once and renders the custom element
76

8-
type Coin = {
9-
id: string;
10-
symbol: string;
11-
label: string;
12-
};
13-
14-
const COINS: Coin[] = [
15-
{ id: 'bitcoin', symbol: 'BTC', label: 'Bitcoin' },
16-
{ id: 'ethereum', symbol: 'ETH', label: 'Ethereum' },
17-
{ id: 'binancecoin', symbol: 'BNB', label: 'BNB' },
18-
{ id: 'solana', symbol: 'SOL', label: 'Solana' },
19-
{ id: 'tether-gold', symbol: 'XAUt', label: 'Tether Gold' },
20-
{ id: 'chainlink', symbol: 'LINK', label: 'Chainlink' },
21-
{ id: 'polkadot', symbol: 'DOT', label: 'Polkadot' },
22-
{ id: 'avalanche-2', symbol: 'AVAX', label: 'Avalanche' },
23-
];
24-
const ICONS: Record<string, string> = {
25-
BTC: 'https://assets.coingecko.com/coins/images/1/small/bitcoin.png',
26-
ETH: 'https://assets.coingecko.com/coins/images/279/small/ethereum.png',
27-
BNB: 'https://assets.coingecko.com/coins/images/825/small/binance-coin-logo.png',
28-
SOL: 'https://assets.coingecko.com/coins/images/4128/small/solana.png',
29-
XAUt: 'https://assets.coingecko.com/coins/images/10488/small/Tether_Gold.png',
30-
LINK: 'https://assets.coingecko.com/coins/images/877/small/chainlink-new-logo.png',
31-
DOT: 'https://assets.coingecko.com/coins/images/12171/small/polkadot.png',
32-
AVAX: 'https://assets.coingecko.com/coins/images/12559/small/coin-round-red.png'
33-
};
7+
declare global {
8+
namespace JSX {
9+
interface IntrinsicElements {
10+
'gecko-coin-price-marquee-widget': any;
11+
}
12+
}
13+
}
3414

35-
const API = (ids: string[]) =>
36-
`https://api.coingecko.com/api/v3/simple/price?ids=${ids.join(',')}&vs_currencies=usd&precision=2`;
37-
38-
const DURATION_SEC = 30; // Adjust speed here (bigger = slower)
15+
const WIDGET_SRC = 'https://widgets.coingecko.com/gecko-coin-price-marquee-widget.js';
3916

4017
const PriceTicker: React.FC = () => {
41-
const [prices, setPrices] = useState<Record<string, number>>({});
42-
const [error, setError] = useState<string | null>(null);
43-
44-
const ids = useMemo(() => COINS.map(c => c.id), []);
45-
4618
useEffect(() => {
47-
let mounted = true;
48-
49-
const fetchPrices = async () => {
50-
try {
51-
setError(null);
52-
const res = await fetch(API(ids), { cache: 'no-store' });
53-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
54-
const data = await res.json();
55-
if (!mounted) return;
56-
const mapped: Record<string, number> = {};
57-
COINS.forEach(c => {
58-
const v = data?.[c.id]?.usd;
59-
if (typeof v === 'number') mapped[c.symbol] = v;
60-
});
61-
setPrices(mapped);
62-
} catch (e: any) {
63-
if (!mounted) return;
64-
console.error('Ticker fetch failed', e);
65-
setError('offline');
66-
}
67-
};
68-
69-
fetchPrices();
70-
const iv = setInterval(fetchPrices, 60_000); // refresh each minute
71-
return () => {
72-
mounted = false;
73-
clearInterval(iv);
74-
};
75-
}, [ids]);
76-
77-
const items = useMemo(() => {
78-
const list = Object.keys(prices).length
79-
? COINS.map(c => ({ symbol: c.symbol, price: prices[c.symbol] }))
80-
: [
81-
{ symbol: 'BTC', price: 64750.21 },
82-
{ symbol: 'ETH', price: 3145.89 },
83-
{ symbol: 'BNB', price: 596.24 },
84-
{ symbol: 'SOL', price: 152.36 },
85-
{ symbol: 'XAUt', price: 2321.42 },
86-
{ symbol: 'LINK', price: 13.45 },
87-
{ symbol: 'DOT', price: 6.12 },
88-
{ symbol: 'AVAX', price: 28.77 },
89-
];
90-
return list;
91-
}, [prices]);
19+
const id = 'coingecko-widget-script';
20+
if (!document.getElementById(id)) {
21+
const s = document.createElement('script');
22+
s.src = WIDGET_SRC;
23+
s.async = true;
24+
s.id = id;
25+
document.head.appendChild(s);
26+
}
27+
}, []);
9228

9329
return (
94-
<div className="w-full overflow-hidden bg-alien-space-dark/80 border-t border-b border-alien-gold/20 h-[40px]">
95-
{/* Local keyframes to avoid touching global CSS */}
96-
<style>{`
97-
@keyframes ticker-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
98-
`}</style>
99-
100-
<div className="relative w-full h-[40px]">
101-
{/* Track wrapper */}
102-
<div className="absolute inset-0 flex items-center">
103-
{/* Two tracks for seamless loop */}
104-
{[0,1].map(i => (
105-
<div
106-
key={i}
107-
className="flex items-center gap-6 px-4 whitespace-nowrap"
108-
style={{
109-
animation: `ticker-scroll ${DURATION_SEC}s linear infinite`,
110-
// Stagger the second copy to start where first ends
111-
animationDelay: i === 1 ? `${DURATION_SEC/2}s` : '0s',
112-
}}
113-
>
114-
{items.map((it, idx) => (
115-
<div key={`${i}-${idx}`} className="flex items-center gap-2">
116-
<img
117-
src={ICONS[it.symbol]}
118-
alt={`${it.symbol} logo`}
119-
loading="lazy"
120-
width={16}
121-
height={16}
122-
className="inline-block"
123-
onError={(e) => {
124-
(e.currentTarget as HTMLImageElement).style.display = 'none';
125-
}}
126-
/>
127-
<span className="font-bold">{it.symbol}:</span>
128-
<span className="text-alien-green">${it.price.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
129-
</div>
130-
))}
131-
</div>
132-
))}
133-
</div>
134-
</div>
30+
<div className="w-full overflow-hidden h-[40px]">
31+
<gecko-coin-price-marquee-widget
32+
locale="es"
33+
transparent-background="true"
34+
outlined="true"
35+
coin-ids="bitcoin,tether-gold,ethereum,binancecoin,bitcoin-cash,bittensor,solana,litecoin,hyperliquid,chainlink,injective-protocol,uniswap,aptos,cosmos,bitget-token,polkadot,sui,the-open-network,near,nexo,cardano,tron,crypto-com-chain"
36+
initial-currency="usd"
37+
/>
13538
</div>
13639
);
13740
};

src/index.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
}
7272

7373
body {
74-
@apply bg-alien-space text-foreground overflow-x-hidden;
74+
@apply bg-transparent text-foreground overflow-x-hidden;
7575
scroll-behavior: smooth;
7676
}
7777

0 commit comments

Comments
 (0)