| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>DePIN & Web3 Best Sellers</title> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| :root { |
| --primary: #6e45e2; |
| --secondary: #88d3ce; |
| --dark: #1a1a2e; |
| --darker: #16213e; |
| --light: #f1f1f1; |
| --accent: #ff6b6b; |
| --success: #4ade80; |
| } |
| |
| * { |
| margin: 0; |
| padding: 0; |
| box-sizing: border-box; |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
| } |
| |
| body { |
| background-color: var(--dark); |
| color: var(--light); |
| min-height: 100vh; |
| } |
| |
| .container { |
| max-width: 1200px; |
| margin: 0 auto; |
| padding: 2rem; |
| } |
| |
| header { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| margin-bottom: 2rem; |
| padding-bottom: 1rem; |
| border-bottom: 1px solid rgba(255, 255, 255, 0.1); |
| } |
| |
| .logo { |
| display: flex; |
| align-items: center; |
| gap: 0.5rem; |
| } |
| |
| .logo i { |
| color: var(--primary); |
| font-size: 1.8rem; |
| } |
| |
| .logo h1 { |
| font-size: 1.5rem; |
| font-weight: 700; |
| background: linear-gradient(to right, var(--primary), var(--secondary)); |
| -webkit-background-clip: text; |
| background-clip: text; |
| color: transparent; |
| } |
| |
| .controls { |
| display: flex; |
| gap: 1rem; |
| } |
| |
| button { |
| background-color: var(--primary); |
| color: white; |
| border: none; |
| padding: 0.6rem 1.2rem; |
| border-radius: 0.5rem; |
| cursor: pointer; |
| font-weight: 600; |
| transition: all 0.3s ease; |
| display: flex; |
| align-items: center; |
| gap: 0.5rem; |
| } |
| |
| button:hover { |
| background-color: #5a35d1; |
| transform: translateY(-2px); |
| } |
| |
| button.secondary { |
| background-color: var(--darker); |
| color: var(--light); |
| } |
| |
| button.secondary:hover { |
| background-color: #1e2a5a; |
| } |
| |
| .search-bar { |
| display: flex; |
| margin-bottom: 2rem; |
| } |
| |
| .search-bar input { |
| flex: 1; |
| padding: 0.8rem 1rem; |
| border-radius: 0.5rem 0 0 0.5rem; |
| border: none; |
| background-color: var(--darker); |
| color: var(--light); |
| font-size: 1rem; |
| } |
| |
| .search-bar button { |
| border-radius: 0 0.5rem 0.5rem 0; |
| } |
| |
| .categories { |
| display: flex; |
| gap: 0.5rem; |
| margin-bottom: 2rem; |
| overflow-x: auto; |
| padding-bottom: 0.5rem; |
| } |
| |
| .category { |
| padding: 0.5rem 1rem; |
| background-color: var(--darker); |
| border-radius: 2rem; |
| cursor: pointer; |
| font-size: 0.9rem; |
| white-space: nowrap; |
| transition: all 0.3s ease; |
| } |
| |
| .category:hover, .category.active { |
| background-color: var(--primary); |
| color: white; |
| } |
| |
| .products-grid { |
| display: grid; |
| grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); |
| gap: 1.5rem; |
| } |
| |
| .product-card { |
| background-color: var(--darker); |
| border-radius: 0.8rem; |
| overflow: hidden; |
| transition: transform 0.3s ease, box-shadow 0.3s ease; |
| position: relative; |
| } |
| |
| .product-card:hover { |
| transform: translateY(-5px); |
| box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3); |
| } |
| |
| .product-image { |
| height: 180px; |
| background-color: #2a2a42; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| position: relative; |
| overflow: hidden; |
| } |
| |
| .product-image img { |
| width: 100%; |
| height: 100%; |
| object-fit: cover; |
| transition: transform 0.5s ease; |
| } |
| |
| .product-card:hover .product-image img { |
| transform: scale(1.05); |
| } |
| |
| .badge { |
| position: absolute; |
| top: 0.5rem; |
| left: 0.5rem; |
| background-color: var(--accent); |
| color: white; |
| padding: 0.2rem 0.5rem; |
| border-radius: 0.3rem; |
| font-size: 0.7rem; |
| font-weight: bold; |
| z-index: 2; |
| } |
| |
| .product-info { |
| padding: 1.2rem; |
| } |
| |
| .product-title { |
| font-size: 1.1rem; |
| margin-bottom: 0.5rem; |
| font-weight: 600; |
| display: -webkit-box; |
| -webkit-line-clamp: 2; |
| -webkit-box-orient: vertical; |
| overflow: hidden; |
| } |
| |
| .product-description { |
| color: rgba(255, 255, 255, 0.7); |
| font-size: 0.9rem; |
| margin-bottom: 1rem; |
| display: -webkit-box; |
| -webkit-line-clamp: 3; |
| -webkit-box-orient: vertical; |
| overflow: hidden; |
| } |
| |
| .product-footer { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| } |
| |
| .product-price { |
| font-weight: bold; |
| font-size: 1.2rem; |
| color: var(--secondary); |
| } |
| |
| .product-rating { |
| display: flex; |
| align-items: center; |
| gap: 0.3rem; |
| color: #ffc107; |
| font-size: 0.9rem; |
| } |
| |
| .loading { |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| height: 300px; |
| } |
| |
| .spinner { |
| width: 50px; |
| height: 50px; |
| border: 5px solid rgba(255, 255, 255, 0.1); |
| border-radius: 50%; |
| border-top-color: var(--primary); |
| animation: spin 1s ease-in-out infinite; |
| } |
| |
| @keyframes spin { |
| to { transform: rotate(360deg); } |
| } |
| |
| .empty-state { |
| text-align: center; |
| padding: 3rem; |
| color: rgba(255, 255, 255, 0.5); |
| } |
| |
| .empty-state i { |
| font-size: 3rem; |
| margin-bottom: 1rem; |
| color: var(--primary); |
| } |
| |
| .pagination { |
| display: flex; |
| justify-content: center; |
| gap: 0.5rem; |
| margin-top: 2rem; |
| } |
| |
| .pagination button { |
| min-width: 40px; |
| padding: 0.5rem; |
| display: flex; |
| justify-content: center; |
| } |
| |
| .pagination button.active { |
| background-color: var(--secondary); |
| color: var(--dark); |
| } |
| |
| .modal { |
| position: fixed; |
| top: 0; |
| left: 0; |
| right: 0; |
| bottom: 0; |
| background-color: rgba(0, 0, 0, 0.8); |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| z-index: 100; |
| opacity: 0; |
| pointer-events: none; |
| transition: opacity 0.3s ease; |
| } |
| |
| .modal.active { |
| opacity: 1; |
| pointer-events: all; |
| } |
| |
| .modal-content { |
| background-color: var(--darker); |
| border-radius: 0.8rem; |
| width: 90%; |
| max-width: 600px; |
| max-height: 90vh; |
| overflow-y: auto; |
| padding: 2rem; |
| position: relative; |
| transform: translateY(-20px); |
| transition: transform 0.3s ease; |
| } |
| |
| .modal.active .modal-content { |
| transform: translateY(0); |
| } |
| |
| .close-modal { |
| position: absolute; |
| top: 1rem; |
| right: 1rem; |
| background: none; |
| border: none; |
| color: var(--light); |
| font-size: 1.5rem; |
| cursor: pointer; |
| } |
| |
| .modal-title { |
| margin-bottom: 1.5rem; |
| color: var(--secondary); |
| } |
| |
| .modal-body { |
| line-height: 1.6; |
| } |
| |
| @media (max-width: 768px) { |
| .container { |
| padding: 1rem; |
| } |
| |
| header { |
| flex-direction: column; |
| gap: 1rem; |
| align-items: flex-start; |
| } |
| |
| .controls { |
| width: 100%; |
| justify-content: space-between; |
| } |
| |
| .products-grid { |
| grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); |
| } |
| } |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <header> |
| <div class="logo"> |
| <i class="fas fa-cube"></i> |
| <h1>DePIN Scout</h1> |
| </div> |
| <div class="controls"> |
| <button class="secondary" id="refresh-btn"> |
| <i class="fas fa-sync-alt"></i> |
| Refresh |
| </button> |
| <button id="about-btn"> |
| <i class="fas fa-info-circle"></i> |
| About |
| </button> |
| </div> |
| </header> |
|
|
| <div class="search-bar"> |
| <input type="text" id="search-input" placeholder="Search for DePIN or Web3 products..."> |
| <button id="search-btn"> |
| <i class="fas fa-search"></i> |
| Search |
| </button> |
| </div> |
|
|
| <div class="categories"> |
| <div class="category active" data-category="all">All Products</div> |
| <div class="category" data-category="depin">DePIN</div> |
| <div class="category" data-category="web3">Web3</div> |
| <div class="category" data-category="hardware">Hardware</div> |
| <div class="category" data-category="software">Software</div> |
| <div class="category" data-category="nft">NFTs</div> |
| <div class="category" data-category="defi">DeFi</div> |
| </div> |
|
|
| <div id="products-container"> |
| <div class="loading"> |
| <div class="spinner"></div> |
| </div> |
| </div> |
|
|
| <div class="pagination"> |
| <button id="prev-page" class="secondary"><i class="fas fa-chevron-left"></i></button> |
| <button class="active">1</button> |
| <button>2</button> |
| <button>3</button> |
| <button id="next-page"><i class="fas fa-chevron-right"></i></button> |
| </div> |
| </div> |
|
|
| <div class="modal" id="about-modal"> |
| <div class="modal-content"> |
| <button class="close-modal" id="close-modal">×</button> |
| <h2 class="modal-title">About DePIN Scout</h2> |
| <div class="modal-body"> |
| <p>DePIN Scout is a web application designed to help you discover the best-selling products in the decentralized physical infrastructure (DePIN) and Web3 space.</p> |
| <p>Our platform scrapes data from multiple sources to provide you with up-to-date information on trending products, their prices, ratings, and more.</p> |
| <p><strong>Features:</strong></p> |
| <ul> |
| <li>Real-time product scraping from top Web3 marketplaces</li> |
| <li>Comprehensive filtering by categories</li> |
| <li>Detailed product information</li> |
| <li>User-friendly interface with dark mode</li> |
| </ul> |
| <p>This is a demo application showcasing Web3 product discovery. Actual scraping functionality would require backend integration with appropriate APIs.</p> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', function() { |
| |
| const mockProducts = [ |
| { |
| id: 1, |
| title: "Helium Hotspot Miner", |
| description: "Decentralized wireless network hotspot for IoT devices. Earn HNT tokens by providing coverage.", |
| price: "$499", |
| rating: 4.7, |
| category: "depin", |
| image: "https://images.unsplash.com/photo-1639762681057-408e52192e55?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80", |
| badge: "BEST SELLER" |
| }, |
| { |
| id: 2, |
| title: "DIMO Vehicle Adapter", |
| description: "Connect your car to the DIMO network and earn rewards while maintaining full control of your data.", |
| price: "$129", |
| rating: 4.5, |
| category: "depin", |
| image: "https://images.unsplash.com/photo-1618843479313-40f8afb4b4d8?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80" |
| }, |
| { |
| id: 3, |
| title: "Ledger Nano X", |
| description: "Secure hardware wallet for your crypto assets with Bluetooth connectivity.", |
| price: "$149", |
| rating: 4.8, |
| category: "web3", |
| image: "https://images.unsplash.com/photo-1620891549027-942fdc95d3f5?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80", |
| badge: "TRENDING" |
| }, |
| { |
| id: 4, |
| title: "ENS Domain NFT", |
| description: "Secure your Ethereum Name Service domain as an NFT for decentralized identity.", |
| price: "0.01 ETH", |
| rating: 4.9, |
| category: "nft", |
| image: "https://images.unsplash.com/photo-1626514324486-cd62457098e3?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80" |
| }, |
| { |
| id: 5, |
| title: "Arweave Storage Node", |
| description: "Decentralized storage node for the permaweb. Earn AR tokens by providing storage.", |
| price: "$899", |
| rating: 4.6, |
| category: "depin", |
| image: "https://images.unsplash.com/photo-1626785774573-4b799315345d?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80" |
| }, |
| { |
| id: 6, |
| title: "MetaMask Swaps API", |
| description: "Developer API for integrating decentralized token swaps into your application.", |
| price: "Free + 0.3% fee", |
| rating: 4.4, |
| category: "software", |
| image: "https://images.unsplash.com/photo-1624953587687-daf255b6b80a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80" |
| }, |
| { |
| id: 7, |
| title: "Aave Staking Vault", |
| description: "Earn interest on your crypto assets through decentralized lending protocol.", |
| price: "0.5% APY", |
| rating: 4.7, |
| category: "defi", |
| image: "https://images.unsplash.com/photo-1639762681057-408e52192e55?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80" |
| }, |
| { |
| id: 8, |
| title: "Filecoin Storage Miner", |
| description: "Hardware for participating in the Filecoin decentralized storage network.", |
| price: "$1,299", |
| rating: 4.5, |
| category: "depin", |
| image: "https://images.unsplash.com/photo-1626785774573-4b799315345d?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80" |
| } |
| ]; |
| |
| |
| const productsContainer = document.getElementById('products-container'); |
| const searchInput = document.getElementById('search-input'); |
| const searchBtn = document.getElementById('search-btn'); |
| const refreshBtn = document.getElementById('refresh-btn'); |
| const categories = document.querySelectorAll('.category'); |
| const aboutBtn = document.getElementById('about-btn'); |
| const aboutModal = document.getElementById('about-modal'); |
| const closeModal = document.getElementById('close-modal'); |
| const prevPageBtn = document.getElementById('prev-page'); |
| const nextPageBtn = document.getElementById('next-page'); |
| const paginationBtns = document.querySelectorAll('.pagination button:not(#prev-page):not(#next-page)'); |
| |
| |
| let currentCategory = 'all'; |
| let currentSearch = ''; |
| let currentPage = 1; |
| const productsPerPage = 8; |
| |
| |
| displayProducts(mockProducts); |
| |
| |
| searchBtn.addEventListener('click', handleSearch); |
| searchInput.addEventListener('keypress', function(e) { |
| if (e.key === 'Enter') handleSearch(); |
| }); |
| |
| refreshBtn.addEventListener('click', function() { |
| |
| productsContainer.innerHTML = '<div class="loading"><div class="spinner"></div></div>'; |
| setTimeout(() => { |
| displayProducts(filterProducts(mockProducts, currentSearch, currentCategory)); |
| }, 1000); |
| }); |
| |
| categories.forEach(category => { |
| category.addEventListener('click', function() { |
| categories.forEach(c => c.classList.remove('active')); |
| this.classList.add('active'); |
| currentCategory = this.dataset.category; |
| displayProducts(filterProducts(mockProducts, currentSearch, currentCategory)); |
| }); |
| }); |
| |
| aboutBtn.addEventListener('click', () => aboutModal.classList.add('active')); |
| closeModal.addEventListener('click', () => aboutModal.classList.remove('active')); |
| aboutModal.addEventListener('click', (e) => { |
| if (e.target === aboutModal) aboutModal.classList.remove('active'); |
| }); |
| |
| |
| prevPageBtn.addEventListener('click', () => { |
| if (currentPage > 1) { |
| currentPage--; |
| updatePagination(); |
| displayProducts(filterProducts(mockProducts, currentSearch, currentCategory)); |
| } |
| }); |
| |
| nextPageBtn.addEventListener('click', () => { |
| const filteredProducts = filterProducts(mockProducts, currentSearch, currentCategory); |
| const totalPages = Math.ceil(filteredProducts.length / productsPerPage); |
| if (currentPage < totalPages) { |
| currentPage++; |
| updatePagination(); |
| displayProducts(filteredProducts); |
| } |
| }); |
| |
| paginationBtns.forEach(btn => { |
| btn.addEventListener('click', function() { |
| if (!this.classList.contains('active')) { |
| currentPage = parseInt(this.textContent); |
| updatePagination(); |
| displayProducts(filterProducts(mockProducts, currentSearch, currentCategory)); |
| } |
| }); |
| }); |
| |
| |
| function handleSearch() { |
| currentSearch = searchInput.value.trim().toLowerCase(); |
| currentPage = 1; |
| displayProducts(filterProducts(mockProducts, currentSearch, currentCategory)); |
| updatePagination(); |
| } |
| |
| function filterProducts(products, searchTerm, category) { |
| return products.filter(product => { |
| const matchesSearch = searchTerm === '' || |
| product.title.toLowerCase().includes(searchTerm) || |
| product.description.toLowerCase().includes(searchTerm); |
| |
| const matchesCategory = category === 'all' || product.category === category; |
| |
| return matchesSearch && matchesCategory; |
| }); |
| } |
| |
| function displayProducts(products) { |
| const startIndex = (currentPage - 1) * productsPerPage; |
| const endIndex = startIndex + productsPerPage; |
| const paginatedProducts = products.slice(startIndex, endIndex); |
| |
| if (paginatedProducts.length === 0) { |
| productsContainer.innerHTML = ` |
| <div class="empty-state"> |
| <i class="fas fa-search"></i> |
| <h3>No products found</h3> |
| <p>Try adjusting your search or filter criteria</p> |
| </div> |
| `; |
| return; |
| } |
| |
| let html = '<div class="products-grid">'; |
| |
| paginatedProducts.forEach(product => { |
| html += ` |
| <div class="product-card"> |
| <div class="product-image"> |
| <img src="${product.image}" alt="${product.title}"> |
| ${product.badge ? `<div class="badge">${product.badge}</div>` : ''} |
| </div> |
| <div class="product-info"> |
| <h3 class="product-title">${product.title}</h3> |
| <p class="product-description">${product.description}</p> |
| <div class="product-footer"> |
| <span class="product-price">${product.price}</span> |
| <span class="product-rating"> |
| <i class="fas fa-star"></i> |
| ${product.rating} |
| </span> |
| </div> |
| </div> |
| </div> |
| `; |
| }); |
| |
| html += '</div>'; |
| productsContainer.innerHTML = html; |
| } |
| |
| function updatePagination() { |
| const filteredProducts = filterProducts(mockProducts, currentSearch, currentCategory); |
| const totalPages = Math.ceil(filteredProducts.length / productsPerPage); |
| |
| |
| paginationBtns.forEach((btn, index) => { |
| if (index < totalPages) { |
| btn.style.display = 'flex'; |
| btn.textContent = index + 1; |
| btn.classList.toggle('active', index + 1 === currentPage); |
| } else { |
| btn.style.display = 'none'; |
| } |
| }); |
| |
| |
| prevPageBtn.disabled = currentPage === 1; |
| nextPageBtn.disabled = currentPage === totalPages; |
| } |
| }); |
| </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 <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> |
| </html> |