Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
<title>Music Stream Mine - Earn STRM Tokens</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
::-webkit-scrollbar { | |
width: 4px; | |
} | |
::-webkit-scrollbar-track { | |
background: #f1f1f1; | |
} | |
::-webkit-scrollbar-thumb { | |
background: #10b981; | |
border-radius: 3px; | |
} | |
::-webkit-scrollbar-thumb:hover { | |
background: #0d9f6e; | |
} | |
.music-card:hover { | |
transform: translateY(-2px); | |
} | |
.strm-bg { background-color: #10b981; } | |
* { | |
-webkit-user-select: none; | |
-moz-user-select: none; | |
-ms-user-select: none; | |
user-select: none; | |
} | |
@keyframes fadeIn { | |
from { opacity: 0; transform: translateY(10px); } | |
to { opacity: 1; transform: translateY(0); } | |
} | |
.explainer-animate { | |
animation: fadeIn 0.3s ease-out forwards; | |
} | |
.percentage-up { | |
color: #10b981; | |
} | |
.percentage-down { | |
color: #ef4444; | |
} | |
.percentage-neutral { | |
color: #6b7280; | |
} | |
.sentiment-positive { | |
background-color: rgba(16, 185, 129, 0.1); | |
border-left: 3px solid #10b981; | |
} | |
.sentiment-negative { | |
background-color: rgba(239, 68, 68, 0.1); | |
border-left: 3px solid #ef4444; | |
} | |
.sentiment-neutral { | |
background-color: rgba(156, 163, 175, 0.1); | |
border-left: 3px solid #9ca3af; | |
} | |
.sentiment-slider::-webkit-slider-thumb { | |
-webkit-appearance: none; | |
appearance: none; | |
width: 20px; | |
height: 20px; | |
border-radius: 50%; | |
cursor: pointer; | |
} | |
.sentiment-slider.positive::-webkit-slider-thumb { | |
background: #10b981; | |
} | |
.sentiment-slider.negative::-webkit-slider-thumb { | |
background: #ef4444; | |
} | |
.sentiment-slider.neutral::-webkit-slider-thumb { | |
background: #6b7280; | |
} | |
/* Floating button styles */ | |
.floating-btn { | |
position: fixed; | |
bottom: 80px; | |
right: 20px; | |
width: 50px; | |
height: 50px; | |
border-radius: 50%; | |
background-color: #10b981; | |
color: white; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); | |
z-index: 40; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
} | |
.floating-btn:hover { | |
transform: scale(1.1); | |
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); | |
} | |
/* Legend modal styles */ | |
.legend-item { | |
display: flex; | |
align-items: center; | |
margin-bottom: 12px; | |
} | |
.legend-icon { | |
width: 24px; | |
height: 24px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
margin-right: 12px; | |
flex-shrink: 0; | |
} | |
.verified-badge { | |
display: inline-flex; | |
align-items: center; | |
background-color: #10b981; | |
color: white; | |
padding: 2px 6px; | |
border-radius: 10px; | |
font-size: 10px; | |
margin-left: 5px; | |
} | |
.mining-animation { | |
animation: pulse 2s infinite; | |
} | |
@keyframes pulse { | |
0% { transform: scale(1); } | |
50% { transform: scale(1.05); } | |
100% { transform: scale(1); } | |
} | |
/* Mining difficulty adjustment */ | |
.mining-difficulty { | |
position: absolute; | |
bottom: 10px; | |
left: 10px; | |
font-size: 10px; | |
color: #6b7280; | |
} | |
</style> | |
</head> | |
<body class="bg-gray-50 font-sans text-gray-800"> | |
<!-- App Container --> | |
<div class="max-w-md mx-auto bg-white min-h-screen flex flex-col"> | |
<!-- Header --> | |
<header class="strm-bg p-4 shadow-sm"> | |
<div class="flex items-center justify-between"> | |
<h1 class="text-white text-xl font-bold">Music Stream Mine</h1> | |
<div class="flex items-center space-x-3"> | |
<button class="text-white" id="explainerBtn"> | |
<i class="fas fa-info-circle"></i> | |
</button> | |
<button class="text-white" id="strmBalanceBtn"> | |
<span id="strmBalanceDisplay">0 STRM</span> | |
</button> | |
</div> | |
</div> | |
</header> | |
<!-- Main Content Area --> | |
<main class="flex-1 overflow-y-auto p-4" id="mainContent"> | |
<!-- Home Tab Content --> | |
<div id="homeTab"> | |
<div class="mb-6"> | |
<h2 class="text-lg font-semibold mb-4">Music Streaming Pools</h2> | |
<div class="grid grid-cols-1 gap-4" id="streamingPoolsContainer"> | |
<!-- Cards will be dynamically inserted here --> | |
</div> | |
</div> | |
<div class="mt-6"> | |
<div class="flex items-center justify-between mb-4"> | |
<h2 class="text-lg font-semibold">Your Staked Pools</h2> | |
<button id="stakeInfoBtn" class="text-xs text-strm-bg font-medium flex items-center"> | |
<i class="fas fa-question-circle mr-1"></i> How mining works | |
</button> | |
</div> | |
<div class="space-y-3" id="stakedPoolsContainer"> | |
<!-- Staked pools will appear here --> | |
</div> | |
</div> | |
</div> | |
<!-- Search Tab Content (hidden by default) --> | |
<div id="searchTab" class="hidden"> | |
<div class="mb-4"> | |
<div class="relative"> | |
<input type="text" id="poolSearchInput" placeholder="Search music streaming pools..." | |
class="w-full py-3 px-4 rounded-lg bg-gray-100 focus:outline-none focus:ring-2 focus:ring-strm-bg"> | |
<button id="searchPoolBtn" class="absolute right-3 top-3 text-gray-500 hover:text-strm-bg"> | |
<i class="fas fa-search"></i> | |
</button> | |
</div> | |
</div> | |
<div class="grid grid-cols-1 gap-4" id="searchResultsContainer"> | |
<!-- Search results will appear here --> | |
</div> | |
</div> | |
</main> | |
<!-- Bottom Navigation --> | |
<nav class="bg-white border-t border-gray-200 p-2"> | |
<div class="flex justify-around"> | |
<button class="tab-button active flex flex-col items-center text-strm-bg" data-tab="homeTab"> | |
<i class="fas fa-home text-lg"></i> | |
<span class="text-xs mt-1">Home</span> | |
</button> | |
<button class="tab-button flex flex-col items-center text-gray-500" data-tab="searchTab"> | |
<i class="fas fa-search text-lg"></i> | |
<span class="text-xs mt-1">Search</span> | |
</button> | |
<button class="flex flex-col items-center text-gray-500" id="addPoolBtn"> | |
<i class="fas fa-plus-circle text-lg"></i> | |
<span class="text-xs mt-1">Add</span> | |
</button> | |
</div> | |
</nav> | |
<!-- Floating Mining Button --> | |
<div class="floating-btn mining-animation" id="miningBtn"> | |
<i class="fas fa-digging"></i> | |
<div class="mining-difficulty">D: 1.0</div> | |
</div> | |
<!-- Add Pool Modal (hidden by default) --> | |
<div id="addPoolModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
<div class="bg-white rounded-lg w-full max-w-md mx-4"> | |
<div class="p-4 border-b border-gray-200"> | |
<h3 class="font-semibold text-lg">Add New Streaming Pool</h3> | |
</div> | |
<div class="p-4"> | |
<div class="mb-4"> | |
<label class="block text-sm font-medium text-gray-700 mb-1">Artist/Playlist</label> | |
<input type="text" id="newPoolName" placeholder="Artist or playlist name" | |
class="w-full py-2 px-4 rounded-lg bg-gray-100 focus:outline-none focus:ring-2 focus:ring-strm-bg"> | |
</div> | |
<div class="mb-4"> | |
<label class="block text-sm font-medium text-gray-700 mb-1">Music Category</label> | |
<div class="grid grid-cols-2 gap-2"> | |
<button class="platform-btn bg-gray-200 text-gray-700 py-2 px-3 rounded text-sm" data-platform="pop"> | |
<i class="fas fa-music mr-1 text-purple-500"></i> Pop | |
</button> | |
<button class="platform-btn bg-gray-200 text-gray-700 py-2 px-3 rounded text-sm" data-platform="rock"> | |
<i class="fas fa-guitar mr-1 text-yellow-500"></i> Rock | |
</button> | |
<button class="platform-btn bg-gray-200 text-gray-700 py-2 px-3 rounded text-sm" data-platform="electronic"> | |
<i class="fas fa-sliders-h mr-1 text-blue-500"></i> Electronic | |
</button> | |
<button class="platform-btn bg-gray-200 text-gray-700 py-2 px-3 rounded text-sm" data-platform="classical"> | |
<i class="fas fa-viola mr-1 text-green-500"></i> Classical | |
</button> | |
</div> | |
</div> | |
</div> | |
<div class="p-4 border-t border-gray-200 flex justify-end space-x-3"> | |
<button id="cancelAddPool" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700"> | |
Cancel | |
</button> | |
<button id="savePool" class="px-4 py-2 strm-bg text-white rounded-md text-sm font-medium"> | |
Create Pool | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- STRM Token Modal (hidden by default) --> | |
<div id="strmModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
<div class="bg-white rounded-lg w-full max-w-md mx-4"> | |
<div class="p-4 border-b border-gray-200 flex justify-between items-center"> | |
<h3 class="font-semibold text-lg">STRM Token</h3> | |
<span class="verified-badge"> | |
<i class="fas fa-check-circle mr-1"></i> Verified | |
</span> | |
</div> | |
<div class="p-4"> | |
<div class="flex items-center mb-4"> | |
<div class="w-12 h-12 rounded-full strm-bg text-white flex items-center justify-center mr-3"> | |
<i class="fas fa-music text-xl"></i> | |
</div> | |
<div> | |
<h4 class="font-medium">Bitcoin Cash CHIP Protocol</h4> | |
<p class="text-sm text-gray-500">Mining Pool: 5,000,000 STRM</p> | |
</div> | |
</div> | |
<div class="mb-4"> | |
<p class="text-sm text-gray-700 mb-3"> | |
STRM is a private cryptocurrency token on the Bitcoin Cash network using the CHIP protocol. | |
Mine STRM tokens by staking to music streaming pools. Total supply: 5,000,000 STRM. | |
</p> | |
<div class="space-y-2"> | |
<a href="https://tokenexplorer.cash/?tokenId=8874186362dd0510af5e26c4321c2a335f7089cfc1a70fcd9e4efb63a49d2a76" target="_blank" class="flex items-center text-blue-500 text-sm"> | |
<i class="fas fa-external-link-alt mr-2"></i> View on Token Explorer | |
</a> | |
<a href="https://app.cauldron.quest/swap/8874186362dd0510af5e26c4321c2a335f7089cfc1a70fcd9e4efb63a49d2a76" target="_blank" class="flex items-center text-blue-500 text-sm"> | |
<i class="fas fa-exchange-alt mr-2"></i> Swap on Cauldron | |
</a> | |
<a href="https://blockchair.com/bitcoin-cash/transaction/8874186362dd0510af5e26c4321c2a335f7089cfc1a70fcd9e4efb63a49d2a76" target="_blank" class="flex items-center text-blue-500 text-sm"> | |
<i class="fas fa-link mr-2"></i> View Transaction | |
</a> | |
</div> | |
</div> | |
<div class="bg-gray-100 rounded-lg p-3 mb-4"> | |
<h4 class="font-medium text-sm mb-2">Your STRM Balance</h4> | |
<div class="flex justify-between items-center"> | |
<span class="font-medium" id="strmBalance">0 STRM</span> | |
<button id="addStrmBtn" class="text-sm text-strm-bg font-medium"> | |
<i class="fas fa-plus-circle mr-1"></i> Add STRM | |
</button> | |
</div> | |
</div> | |
<div class="bg-gray-100 rounded-lg p-3"> | |
<h4 class="font-medium text-sm mb-2">Stake STRM to Pool</h4> | |
<div class="mb-2"> | |
<select id="poolSelect" class="w-full p-2 rounded border border-gray-300 text-sm"> | |
<option value="">-- Select a pool --</option> | |
</select> | |
</div> | |
<div class="mb-2"> | |
<input type="number" id="stakeAmount" placeholder="STRM amount" class="w-full p-2 rounded border border-gray-300 text-sm"> | |
</div> | |
<button id="stakeBtn" class="w-full py-2 strm-bg text-white rounded-lg text-sm font-medium"> | |
Stake & Start Mining | |
</button> | |
</div> | |
</div> | |
<div class="p-4 border-t border-gray-200 flex justify-center"> | |
<button id="closeStrmModal" class="px-4 py-2 strm-bg text-white rounded-md text-sm font-medium"> | |
Close | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Explainer Modal (hidden by default) --> | |
<div id="explainerModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
<div class="bg-white rounded-lg w-full max-w-md mx-4 explainer-animate"> | |
<div class="p-4 border-b border-gray-200 flex justify-between items-center"> | |
<h3 class="font-semibold text-lg">Music Stream Mining</h3> | |
<button id="closeExplainerModal" class="text-gray-500 hover:text-strm-bg"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<div class="p-4 overflow-y-auto max-h-[70vh]"> | |
<div class="mb-6"> | |
<div class="flex items-start mb-4"> | |
<div class="w-10 h-10 rounded-full strm-bg text-white flex items-center justify-center mr-3 flex-shrink-0"> | |
<i class="fas fa-chart-pie"></i> | |
</div> | |
<div> | |
<h4 class="font-medium mb-1">Bitcoin Cash Mining Algorithm</h4> | |
<p class="text-sm text-gray-700"> | |
Our mining algorithm is based on Bitcoin Cash's SHA-256 proof-of-work with difficulty adjustment. | |
The total supply is capped at 5,000,000 STRM tokens with halving every 4 years. | |
</p> | |
</div> | |
</div> | |
<div class="flex items-start mb-4"> | |
<div class="w-10 h-10 rounded-full strm-bg text-white flex items-center justify-center mr-3 flex-shrink-0"> | |
<i class="fas fa-percentage"></i> | |
</div> | |
<div> | |
<h4 class="font-medium mb-1">Mining Difficulty</h4> | |
<p class="text-sm text-gray-700"> | |
Mining difficulty adjusts every 2016 blocks (approx. 2 weeks) to maintain a consistent block time. | |
Current difficulty is displayed on the mining button. | |
</p> | |
</div> | |
</div> | |
<div class="flex items-start mb-4"> | |
<div class="w-10 h-10 rounded-full strm-bg text-white flex items-center justify-center mr-3 flex-shrink-0"> | |
<i class="fas fa-tags"></i> | |
</div> | |
<div> | |
<h4 class="font-medium mb-1">Music Categories</h4> | |
<p class="text-sm text-gray-700"> | |
We track four main music categories: Pop, Rock, Electronic, and Classical. | |
Each pool is classified into one of these categories for mining calculation. | |
</p> | |
</div> | |
</div> | |
<div class="flex items-start mb-4"> | |
<div class="w-10 h-10 rounded-full strm-bg text-white flex items-center justify-center mr-3 flex-shrink-0"> | |
<i class="fas fa-coins"></i> | |
</div> | |
<div> | |
<h4 class="font-medium mb-1">Mining Rewards</h4> | |
<p class="text-sm text-gray-700"> | |
Current block reward is 6.25 STRM per block. The more you stake and the more streams | |
the pool gets, the higher your share of the rewards. Rewards are distributed daily. | |
</p> | |
</div> | |
</div> | |
<div class="bg-blue-50 border border-blue-100 rounded-lg p-3"> | |
<div class="flex"> | |
<div class="text-blue-500 mr-2"> | |
<i class="fas fa-lightbulb"></i> | |
</div> | |
<p class="text-sm text-blue-800"> | |
<strong>Pro Tip:</strong> Look for emerging artists with small but rapidly increasing streams. | |
These often provide the best mining opportunities with lower difficulty. | |
</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="p-4 border-t border-gray-200 flex justify-center"> | |
<button id="closeExplainerBtn" class="px-4 py-2 strm-bg text-white rounded-md text-sm font-medium"> | |
Got It! | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Mining Modal (hidden by default) --> | |
<div id="miningModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
<div class="bg-white rounded-lg w-full max-w-md mx-4"> | |
<div class="p-4 border-b border-gray-200"> | |
<h3 class="font-semibold text-lg">Mining Status</h3> | |
</div> | |
<div class="p-4"> | |
<div class="flex flex-col items-center mb-4"> | |
<div class="w-20 h-20 rounded-full strm-bg text-white flex items-center justify-center mb-4"> | |
<i class="fas fa-digging text-3xl"></i> | |
</div> | |
<h4 class="font-medium mb-2" id="miningPoolName">Pop Hits 2023</h4> | |
<p class="text-sm text-gray-600 mb-4">Currently mining STRM tokens</p> | |
<div class="w-full bg-gray-200 rounded-full h-2.5 mb-4"> | |
<div class="bg-strm-bg h-2.5 rounded-full" style="width: 45%"></div> | |
</div> | |
<div class="grid grid-cols-3 gap-4 w-full text-center mb-4"> | |
<div> | |
<p class="text-sm text-gray-500">Staked</p> | |
<p class="font-medium" id="miningStaked">500 STRM</p> | |
</div> | |
<div> | |
<p class="text-sm text-gray-500">Earned</p> | |
<p class="font-medium" id="miningEarned">1.5 STRM</p> | |
</div> | |
<div> | |
<p class="text-sm text-gray-500">Difficulty</p> | |
<p class="font-medium" id="miningDifficulty">1.0</p> | |
</div> | |
</div> | |
<div class="w-full bg-gray-100 rounded-lg p-3 text-center"> | |
<p class="text-xs text-gray-600 mb-1">Estimated Hashrate: <span id="miningHashrate">12.5 TH/s</span></p> | |
<p class="text-xs text-gray-600">Next Difficulty Adjustment: <span id="nextDifficulty">2016 blocks</span></p> | |
</div> | |
</div> | |
</div> | |
<div class="p-4 border-t border-gray-200 flex justify-end space-x-3"> | |
<button id="stopMiningBtn" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700"> | |
Stop Mining | |
</button> | |
<button id="claimMiningBtn" class="px-4 py-2 strm-bg text-white rounded-md text-sm font-medium"> | |
Claim Rewards | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Toast Notification (hidden by default) --> | |
<div id="toast" class="fixed bottom-20 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white px-4 py-2 rounded-md shadow-lg hidden z-50"> | |
<div class="flex items-center"> | |
<span id="toastMessage">Pool created successfully</span> | |
</div> | |
</div> | |
</div> | |
<script> | |
// Music categories and sample data (removed hip hop) | |
const musicCategories = { | |
pop: { | |
name: "Pop", | |
icon: '<i class="fas fa-music text-purple-500"></i>', | |
color: 'bg-purple-500', | |
totalStreams: 25000000, | |
pools: [ | |
{ name: "Pop Hits 2023", currentStreams: 6000000, previousStreams: 5500000, sentiment: 0 }, | |
{ name: "Top 40 Global", currentStreams: 5000000, previousStreams: 4800000, sentiment: 0 }, | |
{ name: "Taylor Swift Radio", currentStreams: 3000000, previousStreams: 2800000, sentiment: 0 }, | |
{ name: "Weekend Party Mix", currentStreams: 2000000, previousStreams: 1900000, sentiment: 0 } | |
] | |
}, | |
rock: { | |
name: "Rock", | |
icon: '<i class="fas fa-guitar text-yellow-500"></i>', | |
color: 'bg-yellow-500', | |
totalStreams: 12000000, | |
pools: [ | |
{ name: "Classic Rock", currentStreams: 4000000, previousStreams: 4100000, sentiment: 0 }, | |
{ name: "Alternative Rock", currentStreams: 3000000, previousStreams: 2900000, sentiment: 0 }, | |
{ name: "Metal Essentials", currentStreams: 2000000, previousStreams: 2100000, sentiment: 0 }, | |
{ name: "Indie Rock", currentStreams: 1500000, previousStreams: 1400000, sentiment: 0 } | |
] | |
}, | |
electronic: { | |
name: "Electronic", | |
icon: '<i class="fas fa-sliders-h text-blue-500"></i>', | |
color: 'bg-blue-500', | |
totalStreams: 15000000, | |
pools: [ | |
{ name: "EDM Bangers", currentStreams: 4000000, previousStreams: 3800000, sentiment: 0 }, | |
{ name: "Deep House", currentStreams: 3000000, previousStreams: 2900000, sentiment: 0 }, | |
{ name: "Techno Workout", currentStreams: 2500000, previousStreams: 2400000, sentiment: 0 }, | |
{ name: "Drum & Bass", currentStreams: 2000000, previousStreams: 2100000, sentiment: 0 } | |
] | |
}, | |
classical: { | |
name: "Classical", | |
icon: '<i class="fas fa-viola text-green-500"></i>', | |
color: 'bg-green-500', | |
totalStreams: 8000000, | |
pools: [ | |
{ name: "Mozart Essentials", currentStreams: 2000000, previousStreams: 2100000, sentiment: 0 }, | |
{ name: "Piano Relaxation", currentStreams: 1500000, previousStreams: 1400000, sentiment: 0 }, | |
{ name: "Opera Highlights", currentStreams: 1200000, previousStreams: 1300000, sentiment: 0 }, | |
{ name: "Film Scores", currentStreams: 1000000, previousStreams: 900000, sentiment: 0 } | |
] | |
} | |
}; | |
// Calculate total streams across all categories | |
const totalAllStreams = Object.values(musicCategories).reduce((total, category) => total + category.totalStreams, 0); | |
// Bitcoin Cash mining parameters | |
const miningParams = { | |
totalSupply: 5000000, // 5 million STRM total supply | |
currentSupply: 0, // Start with 0 mined | |
blockReward: 6.25, // Initial block reward (halves every 4 years) | |
blocksUntilHalving: 210000, // Halving every ~4 years (BCH halving schedule) | |
difficulty: 1.0, // Initial difficulty | |
blocksUntilDifficultyAdjustment: 2016, // Adjust every 2016 blocks (BCH schedule) | |
blockTimeTarget: 600, // 10 minute target block time (same as BCH) | |
lastBlockTime: Date.now(), // Timestamp of last block | |
hashrate: 0 // Current network hashrate | |
}; | |
// User data | |
let userData = { | |
strmBalance: 5000, | |
stakedPools: [ | |
{ | |
name: "Pop Hits 2023", | |
platform: "pop", | |
hasStrm: true, | |
stakedAmount: 1000, | |
sentiment: 0, | |
earned: 3.2, | |
mining: true, | |
hashrate: 12.5 // TH/s | |
}, | |
{ | |
name: "EDM Bangers", | |
platform: "electronic", | |
hasStrm: true, | |
stakedAmount: 500, | |
sentiment: 0, | |
earned: 1.5, | |
mining: true, | |
hashrate: 6.25 // TH/s | |
} | |
] | |
}; | |
// Current pool being mined | |
let currentMiningPool = null; | |
let miningInterval = null; | |
// Function to calculate market share percentage with sentiment adjustment | |
function calculateMarketShare(poolName) { | |
// Find the pool in our categories | |
let poolData = null; | |
let category = null; | |
for (const [cat, data] of Object.entries(musicCategories)) { | |
const foundPool = data.pools.find(p => p.name === poolName); | |
if (foundPool) { | |
poolData = foundPool; | |
category = cat; | |
break; | |
} | |
} | |
// If pool not found in predefined data, check user staked pools | |
if (!poolData || !category) { | |
const stakedPool = userData.stakedPools.find(p => p.name === poolName); | |
if (stakedPool) { | |
category = stakedPool.platform; | |
// Create a zero entry with sentiment from staked pool | |
return { | |
percentage: 0, | |
change: 0, | |
category: category, | |
sentiment: stakedPool.sentiment || 0 | |
}; | |
} | |
// Default to pop for new pools | |
return { | |
percentage: 0, | |
change: 0, | |
category: "pop", | |
sentiment: 0 | |
}; | |
} | |
// Calculate percentage of category streams | |
const categoryPercentage = (poolData.currentStreams / musicCategories[category].totalStreams) * 100; | |
// Calculate percentage of all music streams | |
const globalPercentage = (poolData.currentStreams / totalAllStreams) * 100; | |
// Calculate raw percentage change from previous period | |
const rawChange = poolData.previousStreams > 0 | |
? ((poolData.currentStreams - poolData.previousStreams) / poolData.previousStreams) * 100 | |
: poolData.currentStreams > 0 ? 100 : 0; | |
// Apply sentiment adjustment (0-100 scale mapped to 0.5-1.5 multiplier) | |
const sentimentMultiplier = 1 + (poolData.sentiment / 200); // Maps -100 to 0.5, 0 to 1, 100 to 1.5 | |
const adjustedChange = rawChange * sentimentMultiplier; | |
return { | |
percentage: globalPercentage.toFixed(2), | |
change: adjustedChange.toFixed(2), | |
rawChange: rawChange.toFixed(2), | |
category: category, | |
sentiment: poolData.sentiment || 0 | |
}; | |
} | |
// Function to get percentage change class | |
function getPercentageClass(change) { | |
const numChange = parseFloat(change); | |
if (numChange > 0) return 'percentage-up'; | |
if (numChange < 0) return 'percentage-down'; | |
return 'percentage-neutral'; | |
} | |
// Function to get sentiment class | |
function getSentimentClass(sentiment) { | |
const numSentiment = parseInt(sentiment); | |
if (numSentiment > 20) return 'sentiment-positive'; | |
if (numSentiment < -20) return 'sentiment-negative'; | |
return 'sentiment-neutral'; | |
} | |
// Function to get sentiment label | |
function getSentimentLabel(sentiment) { | |
const numSentiment = parseInt(sentiment); | |
if (numSentiment > 20) return 'Positive'; | |
if (numSentiment < -20) return 'Negative'; | |
return 'Neutral'; | |
} | |
// Function to generate platform icon | |
function getPlatformIcon(platform) { | |
const icons = { | |
pop: '<i class="fas fa-music text-purple-500"></i>', | |
rock: '<i class="fas fa-guitar text-yellow-500"></i>', | |
electronic: '<i class="fas fa-sliders-h text-blue-500"></i>', | |
classical: '<i class="fas fa-viola text-green-500"></i>' | |
}; | |
return icons[platform] || '<i class="fas fa-music"></i>'; | |
} | |
// Function to render streaming pools | |
function renderStreamingPools() { | |
const container = document.getElementById('streamingPoolsContainer'); | |
container.innerHTML = ''; | |
// Get all pools from all categories | |
const allPools = []; | |
Object.values(musicCategories).forEach(category => { | |
category.pools.forEach(pool => { | |
allPools.push({ | |
...pool, | |
category: category.name.toLowerCase() | |
}); | |
}); | |
}); | |
// Sort by current streams (descending) | |
allPools.sort((a, b) => b.currentStreams - a.currentStreams); | |
// Take top 8 pools | |
const topPools = allPools.slice(0, 8); | |
topPools.forEach(item => { | |
const marketShare = calculateMarketShare(item.name); | |
const percentageClass = getPercentageClass(marketShare.change); | |
const sentimentClass = getSentimentClass(marketShare.sentiment); | |
const card = document.createElement('div'); | |
card.className = `music-card bg-white rounded-lg shadow-sm p-4 h-40 flex flex-col justify-between transition cursor-pointer ${sentimentClass}`; | |
card.innerHTML = ` | |
<div class="flex items-start justify-between mb-2"> | |
<div> | |
<span class="inline-flex items-center bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full"> | |
${getPlatformIcon(item.category)} | |
<span class="ml-1">${item.name}</span> | |
</span> | |
</div> | |
<span class="inline-flex items-center bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full"> | |
<i class="fas fa-chart-line ${percentageClass} mr-1"></i> | |
${marketShare.percentage}% | |
<span class="ml-1 ${percentageClass}">(${marketShare.change > 0 ? '+' : ''}${marketShare.change}%)</span> | |
</span> | |
</div> | |
<div class="flex justify-between items-center mb-3"> | |
<span class="text-xs text-gray-500">${item.currentStreams.toLocaleString()} streams</span> | |
<span class="text-xs px-2 py-1 rounded-full ${musicCategories[item.category].color} text-white"> | |
${musicCategories[item.category].name} | |
</span> | |
</div> | |
<div class="flex justify-between items-center text-xs text-gray-500"> | |
<span> | |
<span class="${getSentimentClass(marketShare.sentiment).replace('sentiment-', 'text-')}"> | |
<i class="fas ${marketShare.sentiment > 20 ? 'fa-smile' : marketShare.sentiment < -20 ? 'fa-frown' : 'fa-meh'}"></i> | |
${getSentimentLabel(marketShare.sentiment)} | |
</span> | |
</span> | |
<button class="stake-pool-btn text-gray-400 hover:text-strm-bg" data-pool="${item.name}" data-platform="${item.category}"> | |
<i class="fas fa-coins"></i> Stake | |
</button> | |
</div> | |
`; | |
container.appendChild(card); | |
// Add click event to open mining modal | |
card.addEventListener('click', function() { | |
openMiningModal(item.name, item.category); | |
}); | |
}); | |
// Add event listeners to stake buttons | |
document.querySelectorAll('.stake-pool-btn').forEach(btn => { | |
btn.addEventListener('click', function(e) { | |
e.stopPropagation(); | |
const poolName = this.getAttribute('data-pool'); | |
const platform = this.getAttribute('data-platform'); | |
stakePool(poolName, platform); | |
}); | |
}); | |
} | |
// Function to render staked pools | |
function renderStakedPools() { | |
const container = document.getElementById('stakedPoolsContainer'); | |
container.innerHTML = ''; | |
// Update select dropdown | |
const poolSelect = document.getElementById('poolSelect'); | |
poolSelect.innerHTML = '<option value="">-- Select a pool --</option>'; | |
userData.stakedPools.forEach(pool => { | |
const marketShare = calculateMarketShare(pool.name); | |
const percentageClass = getPercentageClass(marketShare.change); | |
const sentimentClass = getSentimentClass(pool.sentiment); | |
const element = document.createElement('div'); | |
element.className = `flex items-center p-3 rounded-lg bg-white shadow-sm cursor-pointer hover:bg-gray-50 ${sentimentClass}`; | |
element.innerHTML = ` | |
<div class="flex-shrink-0 mr-3"> | |
<div class="w-8 h-8 rounded-full flex items-center justify-center text-white ${musicCategories[pool.platform].color}"> | |
${getPlatformIcon(pool.platform)} | |
</div> | |
</div> | |
<div class="flex-1"> | |
<div class="flex items-center"> | |
<h4 class="font-medium text-sm">${pool.name}</h4> | |
${pool.hasStrm ? '<span class="ml-1 text-green-500"><i class="fas fa-check-circle"></i></span>' : ''} | |
${pool.mining ? '<span class="ml-1 text-green-500"><i class="fas fa-digging"></i></span>' : ''} | |
</div> | |
<div class="flex items-center"> | |
<p class="text-gray-500 text-xs mr-2">${musicCategories[pool.platform].name}</p> | |
<span class="text-xs ${percentageClass}"> | |
${marketShare.percentage}% (${marketShare.change > 0 ? '+' : ''}${marketShare.change}%) | |
</span> | |
</div> | |
</div> | |
<div class="text-right"> | |
<p class="text-xs font-medium">${pool.stakedAmount} STRM</p> | |
<p class="text-xs text-green-500">+${pool.earned} STRM</p> | |
</div> | |
`; | |
container.appendChild(element); | |
// Add to select dropdown | |
const option = document.createElement('option'); | |
option.value = pool.name; | |
option.textContent = pool.name; | |
poolSelect.appendChild(option); | |
// Add click event to open mining modal | |
element.addEventListener('click', function() { | |
openMiningModal(pool.name, pool.platform); | |
}); | |
}); | |
// Update STRM balance display | |
document.getElementById('strmBalance').textContent = userData.strmBalance + ' STRM'; | |
document.getElementById('strmBalanceDisplay').textContent = userData.strmBalance + ' STRM'; | |
// Update mining difficulty display | |
document.querySelector('.mining-difficulty').textContent = `D: ${miningParams.difficulty.toFixed(1)}`; | |
} | |
// Function to open mining modal | |
function openMiningModal(poolName, platform) { | |
currentMiningPool = poolName; | |
// Find the pool data | |
let poolData = null; | |
for (const category of Object.values(musicCategories)) { | |
const foundPool = category.pools.find(p => p.name === poolName); | |
if (foundPool) { | |
poolData = foundPool; | |
break; | |
} | |
} | |
// If not found in categories, check staked pools | |
if (!poolData) { | |
const stakedPool = userData.stakedPools.find(p => p.name === poolName); | |
if (stakedPool) { | |
poolData = stakedPool; | |
} | |
} | |
// Set modal content | |
document.getElementById('miningPoolName').textContent = poolName; | |
document.getElementById('miningStaked').textContent = poolData?.stakedAmount + ' STRM'; | |
document.getElementById('miningEarned').textContent = poolData?.earned + ' STRM'; | |
document.getElementById('miningDifficulty').textContent = miningParams.difficulty.toFixed(1); | |
document.getElementById('miningHashrate').textContent = poolData?.hashrate ? poolData.hashrate + ' TH/s' : '0 TH/s'; | |
document.getElementById('nextDifficulty').textContent = miningParams.blocksUntilDifficultyAdjustment + ' blocks'; | |
// Show modal | |
document.getElementById('miningModal').classList.remove('hidden'); | |
} | |
// Function to show search results | |
function showSearchResults(query) { | |
const container = document.getElementById('searchResultsContainer'); | |
container.innerHTML = ''; | |
if (!query) return; | |
// Simulate search with timeout | |
setTimeout(() => { | |
// Search across all categories | |
const results = []; | |
const queryLower = query.toLowerCase(); | |
// First check exact matches | |
Object.values(musicCategories).forEach(category => { | |
category.pools.forEach(pool => { | |
if (pool.name.toLowerCase().includes(queryLower)) { | |
results.push({ | |
...pool, | |
platform: category.name.toLowerCase() | |
}); | |
} | |
}); | |
}); | |
// If no exact matches, check category names | |
if (results.length === 0) { | |
Object.entries(musicCategories).forEach(([key, category]) => { | |
if (category.name.toLowerCase().includes(queryLower)) { | |
results.push(...category.pools.slice(0, 3).map(p => ({ | |
...p, | |
platform: key | |
}))); | |
} | |
}); | |
} | |
// If still no results, create a new "pop" pool | |
if (results.length === 0) { | |
const newPool = { | |
name: query.charAt(0).toUpperCase() + query.slice(1), | |
currentStreams: 10000, // Default small number for new pools | |
previousStreams: 0, | |
platform: "pop", | |
sentiment: 0 | |
}; | |
results.push(newPool); | |
// Add to pop category | |
musicCategories.pop.pools.push(newPool); | |
musicCategories.pop.totalStreams += newPool.currentStreams; | |
} | |
// Display results | |
results.forEach(item => { | |
const marketShare = calculateMarketShare(item.name); | |
const percentageClass = getPercentageClass(marketShare.change); | |
const sentimentClass = getSentimentClass(marketShare.sentiment); | |
const card = document.createElement('div'); | |
card.className = `music-card bg-white rounded-lg shadow-sm p-4 h-40 flex flex-col justify-between transition cursor-pointer ${sentimentClass}`; | |
card.innerHTML = ` | |
<div class="flex items-start justify-between mb-2"> | |
<div> | |
<span class="inline-flex items-center bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full"> | |
${getPlatformIcon(item.platform)} | |
<span class="ml-1">${item.name}</span> | |
</span> | |
</div> | |
<span class="inline-flex items-center bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full"> | |
<i class="fas fa-chart-line ${percentageClass} mr-1"></i> | |
${marketShare.percentage}% | |
<span class="ml-1 ${percentageClass}">(${marketShare.change > 0 ? '+' : ''}${marketShare.change}%)</span> | |
</span> | |
</div> | |
<div class="flex justify-between items-center mb-3"> | |
<span class="text-xs text-gray-500">${item.currentStreams.toLocaleString()} streams</span> | |
<span class="text-xs px-2 py-1 rounded-full ${musicCategories[item.platform].color} text-white"> | |
${musicCategories[item.platform].name} | |
</span> | |
</div> | |
<div class="flex justify-between items-center text-xs text-gray-500"> | |
<span> | |
<span class="${getSentimentClass(marketShare.sentiment).replace('sentiment-', 'text-')}"> | |
<i class="fas ${marketShare.sentiment > 20 ? 'fa-smile' : marketShare.sentiment < -20 ? 'fa-frown' : 'fa-meh'}"></i> | |
${getSentimentLabel(marketShare.sentiment)} | |
</span> | |
</span> | |
<button class="stake-pool-btn text-gray-400 hover:text-strm-bg" data-pool="${item.name}" data-platform="${item.platform}"> | |
<i class="fas fa-coins"></i> Stake | |
</button> | |
</div> | |
`; | |
container.appendChild(card); | |
// Add click event to open mining modal | |
card.addEventListener('click', function() { | |
openMiningModal(item.name, item.platform); | |
}); | |
}); | |
// Add event listeners to stake buttons | |
document.querySelectorAll('.stake-pool-btn').forEach(btn => { | |
btn.addEventListener('click', function(e) { | |
e.stopPropagation(); | |
const poolName = this.getAttribute('data-pool'); | |
const platform = this.getAttribute('data-platform'); | |
stakePool(poolName, platform); | |
}); | |
}); | |
showToast(`Found ${results.length} results for ${query}`); | |
}, 1000); | |
} | |
// Function to stake to a pool | |
function stakePool(poolName, platform) { | |
// Check if already staked | |
if (userData.stakedPools.some(p => p.name === poolName)) { | |
showToast('You already have STRM staked to this pool'); | |
return; | |
} | |
// Add to staked pools | |
userData.stakedPools.push({ | |
name: poolName, | |
platform, | |
hasStrm: true, | |
stakedAmount: 0, | |
sentiment: 0, | |
earned: 0, | |
mining: false, | |
hashrate: 0 | |
}); | |
// Update UI | |
renderStakedPools(); | |
showToast(`${poolName} added to your staked pools`); | |
// Open STRM modal to stake tokens | |
document.getElementById('strmModal').classList.remove('hidden'); | |
document.getElementById('poolSelect').value = poolName; | |
} | |
// Function to stake STRM to a pool | |
function stakeStrm(poolName, amount) { | |
if (!poolName || !amount || amount <= 0) { | |
showToast('Please select a pool and enter a valid amount'); | |
return; | |
} | |
if (amount > userData.strmBalance) { | |
showToast('Insufficient STRM balance'); | |
return; | |
} | |
// Update staked amount | |
const pool = userData.stakedPools.find(p => p.name === poolName); | |
if (pool) { | |
pool.hasStrm = true; | |
pool.stakedAmount = (pool.stakedAmount || 0) + amount; | |
pool.mining = true; | |
pool.hashrate = Math.sqrt(pool.stakedAmount) * 0.5; // Simple hashrate calculation based on stake | |
userData.strmBalance -= amount; | |
// Start mining if not already running | |
if (!miningInterval) { | |
startMining(); | |
} | |
} | |
// Update UI | |
renderStakedPools(); | |
showToast(`Staked ${amount} STRM to ${poolName}`); | |
} | |
// Function to start mining | |
function startMining() { | |
if (miningInterval) return; | |
miningInterval = setInterval(() => { | |
// Calculate total network hashrate | |
miningParams.hashrate = userData.stakedPools.reduce((sum, pool) => { | |
return pool.mining ? sum + (pool.hashrate || 0) : sum; | |
}, 0); | |
// Mine blocks with difficulty adjustment | |
userData.stakedPools.forEach(pool => { | |
if (pool.mining && pool.stakedAmount > 0) { | |
// Calculate mining probability based on pool's share of total hashrate | |
const poolShare = miningParams.hashrate > 0 ? (pool.hashrate / miningParams.hashrate) : 0; | |
// Calculate block reward with difficulty adjustment | |
const blockReward = miningParams.blockReward * poolShare; | |
// Add reward to pool | |
pool.earned = (pool.earned || 0) + blockReward; | |
miningParams.currentSupply += blockReward; | |
// Decrease blocks until halving and difficulty adjustment | |
miningParams.blocksUntilHalving = Math.max(0, miningParams.blocksUntilHalving - 1); | |
miningParams.blocksUntilDifficultyAdjustment = Math.max(0, miningParams.blocksUntilDifficultyAdjustment - 1); | |
// Check for halving event | |
if (miningParams.blocksUntilHalving === 0) { | |
miningParams.blockReward /= 2; | |
miningParams.blocksUntilHalving = 210000; | |
showToast('Block reward halved! New reward: ' + miningParams.blockReward + ' STRM'); | |
} | |
// Check for difficulty adjustment | |
if (miningParams.blocksUntilDifficultyAdjustment === 0) { | |
// Simple difficulty adjustment based on block time (target is 10 minutes) | |
const actualBlockTime = (Date.now() - miningParams.lastBlockTime) / 1000 / 60; // in minutes | |
const adjustmentFactor = Math.min(4, Math.max(0.25, miningParams.blockTimeTarget / actualBlockTime)); | |
miningParams.difficulty *= adjustmentFactor; | |
miningParams.blocksUntilDifficultyAdjustment = 2016; | |
showToast(`Difficulty adjusted to ${miningParams.difficulty.toFixed(1)}`); | |
} | |
miningParams.lastBlockTime = Date.now(); | |
} | |
}); | |
// Update UI | |
renderStakedPools(); | |
}, 10000); // Check every 10 seconds | |
} | |
// Function to stop mining | |
function stopMining() { | |
if (miningInterval) { | |
clearInterval(miningInterval); | |
miningInterval = null; | |
} | |
// Update all pools to not mining | |
userData.stakedPools.forEach(pool => { | |
pool.mining = false; | |
}); | |
// Update UI | |
renderStakedPools(); | |
showToast('Mining stopped'); | |
} | |
// Function to add STRM tokens | |
function addStrm(amount) { | |
userData.strmBalance += amount; | |
renderStakedPools(); | |
showToast(`Added ${amount} STRM to your balance`); | |
} | |
// Function to claim mining rewards | |
function claimRewards(poolName) { | |
const pool = userData.stakedPools.find(p => p.name === poolName); | |
if (pool && pool.earned > 0) { | |
userData.strmBalance += pool.earned; | |
const earned = pool.earned; | |
pool.earned = 0; | |
// Update UI | |
renderStakedPools(); | |
showToast(`Claimed ${earned} STRM from ${poolName}`); | |
} | |
} | |
// Initialize the app | |
function initApp() { | |
renderStreamingPools(); | |
renderStakedPools(); | |
// Start mining automatically if user has staked pools | |
if (userData.stakedPools.some(p => p.mining)) { | |
startMining(); | |
} | |
// Simulate changing stream data every 30 seconds | |
setInterval(() => { | |
// Randomly adjust some pool data | |
Object.values(musicCategories).forEach(category => { | |
category.pools.forEach(pool => { | |
// Base random change between -5% and +10% | |
let changePercent = (Math.random() * 15) - 5; | |
// Apply sentiment multiplier (0-100 scale mapped to 0.5-1.5 multiplier) | |
const sentimentMultiplier = 1 + (pool.sentiment / 200); | |
changePercent *= sentimentMultiplier; | |
const change = Math.round(pool.currentStreams * (changePercent / 100)); | |
pool.previousStreams = pool.currentStreams; | |
pool.currentStreams = Math.max(1000, pool.currentStreams + change); | |
}); | |
// Update category totals | |
category.totalStreams = category.pools.reduce((sum, pool) => sum + pool.currentStreams, 0); | |
}); | |
// Update UI | |
renderStreamingPools(); | |
renderStakedPools(); | |
}, 30000); | |
} | |
// Tab switching functionality | |
document.querySelectorAll('.tab-button').forEach(button => { | |
button.addEventListener('click', function() { | |
// Remove active class from all buttons | |
document.querySelectorAll('.tab-button').forEach(btn => { | |
btn.classList.remove('active', 'text-strm-bg'); | |
btn.classList.add('text-gray-500'); | |
}); | |
// Add active class to clicked button | |
this.classList.add('active', 'text-strm-bg'); | |
this.classList.remove('text-gray-500'); | |
// Hide all tabs | |
document.querySelectorAll('#mainContent > div').forEach(tab => { | |
tab.classList.add('hidden'); | |
}); | |
// Show selected tab | |
const tabId = this.getAttribute('data-tab'); | |
document.getElementById(tabId).classList.remove('hidden'); | |
// Scroll to top when switching tabs | |
document.getElementById('mainContent').scrollTo(0, 0); | |
// If switching to search tab, focus search input | |
if (tabId === 'searchTab') { | |
setTimeout(() => { | |
document.getElementById('poolSearchInput').focus(); | |
}, 100); | |
} | |
}); | |
}); | |
// Search pool functionality | |
document.getElementById('searchPoolBtn').addEventListener('click', function() { | |
const query = document.getElementById('poolSearchInput').value.trim(); | |
if (query) { | |
showSearchResults(query); | |
} | |
}); | |
document.getElementById('poolSearchInput').addEventListener('keypress', function(e) { | |
if (e.key === 'Enter') { | |
const query = this.value.trim(); | |
if (query) { | |
showSearchResults(query); | |
} | |
} | |
}); | |
// Add pool button | |
document.getElementById('addPoolBtn').addEventListener('click', function() { | |
document.getElementById('addPoolModal').classList.remove('hidden'); | |
}); | |
// Cancel add pool | |
document.getElementById('cancelAddPool').addEventListener('click', function() { | |
document.getElementById('addPoolModal').classList.add('hidden'); | |
}); | |
// Save new pool | |
document.getElementById('savePool').addEventListener('click', function() { | |
const poolName = document.getElementById('newPoolName').value.trim(); | |
const platform = document.querySelector('.platform-btn.bg-strm-bg')?.getAttribute('data-platform'); | |
if (!poolName || !platform) { | |
showToast('Please enter a pool name and select a category'); | |
return; | |
} | |
// Add to staked pools | |
userData.stakedPools.push({ | |
name: poolName, | |
platform, | |
hasStrm: false, | |
stakedAmount: 0, | |
sentiment: 0, | |
earned: 0, | |
mining: false, | |
hashrate: 0 | |
}); | |
// Add to music category | |
musicCategories[platform].pools.push({ | |
name: poolName, | |
currentStreams: 10000, | |
previousStreams: 0, | |
sentiment: 0 | |
}); | |
musicCategories[platform].totalStreams += 10000; | |
// Update UI | |
renderStreamingPools(); | |
renderStakedPools(); | |
document.getElementById('addPoolModal').classList.add('hidden'); | |
document.getElementById('newPoolName').value = ''; | |
showToast(`${poolName} created successfully`); | |
}); | |
// Platform selection in add pool modal | |
document.querySelectorAll('.platform-btn').forEach(btn => { | |
btn.addEventListener('click', function() { | |
document.querySelectorAll('.platform-btn').forEach(b => { | |
b.classList.remove('bg-strm-bg', 'text-white'); | |
b.classList.add('bg-gray-200', 'text-gray-700'); | |
}); | |
this.classList.remove('bg-gray-200', 'text-gray-700'); | |
this.classList.add('bg-strm-bg', 'text-white'); | |
}); | |
}); | |
// Stake STRM button | |
document.getElementById('stakeBtn').addEventListener('click', function() { | |
const poolName = document.getElementById('poolSelect').value; | |
const amount = parseFloat(document.getElementById('stakeAmount').value); | |
stakeStrm(poolName, amount); | |
}); | |
// STRM balance button | |
document.getElementById('strmBalanceBtn').addEventListener('click', function() { | |
document.getElementById('strmModal').classList.remove('hidden'); | |
}); | |
// Close STRM modal | |
document.getElementById('closeStrmModal').addEventListener('click', function() { | |
document.getElementById('strmModal').classList.add('hidden'); | |
}); | |
// Add STRM button | |
document.getElementById('addStrmBtn').addEventListener('click', function() { | |
addStrm(1000); | |
}); | |
// Explainer button | |
document.getElementById('explainerBtn').addEventListener('click', function() { | |
document.getElementById('explainerModal').classList.remove('hidden'); | |
}); | |
// Close explainer modal | |
document.getElementById('closeExplainerModal').addEventListener('click', function() { | |
document.getElementById('explainerModal').classList.add('hidden'); | |
}); | |
// Close explainer button | |
document.getElementById('closeExplainerBtn').addEventListener('click', function() { | |
document.getElementById('explainerModal').classList.add('hidden'); | |
}); | |
// Stake info button | |
document.getElementById('stakeInfoBtn').addEventListener('click', function() { | |
document.getElementById('explainerModal').classList.remove('hidden'); | |
}); | |
// Mining button | |
document.getElementById('miningBtn').addEventListener('click', function() { | |
if (userData.stakedPools.length > 0) { | |
openMiningModal(userData.stakedPools[0].name, userData.stakedPools[0].platform); | |
} else { | |
showToast('You have no pools staked for mining'); | |
} | |
}); | |
// Stop mining button | |
document.getElementById('stopMiningBtn').addEventListener('click', function() { | |
stopMining(); | |
document.getElementById('miningModal').classList.add('hidden'); | |
}); | |
// Claim mining button | |
document.getElementById('claimMiningBtn').addEventListener('click', function() { | |
claimRewards(currentMiningPool); | |
document.getElementById('miningModal').classList.add('hidden'); | |
}); | |
// Toast notification function | |
function showToast(message) { | |
const toast = document.getElementById('toast'); | |
const toastMessage = document.getElementById('toastMessage'); | |
toastMessage.textContent = message; | |
toast.classList.remove('hidden'); | |
setTimeout(() => { | |
toast.classList.add('hidden'); | |
}, 3000); | |
} | |
// Initialize the app when DOM is loaded | |
document.addEventListener('DOMContentLoaded', initApp); | |
</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 <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=privateuserh/privstrm0-01pa" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |