Download script.js from devusman/cryptopulse-pro-the-future-in-your-hands: direct link, hf CLI and curl.
- Browser
- Download file 8.05 kB
-
https://huggingface.co/spaces/devusman/cryptopulse-pro-the-future-in-your-hands/resolve/main/script.js
- Command line
-
hf download hf://spaces/devusman/cryptopulse-pro-the-future-in-your-hands/script.js
-
curl -L -o script.js https://huggingface.co/spaces/devusman/cryptopulse-pro-the-future-in-your-hands/resolve/main/script.js
8.05 kB
| // Global scripts that will be used across all pages | |
| // Initialize tooltips | |
| function initTooltips() { | |
| const tooltipTriggers = document.querySelectorAll('[data-tooltip]'); | |
| tooltipTriggers.forEach(trigger => { | |
| const tooltip = document.createElement('div'); | |
| tooltip.className = 'tooltip-text bg-gray-800 text-white text-xs rounded py-1 px-2 absolute z-50 invisible'; | |
| tooltip.textContent = trigger.dataset.tooltip; | |
| trigger.appendChild(tooltip); | |
| trigger.addEventListener('mouseenter', () => { | |
| tooltip.classList.remove('invisible'); | |
| tooltip.classList.add('visible'); | |
| }); | |
| trigger.addEventListener('mouseleave', () => { | |
| tooltip.classList.remove('visible'); | |
| tooltip.classList.add('invisible'); | |
| }); | |
| }); | |
| } | |
| // Initialize modals | |
| function initModals() { | |
| const modalButtons = document.querySelectorAll('[data-modal-toggle]'); | |
| modalButtons.forEach(button => { | |
| const modalId = button.dataset.modalToggle; | |
| const modal = document.getElementById(modalId); | |
| const closeButtons = modal.querySelectorAll('[data-modal-hide]'); | |
| button.addEventListener('click', () => { | |
| modal.classList.remove('hidden'); | |
| modal.classList.add('flex'); | |
| document.body.classList.add('overflow-hidden'); | |
| }); | |
| closeButtons.forEach(closeButton => { | |
| closeButton.addEventListener('click', () => { | |
| modal.classList.remove('flex'); | |
| modal.classList.add('hidden'); | |
| document.body.classList.remove('overflow-hidden'); | |
| }); | |
| }); | |
| // Close when clicking outside | |
| modal.addEventListener('click', (e) => { | |
| if (e.target === modal) { | |
| modal.classList.remove('flex'); | |
| modal.classList.add('hidden'); | |
| document.body.classList.remove('overflow-hidden'); | |
| } | |
| }); | |
| }); | |
| } | |
| // Mobile menu toggle | |
| function initMobileMenu() { | |
| const mobileMenuButton = document.querySelector('[data-collapse-toggle="mobile-menu"]'); | |
| if (!mobileMenuButton) return; | |
| const mobileMenu = document.getElementById('mobile-menu'); | |
| mobileMenuButton.addEventListener('click', () => { | |
| mobileMenu.classList.toggle('hidden'); | |
| const expanded = mobileMenuButton.getAttribute('aria-expanded') === 'true'; | |
| mobileMenuButton.setAttribute('aria-expanded', !expanded); | |
| }); | |
| } | |
| // Dropdown toggle | |
| function initDropdowns() { | |
| const dropdownButtons = document.querySelectorAll('[data-dropdown-toggle]'); | |
| dropdownButtons.forEach(button => { | |
| const dropdownId = button.dataset.dropdownToggle; | |
| const dropdown = document.getElementById(dropdownId); | |
| button.addEventListener('click', () => { | |
| dropdown.classList.toggle('hidden'); | |
| }); | |
| // Close when clicking outside | |
| document.addEventListener('click', (e) => { | |
| if (!button.contains(e.target) && !dropdown.contains(e.target)) { | |
| dropdown.classList.add('hidden'); | |
| } | |
| }); | |
| }); | |
| } | |
| // Tab functionality | |
| function initTabs() { | |
| const tabButtons = document.querySelectorAll('[data-tab-toggle]'); | |
| tabButtons.forEach(button => { | |
| button.addEventListener('click', () => { | |
| const tabId = button.dataset.tabToggle; | |
| const tabContainer = button.closest('[data-tab-container]'); | |
| // Hide all tabs in the container | |
| tabContainer.querySelectorAll('[data-tab-content]').forEach(tab => { | |
| tab.classList.add('hidden'); | |
| }); | |
| // Show the selected tab | |
| document.getElementById(tabId).classList.remove('hidden'); | |
| // Update active state of buttons | |
| tabContainer.querySelectorAll('[data-tab-toggle]').forEach(btn => { | |
| btn.classList.remove('active'); | |
| btn.classList.add('text-gray-400'); | |
| btn.classList.remove('text-white', 'border-purple-500'); | |
| }); | |
| button.classList.add('active', 'text-white', 'border-purple-500'); | |
| button.classList.remove('text-gray-400'); | |
| }); | |
| }); | |
| } | |
| // Initialize everything when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', () => { | |
| initTooltips(); | |
| initModals(); | |
| initMobileMenu(); | |
| initDropdowns(); | |
| initTabs(); | |
| // Smooth scroll for anchor links | |
| document.querySelectorAll('a[href^="#"]').forEach(anchor => { | |
| anchor.addEventListener('click', function(e) { | |
| e.preventDefault(); | |
| const targetId = this.getAttribute('href'); | |
| if (targetId === '#') return; | |
| const targetElement = document.querySelector(targetId); | |
| if (targetElement) { | |
| targetElement.scrollIntoView({ | |
| behavior: 'smooth' | |
| }); | |
| } | |
| }); | |
| }); | |
| }); | |
| // Price ticker functionality | |
| class PriceTicker { | |
| constructor() { | |
| this.ticker = document.querySelector('custom-price-ticker'); | |
| if (!this.ticker) return; | |
| this.coins = [ | |
| { symbol: 'BTC', name: 'Bitcoin', price: 0, change: 0 }, | |
| { symbol: 'ETH', name: 'Ethereum', price: 0, change: 0 }, | |
| { symbol: 'XRP', name: 'Ripple', price: 0, change: 0 }, | |
| { symbol: 'LTC', name: 'Litecoin', price: 0, change: 0 }, | |
| { symbol: 'ADA', name: 'Cardano', price: 0, change: 0 }, | |
| { symbol: 'DOGE', name: 'Dogecoin', price: 0, change: 0 }, | |
| ]; | |
| this.fetchPrices(); | |
| } | |
| async fetchPrices() { | |
| try { | |
| // In a real app, you would fetch from a real API | |
| // This is a mock implementation | |
| this.coins = this.coins.map(coin => { | |
| const basePrice = Math.random() * 10000 + 1000; | |
| const price = parseFloat(basePrice.toFixed(2)); | |
| const change = parseFloat((Math.random() * 10 - 5).toFixed(2)); | |
| return { | |
| ...coin, | |
| price, | |
| change | |
| }; | |
| }); | |
| this.render(); | |
| // Update prices every 10 seconds | |
| setTimeout(() => this.fetchPrices(), 10000); | |
| } catch (error) { | |
| console.error('Error fetching prices:', error); | |
| } | |
| } | |
| render() { | |
| if (!this.ticker) return; | |
| this.ticker.innerHTML = ` | |
| <div class="overflow-hidden"> | |
| <div class="inline-block whitespace-nowrap animate-marquee"> | |
| ${this.coins.map(coin => ` | |
| <div class="inline-flex items-center mx-8"> | |
| <span class="font-bold mr-2">${coin.symbol}</span> | |
| <span class="mr-2">$${coin.price.toLocaleString()}</span> | |
| <span class="${coin.change >= 0 ? 'text-green-400' : 'text-red-400'}"> | |
| ${coin.change >= 0 ? '+' : ''}${coin.change}% | |
| </span> | |
| </div> | |
| `).join('')} | |
| </div> | |
| </div> | |
| `; | |
| } | |
| startAnimation() { | |
| if (!this.ticker) return; | |
| const marquee = this.ticker.querySelector('.animate-marquee'); | |
| if (!marquee) return; | |
| // Calculate animation duration based on content width | |
| const contentWidth = marquee.scrollWidth; | |
| const duration = contentWidth / 50; // Adjust speed as needed | |
| marquee.style.animationDuration = `${duration}s`; | |
| } | |
| } | |
| // Initialize price ticker when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', () => { | |
| new PriceTicker(); | |
| }); |