update: GUI version 2.0.1 (Chart + USD prices) and UI fixes.

This commit is contained in:
gerlofvanek 2023-04-11 22:01:06 +02:00
parent 81e7825b51
commit 0041fb4a3c
7 changed files with 418 additions and 97 deletions

File diff suppressed because one or more lines are too long

View File

@ -23,7 +23,7 @@
<div class="flex items-center"> <div class="flex items-center">
<p class="mr-1 text-sm text-gray-90 dark:text-white font-medium ">© 2023~</p> <p class="mr-1 text-sm text-gray-90 dark:text-white font-medium ">© 2023~</p>
<p class="text-sm text-coolGray-400 dark:text-white font-medium">{{ title }}</p> <span class="w-1 h-1 mx-1.5 bg-gray-500 rounded-full"></span> <p class="text-sm text-coolGray-400 dark:text-white font-medium">{{ title }}</p> <span class="w-1 h-1 mx-1.5 bg-gray-500 rounded-full"></span>
<p class="text-sm text-coolGray-400 dark:text-white font-medium">GUI 2.0 </p> <span class="w-1 h-1 mx-1.5 bg-gray-500 rounded-full"></span> <p class="text-sm text-coolGray-400 dark:text-white font-medium">GUI 2.0.1 </p> <span class="w-1 h-1 mx-1.5 bg-gray-500 rounded-full"></span>
<p class="mr-2 text-sm font-bold dark:text-white text-gray-90 ">Made with </p> <p class="mr-2 text-sm font-bold dark:text-white text-gray-90 ">Made with </p>
<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 24 24"> <svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 24 24">
<g stroke-linecap="round" stroke-width="2" fill="none" stroke="#f80b0b" stroke-linejoin="round"> <g stroke-linecap="round" stroke-width="2" fill="none" stroke="#f80b0b" stroke-linejoin="round">

View File

@ -5,6 +5,7 @@
{% if refresh %} {% if refresh %}
<meta http-equiv="refresh" content="{{ refresh }}"> <meta http-equiv="refresh" content="{{ refresh }}">
{% endif %} {% endif %}
<script src="/static/js/libs/chart.js"></script>
<link type="text/css" media="all" href="/static/css/libs/flowbite.min.css" rel="stylesheet" /> <link type="text/css" media="all" href="/static/css/libs/flowbite.min.css" rel="stylesheet" />
<link type="text/css" media="all" href="/static/css/libs/tailwind.min.css" rel="stylesheet"> <link type="text/css" media="all" href="/static/css/libs/tailwind.min.css" rel="stylesheet">
<link type="text/css" media="all" href="/static/css/style.css" rel="stylesheet"> <link type="text/css" media="all" href="/static/css/style.css" rel="stylesheet">

View File

