A
Anonymous

Mock Crypto Data - Copy this React, Tailwind Component to your project

/* CSS Reset: Ensures consistent styling across browsers by resetting margins, paddings, and box-sizing */ * { margin: 0; padding: 0; box-sizing: border-box; } /* Base styling for the body: Sets background color, text color, and font family */ body { background-color: #ffffff; color: white; font-family: Arial, sans-serif; } /* Header section: Flex container for alignment and responsive behavior */ .header { padding: 1rem; background-color: #2ccaff; display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; } /* Logo container: Centers the logo and adds spacing below */ /* Logo */ .header .logo { width: 40px; height: 40px; object-fit: contain; border-radius: 50%; } /* Time button group: Arranges buttons in a horizontal row with spacing */ .time-buttons { display: flex; gap: 0.5rem; } /* Individual time button: Rounded buttons with a modern look */ .time-btn { padding: 0.5rem 1rem; border: none; border-radius: 20px; cursor: pointer; background-color: #333; color: white; } /* Active button styling: Highlights the selected time button */ .time-btn.active { background-color: #ff0000; } /* Search container: Flexible input field for responsiveness */ .search-container { flex-grow: 1; max-width: 400px; } /* Search bar styling: Rounded input field with light background */ #search { width: 100%; padding: 0.9rem 1rem; border-radius: 20px; border: none; background-color: #F0F0F0; color: rgb(0, 0, 0); } /* Bubble container: Flexbox layout to center and arrange bubbles */ .bubbles-container { padding: 2rem; display: flex; flex-wrap: wrap; gap: 1rem; justify-content: center; } /* Bubble styling: Circular elements with hover and animation effects */ .bubble { border-radius: 50%; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; position: relative; animation: float 5s ease-in-out infinite; background: transparent; } /* Positive bubble: Green glowing effect to indicate positive state */ .bubble.positive { box-shadow: inset 0 0 15px 3px rgba(0, 255, 0, 0.7), inset 0 0 30px 5px rgba(0, 255, 0, 0.5); } /* Negative bubble: Red glowing effect to indicate negative state */ .bubble.negative { box-shadow: inset 0 0 15px 3px rgba(255, 0, 0, 0.7), inset 0 0 30px 5px rgba(255, 0, 0, 0.5); } /* Hover effect for bubbles: Enlarges bubble on hover for interaction feedback */ .bubble:hover { transform: scale(1.2); } /* Symbol inside the bubble: Text styling for symbol content */ .bubble .symbol { font-size: 0.9rem; font-weight: bold; color: rgb(0, 0, 0); margin-top: 4px; } /* Percentage inside the bubble: Smaller, lighter text below the symbol */ .bubble .percentage { font-size: 0.65rem; color: rgb(0, 0, 0); font-weight: normal; } /* Bubble image: Circular image inside the bubble */ .bubble img { width: 40px; height: 40px; object-fit: contain; border-radius: 50%; } /* Loading text: Center-aligned message for loading state */ .loading { text-align: center; padding: 2rem; font-size: 1.2rem; } /* Floating animation for bubbles: Smooth, subtle movement */ @keyframes float { 0% { transform: translate(0, 0); } 25% { transform: translate(3px, -5px); } 50% { transform: translate(-3px, 5px); } 75% { transform: translate(-5px, -3px); } 100% { transform: translate(0, 0); } }// Base URL for the CoinGecko API const COINGECKO_API = 'https://api.coingecko.com/api/v3'; // DOM elements for bubbles container, search input, and time period buttons const bubblesContainer = document.querySelector('.bubbles-container'); const searchInput = document.getElementById('search'); const timeButtons = document.querySelectorAll('.time-btn'); // Array to store the cryptocurrency data fetched from the API let cryptoData = []; // Define the minimum and maximum bubble sizes (in pixels) for scaling visualization const minSize = 50; const maxSize = 150; // Function to fetch cryptocurrency market data from the CoinGecko API async function fetchCryptoData() { try { const response = await fetch( `${COINGECKO_API}/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&sparkline=false&price_change_percentage=1h,24h,7d,30d,1y` ); const data = await response.json(); // Parse the API response JSON cryptoData = data; // Store the data globally renderBubbles(data); // Render bubbles using the fetched data } catch (error) { // Display an error message if the API request fails bubblesContainer.innerHTML = 'Error loading data. Please try again later.'; console.error('Error:', error); } } // Function to render bubbles dynamically based on cryptocurrency data function renderBubbles(data) { // Get the active time period from the selected button const period = document.querySelector('.time-btn.active').dataset.period; // Get the search term from the input field (convert to lowercase for case-insensitive matching) const searchTerm = searchInput.value.toLowerCase(); // Filter data based on the search term matching the coin's symbol or name const filteredData = data.filter(coin => coin.symbol.toLowerCase().includes(searchTerm) || coin.name.toLowerCase().includes(searchTerm) ); // Calculate max percentage change to scale bubble sizes const percentages = filteredData.map(coin => Math.abs(getPercentageChange(coin, period))); const maxPercentage = Math.max(...percentages); // Create HTML for each bubble dynamically const bubblesHTML = filteredData.map(coin => { const percentage = getPercentageChange(coin, period); // Get percentage change for the active period const logoUrl = coin.image; // Coin's logo URL const isPositive = percentage >= 0; // Determine if percentage is positive or negative const bubbleClass = isPositive ? 'positive' : 'negative'; // Apply appropriate CSS class // Scale bubble size based on the percentage change const size = minSize + ((Math.abs(percentage) / maxPercentage) * (maxSize - minSize)); // Return the HTML for each bubble return ` <div class="bubble ${bubbleClass}" style="width: ${size}px; height: ${size}px;"> <img src="${logoUrl}" alt="${coin.symbol.toUpperCase()} logo"> <div class="symbol">${coin.symbol.toUpperCase()}</div> <div class="percentage">${percentage.toFixed(2)}%</div> </div> `; }).join(''); // Join all bubble HTML strings into one // Update the container with the generated bubbles HTML bubblesContainer.innerHTML = bubblesHTML; } // Function to get the percentage change for the specified period function getPercentageChange(coin, period) { switch(period) { case '1h': return coin.price_change_percentage_1h_in_currency || 0; case '24h': return coin.price_change_percentage_24h || 0; case '7d': return coin.price_change_percentage_7d_in_currency || 0; case '30d': return coin.price_change_percentage_30d_in_currency || 0; case '1y': return coin.price_change_percentage_1y_in_currency || 0; default: return coin.price_change_percentage_24h || 0; // Default to 24-hour percentage change } } // Add click event listeners to all time period buttons timeButtons.forEach(button => { button.addEventListener('click', () => { // Remove 'active' class from all buttons and set it for the clicked button timeButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); // Re-render the bubbles for the selected time period renderBubbles(cryptoData); }); }); // Add an input event listener to filter bubbles based on search input searchInput.addEventListener('input', () => renderBubbles(cryptoData)); // Initial fetch of cryptocurrency data on page load fetchCryptoData(); // Set up periodic data refresh every 1 hour (3600000 ms) setInterval(fetchCryptoData, 3600000);convert this all files into react and tailwind css and improves the ui also

Prompt
Component Preview

About

mockCryptoData - A dynamic crypto data visualization component with interactive bubbles, responsive search, and time period buttons,. Copy component code!

Share

Last updated 1 month ago