@ -14,7 +14,6 @@
<path d="M5.34 0.671999L2.076 14.1H0.732L3.984 0.671999H5.34Z" fill="#BBC3CF"></path> <path d="M5.34 0.671999L2.076 14.1H0.732L3.984 0.671999H5.34Z" fill="#BBC3CF"></path>
</svg> </svg>
</li> </li>
<!-- todo fix link -->
<li> <li>
<a class="flex font-medium text-xs text-coolGray-500 dark:text-gray-300 hover:text-coolGray-700" href="#">{{ page_type }}</a> <a class="flex font-medium text-xs text-coolGray-500 dark:text-gray-300 hover:text-coolGray-700" href="#">{{ page_type }}</a>
</li> </li>
@ -57,15 +56,53 @@
</div> </div>
</div> </div>
</section> </section>
{% include 'inc_messages.html' %} {% include 'inc_messages.html' %}
{% if show_chart %}
{% if show_chart %} <section>
<div class="pl-6 pr-6 pt-0 pb-0 mt-5 h-full overflow-hidden">
<div class="pb-6 border-coolGray-100">
<div class="flex flex-wrap items-center justify-between -m-2">
<div class="w-full pt-2">
<div class="container mt-5 mx-auto">
<div class="pt-6 pb-8 bg-coolGray-100 dark:bg-gray-500 rounded-xl">
<div class="px-6">
<div class="w-full mt-6 pb-6 overflow-x-auto">
<div class="chart-container" style="max-width: 100%;">
<canvas id="coin-chart" style="height: 280px;"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="py-4 overflow-hidden"> <section class="py-4 overflow-hidden">
<div class="container px-4 mx-auto"> <div class="container px-4 mx-auto">
<div class="flex flex-wrap -m-3"> <div class="flex flex-wrap -m-3">
<div class="w-full sm:w-1/2 lg:w-1/5 p-3"> <style>
<div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white"> .active-container {
position: relative;
border-radius: 5px;
}
.active-container::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 1px solid rgb(77, 132, 240);
border-radius: inherit;
pointer-events: none;
}
</style>
<div class="w-full sm:w-1/2 lg:w-1/5 p-3" id="btc-container">
<div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white" id="btc-active">
<div class="flex items-center mb-2.5"> <div class="flex items-center mb-2.5">
<img src="/static/images/coins/Bitcoin-20.png" height="20" width="20" class="mr-2"> <img src="/static/images/coins/Bitcoin-20.png" height="20" width="20" class="mr-2">
<p class="text-sm text-neutral-500 font-medium">Bitcoin (BTC)</p> <p class="text-sm text-neutral-500 font-medium">Bitcoin (BTC)</p>
@ -89,9 +126,8 @@
Volume 24H:<div class="text-xs" id="btc-volume-24h"></div> Volume 24H:<div class="text-xs" id="btc-volume-24h"></div>
</p> </p>
</div> </div>
</div> </div>
<div class="w-full sm:w-1/2 lg:w-1/5 p-3" id="xmr-container">
<div class="w-full sm:w-1/2 lg:w-1/5 p-3">
<div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white"> <div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white">
<div class="flex items-center mb-2.5"> <div class="flex items-center mb-2.5">
<img src="/static/images/coins/Monero-20.png" height="20" width="20" class="mr-2"> <img src="/static/images/coins/Monero-20.png" height="20" width="20" class="mr-2">
@ -119,7 +155,7 @@
</div> </div>
</div> </div>
<div class="w-full sm:w-1/2 lg:w-1/5 p-3"> <div class="w-full sm:w-1/2 lg:w-1/5 p-3" id="part-container">
<div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white"> <div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white">
<div class="flex items-center mb-2.5"> <div class="flex items-center mb-2.5">
<img src="/static/images/coins/Particl-20.png" height="20" width="20" class="mr-2"> <img src="/static/images/coins/Particl-20.png" height="20" width="20" class="mr-2">
@ -146,9 +182,7 @@
</p> </p>
</div> </div>
</div> </div>
<div class="w-full sm:w-1/2 lg:w-1/5 p-3" id="pivx-container">
<div class="w-full sm:w-1/2 lg:w-1/5 p-3">
<div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white"> <div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white">
<div class="flex items-center mb-2.5"> <div class="flex items-center mb-2.5">
<img src="/static/images/coins/PIVX-20.png" height="20" width="20" class="mr-2"> <img src="/static/images/coins/PIVX-20.png" height="20" width="20" class="mr-2">
@ -175,8 +209,7 @@
</p> </p>
</div> </div>
</div> </div>
<div class="w-full sm:w-1/2 lg:w-1/5 p-3" id="firo-container">
<div class="w-full sm:w-1/2 lg:w-1/5 p-3">
<div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white"> <div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white">
<div class="flex items-center mb-2.5"> <div class="flex items-center mb-2.5">
<img src="/static/images/coins/Firo-20.png" height="20" width="20" class="mr-2"> <img src="/static/images/coins/Firo-20.png" height="20" width="20" class="mr-2">
@ -203,8 +236,7 @@
</p> </p>
</div> </div>
</div> </div>
<div class="w-full sm:w-1/2 lg:w-1/5 p-3" id="ltc-container">
<div class="w-full sm:w-1/2 lg:w-1/5 p-3">
<div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white"> <div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white">
<div class="flex items-center mb-2.5"> <div class="flex items-center mb-2.5">
<img src="/static/images/coins/Litecoin-20.png" height="20" width="20" class="mr-2"> <img src="/static/images/coins/Litecoin-20.png" height="20" width="20" class="mr-2">
@ -224,15 +256,13 @@
<div id="ltc-price-btc"></div> <div id="ltc-price-btc"></div>
</h3> </h3>
</div> </div>
</div> </div>
<p class="text-xs text-neutral-400 font-medium"> <p class="text-xs text-neutral-400 font-medium">
Volume 24H:<div class="text-xs" id="ltc-volume-24h"></div> Volume 24H:<div class="text-xs" id="ltc-volume-24h"></div>
</p> </p>
</div> </div>
</div> </div>
<div class="w-full sm:w-1/2 lg:w-1/5 p-3" id="dash-container">
<div class="w-full sm:w-1/2 lg:w-1/5 p-3">
<div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white"> <div class="px-5 py-3 h-full bg-coolGray-100 dark:bg-gray-500 rounded-lg dark:text-white">
<div class="flex items-center mb-2.5"> <div class="flex items-center mb-2.5">
<img src="/static/images/coins/Dash-20.png" height="20" width="20" class="mr-2"> <img src="/static/images/coins/Dash-20.png" height="20" width="20" class="mr-2">
@ -252,71 +282,256 @@
<div id="dash-price-btc"></div> <div id="dash-price-btc"></div>
</h3> </h3>
</div> </div>
</div> </div>
<p class="text-xs text-neutral-400 font-medium"> <p class="text-xs text-neutral-400 font-medium">
Volume 24H:<div class="text-xs" id="dash-volume-24h"></div> Volume 24H:<div class="text-xs" id="dash-volume-24h"></div>
</p> </p>
</div> </div>
</div> </div>
</section> </section>
<script> <script>
window.addEventListener('load', function() { window.addEventListener('load', function() {
const api_key = '{{chart_api_key}}'; const api_key = '{{chart_api_key}}';
const coins = ['BTC', 'PART', 'XMR', 'LTC', 'FIRO', 'DASH', 'PIVX']; const coins = ['BTC', 'PART', 'XMR', 'LTC', 'FIRO', 'DASH', 'PIVX'];
coins.forEach(coin => { coins.forEach(coin => {
fetch(`https://min-api.cryptocompare.com/data/pricemultifull?fsyms=${coin}&tsyms=USD,BTC&api_key=${api_key}`) fetch(`https://min-api.cryptocompare.com/data/pricemultifull?fsyms=${coin}&tsyms=USD,BTC&api_key=${api_key}`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
displayCoinData(coin, data);
})
.catch(error => console.error(`Error fetching ${coin} data:`, error));
});
updateChart('BTC');
});
function displayCoinData(coin, data) {
const priceUSD = data.RAW[coin].USD.PRICE; const priceUSD = data.RAW[coin].USD.PRICE;
const priceBTC = data.RAW[coin].BTC.PRICE; const priceBTC = data.RAW[coin].BTC.PRICE;
const priceChange1h = data.RAW[coin].USD.CHANGEPCTHOUR; const priceChange1h = data.RAW[coin].USD.CHANGEPCTHOUR;
const volume24h = data.RAW[coin].USD.TOTALVOLUME24HTO; const volume24h = data.RAW[coin].USD.TOTALVOLUME24HTO;
document.querySelector(`#${coin.toLowerCase()}-price-usd`).textContent = priceUSD.toFixed(2) + ' USD'; document.querySelector(`#${coin.toLowerCase()}-price-usd`).textContent = priceUSD.toFixed(2) + ' USD';
if (coin !== 'BTC') { if (coin !== 'BTC') {
document.querySelector(`#${coin.toLowerCase()}-price-btc`).textContent = priceBTC.toFixed(8) + ' BTC'; document.querySelector(`#${coin.toLowerCase()}-price-btc`).textContent = priceBTC.toFixed(8) + ' BTC';
} }
document.querySelector(`#${coin.toLowerCase()}-price-change-container`).textContent = priceChange1h.toFixed(2) + '%'; document.querySelector(`#${coin.toLowerCase()}-price-change-container`).textContent = priceChange1h.toFixed(2) + '%';
document.querySelector(`#${coin.toLowerCase()}-volume-24h`).textContent = volume24h.toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ',') + ' USD'; document.querySelector(`#${coin.toLowerCase()}-volume-24h`).textContent = volume24h.toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ',') + ' USD';
const priceChangeContainer = document.querySelector(`#${coin.toLowerCase()}-price-change-container`); const priceChangeContainer = document.querySelector(`#${coin.toLowerCase()}-price-change-container`);
if (priceChange1h >= 0) { if (priceChange1h >= 0) {
priceChangeContainer.innerHTML = ` priceChangeContainer.innerHTML = positivePriceChangeHTML(priceChange1h);
} else {
priceChangeContainer.innerHTML = negativePriceChangeHTML(priceChange1h);
}
}
function positivePriceChangeHTML(value) {
return `
<div class="flex flex-wrap items-center py-px px-1 border border-green-500 rounded-full"> <div class="flex flex-wrap items-center py-px px-1 border border-green-500 rounded-full">
<svg class="mr-0.5" width="15" height="10" viewBox="0 0 15 10" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="mr-0.5" width="15" height="10" viewBox="0 0 15 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.16667 0.916748C7.75245 0.916748 7.41667 1.25253 7.41667 1.66675C7.41667 2.08096 7.75245 2.41675 8.16667 2.41675V0.916748ZM13.5 1.66675H14.25C14.25 1.25253 13.9142 0.916748 13.5 0.916748V1.66675ZM12.75 7.00008C12.75 7.41429 13.0858 7.75008 13.5 7.75008C13.9142 7.75008 14.25 7.41429 14.25 7.00008H12.75ZM0.96967 7.80308C0.676777 8.09598 0.676777 8.57085 0.96967 8.86374C1.26256 9.15664 1.73744 9.15664 2.03033 8.86374L0.96967 7.80308ZM5.5 4.33341L6.03033 3.80308C5.73744 3.51019 5.26256 3.51019 4.96967 3.80308L5.5 4.33341ZM8.16667 7.00008L7.63634 7.53041C7.92923 7.8233 8.4041 7.8233 8.697 7.53041L8.16667 7.00008ZM8.16667 2.41675H13.5V0.916748H8.16667V2.41675ZM12.75 1.66675V7.00008H14.25V1.66675H12.75ZM2.03033 8.86374L6.03033 4.86374L4.96967 3.80308L0.96967 7.80308L2.03033 8.86374ZM4.96967 4.86374L7.63634 7.53041L8.697 6.46975L6.03033 3.80308L4.96967 4.86374ZM8.697 7.53041L14.0303 2.19708L12.9697 1.13642L7.63634 6.46975L8.697 7.53041Z" fill="#20C43A"></path> <path d="M8.16667 0.916748C7.75245 0.916748 7.41667 1.25253 7.41667 1.66675C7.41667 2.08096 7.75245 2.41675 8.16667 2.41675V0.916748ZM13.5 1.66675H14.25C14.25 1.25253 13.9142 0.916748 13.5 0.916748V1.66675ZM12.75 7.00008C12.75 7.41429 13.0858 7.75008 13.5 7.75008C13.9142 7.75008 14.25 7.41429 14.25 7.00008H12.75ZM0.96967 7.80308C0.676777 8.09598 0.676777 8.57085 0.96967 8.86374C1.26256 9.15664 1.73744 9.15664 2.03033 8.86374L0.96967 7.80308ZM5.5 4.33341L6.03033 3.80308C5.73744 3.51019 5.26256 3.51019 4.96967 3.80308L5.5 4.33341ZM8.16667 7.00008L7.63634 7.53041C7.92923 7.8233 8.4041 7.8233 8.697 7.53041L8.16667 7.00008ZM8.16667 2.41675H13.5V0.916748H8.16667V2.41675ZM12.75 1.66675V7.00008H14.25V1.66675H12.75ZM2.03033 8.86374L6.03033 4.86374L4.96967 3.80308L0.96967 7.80308L2.03033 8.86374ZM4.96967 4.86374L7.63634 7.53041L8.697 6.46975L6.03033 3.80308L4.96967 4.86374ZM8.697 7.53041L14.0303 2.19708L12.9697 1.13642L7.63634 6.46975L8.697 7.53041Z" fill="#20C43A"></path>
</svg> </svg>
<span class="text-xs text-green-500 font-medium">${priceChange1h.toFixed(2)}%</span> <span class="text-xs text-green-500 font-medium">${value.toFixed(2)}%</span>
</div>`; </div>`;
} else { }
priceChangeContainer.innerHTML = ` function negativePriceChangeHTML(value) {
return `
<div class="flex flex-wrap items-center py-px px-1 border border-red-500 rounded-full"> <div class="flex flex-wrap items-center py-px px-1 border border-red-500 rounded-full">
<svg class="mr-0.5" width="14" height="10" viewBox="0 0 14 10" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="mr-0.5" width="14" height="10" viewBox="0 0 14 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.66667 7.58341C7.25245 7.58341 6.91667 7.9192 6.91667 8.33341C6.91667 8.74763 7.25245 9.08341 7.66667 9.08341V7.58341ZM13 8.33341V9.08341C13.4142 9.08341 13.75 8.74763 13.75 8.33341H13ZM13.75 3.00008C13.75 2.58587 13.4142 2.25008 13 2.25008C12.5858 2.25008 12.25 2.58587 12.25 3.00008H13.75ZM1.53033 1.13642C1.23744 0.843525 0.762563 0.843525 0.46967 1.13642C0.176777 1.42931 0.176777 1.90418 0.46967 2.19708L1.53033 1.13642ZM5 5.66675L4.46967 6.19708C4.76256 6.48997 5.23744 6.48997 5.53033 6.19708L5 5.66675ZM7.66667 3.00008L8.197 2.46975C7.9041 2.17686 7.42923 2.17686 7.13634 2.46975L7.66667 3.00008ZM7.66667 9.08341H13V7.58341H7.66667V9.08341ZM13.75 8.33341V3.00008H12.25V8.33341H13.75ZM0.46967 2.19708L4.46967 6.19708L5.53033 5.13642L1.53033 1.13642L0.46967 2.19708ZM5.53033 6.19708L8.197 3.53041L7.13634 2.46975L4.46967 5.13642L5.53033 6.19708ZM7.13634 3.53041L12.4697 8.86374L13.5303 7.80308L8.197 2.46975L7.13634 3.53041Z" fill="#FF3131"></path> <path d="M7.66667 7.58341C7.25245 7.58341 6.91667 7.9192 6.91667 8.33341C6.91667 8.74763 7.25245 9.08341 7.66667 9.08341V7.58341ZM13 8.33341V9.08341C13.4142 9.08341 13.75 8.74763 13.75 8.33341H13ZM13.75 3.00008C13.75 2.58587 13.4142 2.25008 13 2.25008C12.5858 2.25008 12.25 2.58587 12.25 3.00008H13.75ZM1.53033 1.13642C1.23744 0.843525 0.762563 0.843525 0.46967 1.13642C0.176777 1.42931 0.176777 1.90418 0.46967 2.19708L1.53033 1.13642ZM5 5.66675L4.46967 6.19708C4.76256 6.48997 5.23744 6.48997 5.53033 6.19708L5 5.66675ZM7.66667 3.00008L8.197 2.46975C7.9041 2.17686 7.42923 2.17686 7.13634 2.46975L7.66667 3.00008ZM7.66667 9.08341H13V7.58341H7.66667V9.08341ZM13.75 8.33341V3.00008H12.25V8.33341H13.75ZM0.46967 2.19708L4.46967 6.19708L5.53033 5.13642L1.53033 1.13642L0.46967 2.19708ZM5.53033 6.19708L8.197 3.53041L7.13634 2.46975L4.46967 5.13642L5.53033 6.19708ZM7.13634 3.53041L12.4697 8.86374L13.5303 7.80308L8.197 2.46975L7.13634 3.53041Z" fill="#FF3131"></path>
</svg> </svg>
<span class="text-xs text-red-500 font-medium">${Math.abs(priceChange1h.toFixed(2))}%</span> <span class="text-xs text-red-500 font-medium">${value.toFixed(2)}%</span>
</div>`; </div>`;
} }
}) function setActiveContainer(containerId) {
.catch(error => console.error(`Error fetching ${coin} data:`, error)); const containerIds = ['btc-container', 'xmr-container', 'part-container', 'pivx-container', 'firo-container', 'dash-container', 'ltc-container'];
const activeClass = 'active-container';
containerIds.forEach(id => {
const container = document.getElementById(id);
const innerDiv = container.querySelector('div');
if (id === containerId) {
innerDiv.classList.add(activeClass);
} else {
innerDiv.classList.remove(activeClass);
}
}); });
}
document.getElementById('btc-container').addEventListener('click', () => {
setActiveContainer('btc-container');
updateChart('BTC');
});
document.getElementById('xmr-container').addEventListener('click', () => {
setActiveContainer('xmr-container');
updateChart('XMR');
});
document.getElementById('part-container').addEventListener('click', () => {
setActiveContainer('part-container');
updateChart('PART');
});
document.getElementById('pivx-container').addEventListener('click', () => {
setActiveContainer('pivx-container');
updateChart('PIVX');
});
document.getElementById('firo-container').addEventListener('click', () => {
setActiveContainer('firo-container');
updateChart('FIRO');
});
document.getElementById('dash-container').addEventListener('click', () => {
setActiveContainer('dash-container');
updateChart('DASH');
});
document.getElementById('ltc-container').addEventListener('click', () => {
setActiveContainer('ltc-container');
updateChart('LTC');
});
let coin;
const coinOptions = {
'BTC': {
lineColor: 'rgba(77, 132, 240, 1)',
backgroundColor: 'rgba(77, 132, 240, 0.1)'
}
};
function updateChart(coinSymbol) {
coin = coinSymbol;
const api_key = '{{chart_api_key}}';
fetch(`https://min-api.cryptocompare.com/data/v2/histoday?fsym=${coin}&tsym=USD&limit=30&api_key=${api_key}`)
.then((response) => response.json())
.then((data) => {
const coinSettings = coinOptions[coinSymbol] || {};
const chartData = {
labels: data.Data.Data.map(d => formatDate(new Date(d.time * 1000))),
datasets: [{
data: data.Data.Data.map(d => d.close),
borderColor: coinSettings.lineColor || 'rgba(77, 132, 240, 1)',
tension: 0.1,
fill: true,
backgroundColor: coinSettings.backgroundColor || 'rgba(77, 132, 240, 0.1)',
pointStyle: 'circle',
pointRadius: 5,
pointHoverRadius: 10
}]
};
chart.data.labels = chartData.labels;
chart.data.datasets = chartData.datasets;
chart.options.scales.y.title.text = `Price (USD) - ${coin} 30 DAYS`;
chart.update();
})
.catch(error => console.error(`Error updating chart for ${coin}:`, error));
}
function formatDate(date) {
const options = { day: '2-digit', month: '2-digit', year: '2-digit' };
return new Intl.DateTimeFormat('en-US', options).format(date);
}
const verticalLinePlugin = {
id: 'verticalLine',
beforeTooltipDraw: (chart, args) => {
const tooltip = chart.tooltip;
if (tooltip.opacity !== 0) {
const ctx = chart.ctx;
const x = tooltip.caretX;
const topY = chart.chartArea.top;
const bottomY = chart.chartArea.bottom;
const options = chart.options.plugins.verticalLine;
ctx.save();
ctx.setLineDash([5, 5]);
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = options.lineWidth || 1;
ctx.strokeStyle = options.lineColor || 'rgba(0, 0, 255, 1)';
ctx.stroke();
ctx.restore();
}
}
};
Chart.register(verticalLinePlugin);
const ctx = document.getElementById('coin-chart').getContext('2d');
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
data: [],
borderColor: 'rgba(77, 132, 240, 1)',
tension: 0.4,
fill: true,
pointStyle: 'circle',
pointRadius: 5,
pointHoverRadius: 10
}]
},
options: {
maintainAspectRatio: false,
scales: {
x: {
grid: {
display: false,
},
display: true,
title: {
display: false,
text: 'Date'
},
ticks: {
font: {
size: 12,
},
callback: function(value, index, values) {
return chart.data.labels[index];
},
}
},
y: {
grid: {
display: false,
},
display: true,
title: {
display: true,
text: 'Price (USD)'
}
}
},
plugins: {
legend: {
display: false
},
tooltip: {
mode: 'index',
intersect: false,
displayColors: false,
callbacks: {
title: function(tooltipItems) {
const item = tooltipItems[0];
return chart.data.labels[item.dataIndex];
},
label: function(item) {
return `${coin}: $${item.parsed.y}`;
}
}
},
verticalLine: {
lineWidth: 1,
lineColor: 'rgba(77, 132, 240, 1)'
}
},
elements: {
line: {
backgroundColor: 'rgba(25, 132, 140, 0.6)',
borderColor: 'transparent'
}
}
}
}); });
</script> </script>
{% endif %} {% endif %}
<section> <section>
<div class="pl-6 pr-6 pt-0 pb-0 mt-5 h-full overflow-hidden"> <div class="pl-6 pr-6 pt-0 pb-0 mt-5 h-full overflow-hidden">
<div class="pb-6 border-coolGray-100"> <div class="pb-6 border-coolGray-100">
<div class="flex flex-wrap items-center justify-between -m-2"> <div class="flex flex-wrap items-center justify-between -m-2">
<div class="w-full pt-2"> <div class="w-full pt-2">
<form method="post"> <form method="post">
<div class="flex justify-between items-center pb-4 dark:text-white"> <div class="flex justify-between items-center pb-4 dark:text-white">
<div class="rounded-b-md"> <div class="rounded-b-md">
@ -327,7 +542,6 @@ window.addEventListener('load', function() {
<svg class="absolute right-4 top-1/2 transform -translate-y-1/2 " width="16 " height="16 " viewBox="0 0 16 16 " fill="none " xmlns="http://www.w3.org/2000/svg "> <svg class="absolute right-4 top-1/2 transform -translate-y-1/2 " width="16 " height="16 " viewBox="0 0 16 16 " fill="none " xmlns="http://www.w3.org/2000/svg ">
<path d="M11.3333 6.1133C11.2084 5.98913 11.0395 5.91943 10.8633 5.91943C10.6872 5.91943 10.5182 5.98913 10.3933 6.1133L8.00001 8.47329L5.64001 6.1133C5.5151 5.98913 5.34613 5.91943 5.17001 5.91943C4.99388 5.91943 4.82491 5.98913 4.70001 6.1133C4.63752 6.17527 4.58792 6.249 4.55408 6.33024C4.52023 6.41148 4.50281 6.49862 4.50281 6.58663C4.50281 6.67464 4.52023 6.76177 4.55408 6.84301C4.58792 6.92425 4.63752 6.99799 4.70001 7.05996L7.52667 9.88663C7.58865 9.94911 7.66238 9.99871 7.74362 10.0326C7.82486 10.0664 7.912 10.0838 8.00001 10.0838C8.08801 10.0838 8.17515 10.0664 8.25639 10.0326C8.33763 9.99871 8.41136 9.94911 8.47334 9.88663L11.3333 7.05996C11.3958 6.99799 11.4454 6.92425 11.4793 6.84301C11.5131 6.76177 11.5305 6.67464 11.5305 6.58663C11.5305 6.49862 11.5131 6.41148 11.4793 6.33024C11.4454 6.249 11.3958 6.17527 11.3333 6.1133Z " fill="#8896AB"></path> <path d="M11.3333 6.1133C11.2084 5.98913 11.0395 5.91943 10.8633 5.91943C10.6872 5.91943 10.5182 5.98913 10.3933 6.1133L8.00001 8.47329L5.64001 6.1133C5.5151 5.98913 5.34613 5.91943 5.17001 5.91943C4.99388 5.91943 4.82491 5.98913 4.70001 6.1133C4.63752 6.17527 4.58792 6.249 4.55408 6.33024C4.52023 6.41148 4.50281 6.49862 4.50281 6.58663C4.50281 6.67464 4.52023 6.76177 4.55408 6.84301C4.58792 6.92425 4.63752 6.99799 4.70001 7.05996L7.52667 9.88663C7.58865 9.94911 7.66238 9.99871 7.74362 10.0326C7.82486 10.0664 7.912 10.0838 8.00001 10.0838C8.08801 10.0838 8.17515 10.0664 8.25639 10.0326C8.33763 9.99871 8.41136 9.94911 8.47334 9.88663L11.3333 7.05996C11.3958 6.99799 11.4454 6.92425 11.4793 6.84301C11.5131 6.76177 11.5305 6.67464 11.5305 6.58663C11.5305 6.49862 11.5131 6.41148 11.4793 6.33024C11.4454 6.249 11.3958 6.17527 11.3333 6.1133Z " fill="#8896AB"></path>
</svg> </svg>
<!-- is="ms-dropdown" todo -->
<select name="coin_from" class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-gray-50 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0"> <select name="coin_from" class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-gray-50 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0">
<option value="any" {% if filters.coin_from==-1 %} selected{% endif %}>Any</option> <option value="any" {% if filters.coin_from==-1 %} selected{% endif %}>Any</option>
{% for c in coins_from %} {% for c in coins_from %}
@ -474,7 +688,7 @@ window.addEventListener('load', function() {
</th> </th>
<th class="p-0"> <th class="p-0">
<div class="py-3 px-6 bg-coolGray-200 dark:bg-gray-600"> <div class="py-3 px-6 bg-coolGray-200 dark:bg-gray-600">
<span class="text-xs text-gray-600 dark:text-gray-300 font-semibold">Network</span> <span class="text-xs text-gray-600 dark:text-gray-300 font-semibold">Details</span>
</div> </div>
</th> </th>
<th class="p-0"> <th class="p-0">
@ -483,11 +697,6 @@ window.addEventListener('load', function() {
</div> </div>
</th> </th>
<!--<th>ID</th>--> <!--<th>ID</th>-->
<th class="p-0">
<div class="py-3 px-6 bg-coolGray-200 dark:bg-gray-600">
<span class="text-xs text-gray-600 dark:text-gray-300 font-semibold">Swap Type</span>
</div>
</th>
<th class="p-0"> <th class="p-0">
<div class="py-3 px-6 bg-coolGray-200 dark:bg-gray-600"> <div class="py-3 px-6 bg-coolGray-200 dark:bg-gray-600">
<span class="text-xs text-gray-600 dark:text-gray-300 font-semibold">You get</span> <span class="text-xs text-gray-600 dark:text-gray-300 font-semibold">You get</span>
@ -537,37 +746,54 @@ window.addEventListener('load', function() {
</td> </td>
<!--<td class="py-4 px-6 text-xs"><a class="monospace text-xs" href=/offer/{{ o[1] }}>{{ o[1]|truncate(6, True) }}</a></td>--> <!--<td class="py-4 px-6 text-xs"><a class="monospace text-xs" href=/offer/{{ o[1] }}>{{ o[1]|truncate(6, True) }}</a></td>-->
<!--<td class="py-4 px-6 text-xs monospace">{{ o[8] }}{% if o[9]==true %} <b>Sent</b>{% endif %}</td>--> <!--<td class="py-4 px-6 text-xs monospace">{{ o[8] }}{% if o[9]==true %} <b>Sent</b>{% endif %}</td>-->
<td class="py-3 px-6 text-xs">{{ o[7] }} <td class="py-3 px-6 text-xs">
<div class="network"><span class="bold">Network:</span> {{ o[7] }}</div>
<div class="partial pt-1"><span class="bold">Amount Variable:</span> {{ o[14] }}<div>
<div class="swaptype pt-1"><span class="bold">Swap Type:</span> {{ o[13] }}</div>
<!-- {% if o[12]==2 %}(Revoked){% elif o[11]==true %}(Not Active){% else %}(Active){% endif %} --> <!-- {% if o[12]==2 %}(Revoked){% elif o[11]==true %}(Not Active){% else %}(Active){% endif %} -->
</td> </td>
<td class="py-3 px-6 text-xs monospace"> <td class="py-3 px-6 text-xs monospace">
<a href="/identity/{{ o[8] }}{% if o[9]==true %}{% endif %}">{{ o[8] }}</a> <a href="/identity/{{ o[8] }}{% if o[9]==true %}{% endif %}">{{ o[8] }}</a>
</td> </td>
<td class="py-3 px-6 text-xs">{{ o[13] }}</td>
<td class="py-3 px-6 text-xs"> <td class="py-3 px-6 text-xs">
<span class="inline-flex align-middle items-center justify-center w-9 h-10 rounded"> <span class="inline-flex align-middle items-center justify-center w-9 h-10 rounded">
{% if o[9]==true %} <img class="h-7" src="/static/images/coins/{{ o[3]|replace(" ", "-") }}.png" alt=""> {% if o[9]==true %} <img class="h-7" src="/static/images/coins/{{ o[3]|replace(" ", "-") }}.png" alt="">
</span>{{ o[3] }} </span>{{ o[3] }}
</td> </td>
<td class="py-3 px-6 text-xs">{{ o[5]|truncate(8,true,'',0) }}</td> <td class="py-3 px-6 text-xs">
<div class="coinname-value" data-coinname="{{ o[3] }}">{{ o[5]|truncate(8,true,'',0) }}</div>
<div class="usd-value"></div>
</td>
{% else %} {% else %}
<img class="h-7" src="/static/images/coins/{{ o[2]|replace(" ", "-") }}.png" alt=""> <img class="h-7" src="/static/images/coins/{{ o[2]|replace(" ", "-") }}.png" alt="">
</span>{{ o[2] }} </span>{{ o[2] }}
</td> </td>
<td class="py-3 px-6 text-xs">{{ o[4]|truncate(8,true,'',0) }}</td> <td class="py-3 px-6 text-xs">
<div class="coinname-value" data-coinname="{{ o[2] }}">{{ o[4]|truncate(8,true,'',0) }}</div>
<div class="usd-value"></div>
</td>
{% endif %} {% endif %}
<td class="py-4 px-6 text-xs"> <td class="py-4 px-6 text-xs">
<span class="inline-flex align-middle items-center justify-center w-9 h-10 rounded"> {% if o[9]==true %} <img class="h-7" src="/static/images/coins/{{ o[2]|replace(" ", "-") }}.png" alt=""> <span class="inline-flex align-middle items-center justify-center w-9 h-10 rounded"> {% if o[9]==true %} <img class="h-7" src="/static/images/coins/{{ o[2]|replace(" ", "-") }}.png" alt="">
</span>{{ o[2] }} </span>{{ o[2] }}
</td> </td>
<td class="py-3 px-6 text-xs">{{ o[4]|truncate(8,true,'',0) }}</td> <td class="py-3 px-6 text-xs">
<div class="coinname-value" data-coinname="{{ o[2] }}">{{ o[4]|truncate(8,true,'',0) }}</div>
<div class="usd-value"></div>
</td>
{% else %} {% else %}
<img class="h-7" src="/static/images/coins/{{ o[3]|replace(" ", "-") }}.png" alt=""> <img class="h-7" src="/static/images/coins/{{ o[3]|replace(" ", "-") }}.png" alt="">
</span>{{ o[3] }} </span>{{ o[3] }}
</td> </td>
<td class="py-3 px-6 text-xs">{{ o[5]|truncate(8,true,'',0) }}</td> <td class="py-3 px-6 text-xs">
<div class="coinname-value" data-coinname="{{ o[3] }}">{{ o[5]|truncate(8,true,'',0) }}</div>
<div class="usd-value"></div>
</td>
{% endif %} {% endif %}
<td class="py-4 px-6 text-xs">{{ o[6]|truncate(8,true,'',0) }}</td> <td class="py-3 px-6 text-xs">
<div class="coinname-value" data-coinname="{{ o[3] }}">{{ o[5]|truncate(8,true,'',0) }}</div>
<div class="usd-value"></div>
</td>
<!-- <td class="py-4 px-6">{{ o[10] }}</td>--> <!-- <td class="py-4 px-6">{{ o[10] }}</td>-->
<td class="py-3 px-6"> <td class="py-3 px-6">
<a class="inline-block w-20 py-1 px-2 font-medium text-center text-sm rounded-md {% if o[9]==true %} bg-blue-500 text-white border border-blue-500 hover:bg-blue-600 transition duration-200 {% else %} bg-blue-500 text-white hover:bg-blue-600 transition duration-200 {% endif %}" href="/offer/{{ o[1] }}">{% if o[9]==true %}Edit{% else %}Swap{% endif %}</a> <a class="inline-block w-20 py-1 px-2 font-medium text-center text-sm rounded-md {% if o[9]==true %} bg-blue-500 text-white border border-blue-500 hover:bg-blue-600 transition duration-200 {% else %} bg-blue-500 text-white hover:bg-blue-600 transition duration-200 {% endif %}" href="/offer/{{ o[1] }}">{% if o[9]==true %}Edit{% else %}Swap{% endif %}</a>
@ -580,7 +806,55 @@ window.addEventListener('load', function() {
<input type="hidden" name="pageno" value="{{ filters.page_no }}"> <input type="hidden" name="pageno" value="{{ filters.page_no }}">
</div> </div>
</div> </div>
<script>
const coinNameToSymbol = {
'Bitcoin': 'BTC',
'Particl': 'PART',
'Particl Blind': 'PART',
'Particl Anon': 'PART',
'Monero': 'XMR',
'Litecoin': 'LTC',
'Firo': 'FIRO',
'Dash': 'DASH',
'PIVX': 'PIVX'
};
function updateUsdValue(cryptoCell, coinFullName) {
const coinSymbol = coinNameToSymbol[coinFullName];
if (!coinSymbol) {
console.error(`Coin symbol not found for full name: ${coinFullName}`);
return;
}
const cryptoValue = parseFloat(cryptoCell.textContent);
const usdCell = cryptoCell.nextElementSibling;
const apiUrl = `https://min-api.cryptocompare.com/data/price?fsym=${coinSymbol}&tsyms=USD`;
fetch(apiUrl)
.then(response => response.json())
.then(data => {
const exchangeRate = data.USD;
if (!isNaN(exchangeRate)) {
const usdValue = cryptoValue * exchangeRate;
usdCell.textContent = `${usdValue.toFixed(2)} USD`;
} else {
usdCell.textContent = 'Invalid exchange rate';
}
})
.catch(error => {
usdCell.textContent = 'Error retrieving exchange rate';
});
}
document.addEventListener('DOMContentLoaded', () => {
const coinNameValues = document.querySelectorAll('.coinname-value');
for (let i = 0; i < coinNameValues.length; i++) {
const coinFullName = coinNameValues[i].getAttribute('data-coinname');
updateUsdValue(coinNameValues[i], coinFullName);
coinNameValues[i].addEventListener('input', () => updateUsdValue(coinNameValues[i], coinFullName));
}
});
</script>
<div class="rounded-b-md"> <div class="rounded-b-md">
<div class="w-full md:w-0/12"> <div class="w-full md:w-0/12">
<div class="flex flex-wrap justify-end pt-6 pr-6 border-t border-gray-100 dark:border-gray-400"> <div class="flex flex-wrap justify-end pt-6 pr-6 border-t border-gray-100 dark:border-gray-400">
@ -616,5 +890,28 @@ window.addEventListener('load', function() {
</section> </section>
</div> </div>
{% include 'footer.html' %} {% include 'footer.html' %}
<script>
document.getElementById('btc-container').addEventListener('click', () => {
updateChart('BTC');
});
document.getElementById('xmr-container').addEventListener('click', () => {
updateChart('XMR');
});
document.getElementById('part-container').addEventListener('click', () => {
updateChart('PART');
});
document.getElementById('pivx-container').addEventListener('click', () => {
updateChart('PIVX');
});
document.getElementById('firo-container').addEventListener('click', () => {
updateChart('FIRO');
});
document.getElementById('dash-container').addEventListener('click', () => {
updateChart('DASH');
});
document.getElementById('ltc-container').addEventListener('click', () => {
updateChart('LTC');
});
</script>
</body> </body>
</html> </html>

View File

@ -65,6 +65,7 @@
</div> </div>
</section> </section>
{% include 'inc_messages.html' %} {% include 'inc_messages.html' %}
<section>
<div class="pl-6 pr-6 pt-0 pb-0 mt-5 h-full overflow-hidden"> <div class="pl-6 pr-6 pt-0 pb-0 mt-5 h-full overflow-hidden">
<div class="pb-6 border-coolGray-100"> <div class="pb-6 border-coolGray-100">
<div class="flex flex-wrap items-center justify-between -m-2"> <div class="flex flex-wrap items-center justify-between -m-2">

View File

@ -318,10 +318,10 @@
</svg>Withdraw</button> </svg>Withdraw</button>
</td> </td>
<td class="py-3 px-6"> <td class="py-3 px-6">
<input placeholder="Address" class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-white text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" type="text" name="to_{{ w.cid }}" value="{{ w.wd_address }}"> <input placeholder="Address" class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-gray-400 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" type="text" name="to_{{ w.cid }}" value="{{ w.wd_address }}">
</td> </td>
<td class="py-3 px-6"> <td class="py-3 px-6">
<input placeholder="Amount" class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-white text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" type="text" name="amt_{{ w.cid }}" value="{{ w.wd_value }}"> <input placeholder="Amount" class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-gray-400 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" type="text" name="amt_{{ w.cid }}" value="{{ w.wd_value }}">
</td> </td>
</tr> </tr>
<tr class="opacity-100 text-gray-500 dark:text-gray-100"> <tr class="opacity-100 text-gray-500 dark:text-gray-100">
@ -432,7 +432,7 @@
</svg>Create UTXO</button> </svg>Create UTXO</button>
</td> </td>
<td class="py-3 px-6"> <td class="py-3 px-6">
<input placeholder="Amount" class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-white text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" type="text" name="utxo_value" value="{{ w.utxo_value }}"> <input placeholder="Amount" class="hover:border-blue-500 bg-gray-50 text-gray-900 appearance-none pr-10 dark:bg-gray-500 dark:text-white border border-gray-300 dark:border-gray-400 dark:text-gray-50 dark:placeholder-gray-400 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 focus:ring-0" type="text" name="utxo_value" value="{{ w.utxo_value }}">
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -691,6 +691,7 @@ def page_offers(self, url_split, post_string, sent=False):
ci_from = swap_client.ci(Coins(o.coin_from)) ci_from = swap_client.ci(Coins(o.coin_from))
ci_to = swap_client.ci(Coins(o.coin_to)) ci_to = swap_client.ci(Coins(o.coin_to))
is_expired = o.expire_at <= now is_expired = o.expire_at <= now
amount_negotiable = "Yes" if o.amount_negotiable else "No"
formatted_offers.append(( formatted_offers.append((
format_timestamp(o.created_at), format_timestamp(o.created_at),
o.offer_id.hex(), o.offer_id.hex(),
@ -705,7 +706,8 @@ def page_offers(self, url_split, post_string, sent=False):
ci_from.format_amount(completed_amount), ci_from.format_amount(completed_amount),
is_expired, is_expired,
o.active_ind, o.active_ind,
strSwapDesc(o.swap_type))) strSwapDesc(o.swap_type),
amount_negotiable))
coins_from, coins_to = listAvailableCoins(swap_client, split_from=True) coins_from, coins_to = listAvailableCoins(swap_client, split_from=True)