Merge pull request #119 from gerlofvanek/shutdown

ui: Style info/error templates + disable shutdown button when swap is in progress.
This commit is contained in:
tecnovert 2024-09-13 19:53:04 +00:00 committed by GitHub
commit 4b18ddfe79
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 439 additions and 143 deletions

View file

@ -1,42 +1,39 @@
.padded_row td
{
padding-top:1.5em;
}
.bold
{
/* General Styles */
.bold {
font-weight: bold;
}
.monospace
{
.monospace {
font-family: monospace;
}
.floatright
{
.floatright {
position: fixed;
top: 1.25rem;
right: 1.25rem;
z-index: 9999;
}
.error_msg
{
/* Table Styles */
.padded_row td {
padding-top: 1.5em;
}
/* Modal Styles */
.modal-highest {
z-index: 9999;
}
/* Animation */
#hide {
-moz-animation: cssAnimation 0s ease-in 15s forwards;
/* Firefox */
-webkit-animation: cssAnimation 0s ease-in 15s forwards;
/* Safari and Chrome */
-o-animation: cssAnimation 0s ease-in 15s forwards;
/* Opera */
animation: cssAnimation 0s ease-in 15s forwards;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
@keyframes cssAnimation {
to {
width: 0;
@ -44,6 +41,7 @@
overflow: hidden;
}
}
@-webkit-keyframes cssAnimation {
to {
width: 0;
@ -52,6 +50,7 @@
}
}
/* Custom Select Styles */
.custom-select .select {
appearance: none;
background-image: url('/static/images/other/coin.png');
@ -95,8 +94,9 @@
display: block;
}
/* Blur and Overlay Styles */
.blurred {
filter: blur(4px);
filter: blur(3px);
pointer-events: none;
user-select: none;
}
@ -107,7 +107,7 @@
user-select: auto;
}
/* Disable opacity on disabled form elements in Chrome */
/* Form Element Styles */
@media screen and (-webkit-min-device-pixel-ratio:0) {
select:disabled,
input:disabled,
@ -120,6 +120,7 @@
border: 1px solid red !important;
}
/* Active Container Styles */
.active-container {
position: relative;
border-radius: 10px;
@ -137,6 +138,7 @@
pointer-events: none;
}
/* Center Spin Animation */
.center-spin {
display: flex;
justify-content: center;
@ -148,10 +150,11 @@
100% { transform: rotate(360deg); }
}
.hover-container:hover #coin_to_button, .hover-container:hover #coin_to {
border-color: #3b82f6;
}
.hover-container:hover #coin_from_button, .hover-container:hover #coin_from {
/* Hover Container Styles */
.hover-container:hover #coin_to_button,
.hover-container:hover #coin_to,
.hover-container:hover #coin_from_button,
.hover-container:hover #coin_from {
border-color: #3b82f6;
}
@ -161,6 +164,7 @@
background-size: 20px 20px;
}
/* Input-like Container Styles */
.input-like-container {
max-width: 100%;
background-color: #ffffff;
@ -172,29 +176,33 @@
line-height: 1.25rem;
outline: none;
word-wrap: break-word;
height: 90px;
color: #374151;
border-radius: 0.375rem;
font-size: 0.875rem;
line-height: 1.25rem;
outline: none;
overflow-wrap: break-word;
word-break: break-all;
height: auto;
min-height: 90px;
max-height: 150px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow-y: auto;
}
.input-like-container.dark {
background-color: #374151;
color: #ffffff;
}
.input-like-container.copying {
width: inherit;
}
/* QR Code Styles */
.qrcode {
position: relative;
display: inline-block;
padding: 10px;
overflow: hidden;
position: relative;
}
.qrcode-border {
@ -221,59 +229,52 @@
margin-top: 25px;
}
select.select-disabled {
opacity: 0.40 !important;
}
.disabled-input-enabled {
opacity: 0.40 !important;
}
/* Disabled Element Styles */
select.select-disabled,
.disabled-input-enabled,
select.disabled-select-enabled {
opacity: 0.40 !important;
}
.custom-select .select {
appearance: none;
background-position: 10px center;
background-repeat: no-repeat;
position: relative;
/* Shutdown Modal Styles */
#shutdownModal {
z-index: 50;
}
.custom-select select::-webkit-scrollbar {
width: 0;
#shutdownModal > div:first-child {
z-index: 40;
}
.custom-select .select option {
padding-left: 0;
text-indent: 0;
background-repeat: no-repeat;
background-position: 0 50%;
#shutdownModal > div:last-child {
z-index: 50;
}
.custom-select .select option.no-space {
padding-left: 0;
#shutdownModal > div {
transition: opacity 0.3s ease-out;
}
.custom-select .select option[data-image] {
background-image: url('');
#shutdownModal.hidden > div {
opacity: 0;
}
.custom-select .select-icon {
position: absolute;
top: 50%;
left: 10px;
transform: translateY(-50%);
#shutdownModal:not(.hidden) > div {
opacity: 1;
}
.custom-select .select-image {
display: none;
margin-top: 10px;
.shutdown-button {
transition: all 0.3s ease;
}
.custom-select .select:focus+.select-dropdown .select-image {
display: block;
.shutdown-button.shutdown-disabled {
opacity: 0.6;
cursor: not-allowed;
color: #a0aec0;
}
.shutdown-button.shutdown-disabled:hover {
background-color: #4a5568;
}
.shutdown-button.shutdown-disabled svg {
opacity: 0.5;
}

View file

@ -2,12 +2,122 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel=icon sizes="32x32" type="image/png" href="/static/images/favicon-32.png">
<title>(BSX) BasicSwap - v{{ version }}</title>
<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/style.css" rel="stylesheet">
<script src="/static/js/main.js"></script>
<script src="/static/js/libs/flowbite.js"></script>
<script>
const isDarkMode =
localStorage.getItem('color-theme') === 'dark' ||
(!localStorage.getItem('color-theme') &&
window.matchMedia('(prefers-color-scheme: dark)').matches);
if (!localStorage.getItem('color-theme')) {
localStorage.setItem('color-theme', isDarkMode ? 'dark' : 'light');
}
document.documentElement.classList.toggle('dark', isDarkMode);
</script>
<link rel=icon sizes="32x32" type="image/png" href="/static/images/favicon/favicon-32.png">
<title>(BSX) BasicSwap - Info</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
}
.container {
width: 100%;
max-width: 600px;
}
</style>
</head>
<body>
<h2>{{ title_str }}</h2>
<p>Info: {{ message_str }}</p>
<p><a href="/">home</a></p>
<body class="dark:bg-gray-700">
<div class="container px-4 mx-auto">
<div class="text-center">
<a class="inline-block mb-6" href="#">
<img src="/static/images/logos/basicswap-logo.svg" class="h-20 imageshow dark-image">
<img src="/static/images/logos/basicswap-logo-dark.svg" class="h-20 imageshow light-image">
</a>
<div class="p-6 bg-coolGray-100 dark:bg-gray-800 rounded-lg shadow-md">
<h2 class="text-xl font-bold mb-4 text-coolGray-900 dark:text-white">ERROR:</h2>
<p class="text-lg text-coolGray-500 dark:text-white mb-6">{{ message_str }}</p>
<a href="/" class="inline-block py-2 px-4 bg-blue-500 hover:bg-blue-600 text-white rounded-md transition duration-300">Home</a>
</div>
<p class="mt-10">
<span class="text-xs font-medium dark:text-white">Need help?</span>
<a class="inline-block text-xs font-medium text-blue-500 hover:text-blue-600 hover:underline" href="https://academy.particl.io/en/latest/faq/get_support.html" target="_blank">Help / Tutorials</a>
</p>
<p>
<span class="text-xs font-medium text-coolGray-500 dark:text-gray-500">{{ title }}</span>
</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Image toggling function
function toggleImages() {
const html = document.querySelector('html');
const darkImages = document.querySelectorAll('.dark-image');
const lightImages = document.querySelectorAll('.light-image');
if (html && html.classList.contains('dark')) {
toggleImageDisplay(darkImages, 'block');
toggleImageDisplay(lightImages, 'none');
} else {
toggleImageDisplay(darkImages, 'none');
toggleImageDisplay(lightImages, 'block');
}
}
function toggleImageDisplay(images, display) {
images.forEach(img => {
img.style.display = display;
});
}
// Theme toggle functionality
function setTheme(theme) {
if (theme === 'light') {
document.documentElement.classList.remove('dark');
localStorage.setItem('color-theme', 'light');
} else {
document.documentElement.classList.add('dark');
localStorage.setItem('color-theme', 'dark');
}
}
// Initialize theme
const themeToggle = document.getElementById('theme-toggle');
const themeToggleDarkIcon = document.getElementById('theme-toggle-dark-icon');
const themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
if (themeToggle && themeToggleDarkIcon && themeToggleLightIcon) {
if (localStorage.getItem('color-theme') === 'dark' || (!('color-theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
themeToggleLightIcon.classList.remove('hidden');
} else {
themeToggleDarkIcon.classList.remove('hidden');
}
themeToggle.addEventListener('click', () => {
if (localStorage.getItem('color-theme') === 'dark') {
setTheme('light');
} else {
setTheme('dark');
}
themeToggleDarkIcon.classList.toggle('hidden');
themeToggleLightIcon.classList.toggle('hidden');
toggleImages();
});
}
// Call toggleImages on load
toggleImages();
});
</script>
</body>
</html>

View file

@ -85,8 +85,60 @@
}
},
}
</script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const shutdownButtons = document.querySelectorAll('.shutdown-button');
const shutdownModal = document.getElementById('shutdownModal');
const closeModalButton = document.getElementById('closeShutdownModal');
function updateShutdownButtons() {
const activeSwaps = parseInt(shutdownButtons[0].getAttribute('data-active-swaps') || '0');
shutdownButtons.forEach(button => {
if (activeSwaps > 0) {
button.classList.add('shutdown-disabled');
button.setAttribute('data-disabled', 'true');
button.setAttribute('title', 'Cannot shutdown while swaps are in progress');
} else {
button.classList.remove('shutdown-disabled');
button.removeAttribute('data-disabled');
button.removeAttribute('title');
}
});
}
function showShutdownModal() {
shutdownModal.classList.remove('hidden');
document.body.style.overflow = 'hidden';
}
function hideShutdownModal() {
shutdownModal.classList.add('hidden');
document.body.style.overflow = '';
}
shutdownButtons.forEach(button => {
button.addEventListener('click', function(e) {
if (this.hasAttribute('data-disabled')) {
e.preventDefault();
showShutdownModal();
}
});
});
closeModalButton.addEventListener('click', hideShutdownModal);
shutdownModal.addEventListener('click', function(e) {
if (e.target === this) {
hideShutdownModal();
}
});
updateShutdownButtons();
});
</script>
<link rel=icon sizes="32x32" type="image/png" href="/static/images/favicon/favicon-32.png">
<title>(BSX) BasicSwap - v{{ version }}</title>
</head>
@ -170,17 +222,37 @@
</li>
{% if debug_mode == true %}
<li>
<a href="/automation" class="flex items-center block py-4 px-4 hover:bg-gray-10 dark:hover:bg-gray-700 dark:text-white"> <span class="sr-only">Automation Strategies</span>
<a href="/automation" class="flex items-center block py-4 px-4 hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white"> <span class="sr-only">Automation Strategies</span>
{{ automation_svg | safe }} Automation Strategies</a>
</li>
{% endif %}
</ul>
<div class="text-sm text-gray-700">
<a href="/shutdown/{{ shutdown_token }}" class="flex items-center block py-4 px-4 hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white"> <span class="sr-only">Shutdown</span>
{{ shutdown_svg | safe }} Shutdown </a>
<a href="/shutdown/{{ shutdown_token }}"
class="shutdown-button flex items-center block py-4 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white"
data-active-swaps="{{ summary.num_swapping }}">
{{ shutdown_svg | safe }}
<span class="ml-2">Shutdown</span>
</a>
</div>
</div>
<div id="shutdownModal" tabindex="-1" class="hidden fixed inset-0 z-50 overflow-y-auto overflow-x-hidden">
<div class="fixed inset-0 bg-black bg-opacity-50 transition-opacity"></div>
<div class="flex items-center justify-center min-h-screen p-4 relative z-10">
<div class="bg-white dark:bg-gray-500 rounded-lg shadow-xl max-w-md w-full">
<div class="p-6 text-center">
<svg class="mx-auto mb-4 text-gray-400 w-12 h-12 dark:text-gray-200" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 11V6m0 8h.01M19 10a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
</svg>
<h3 class="mb-5 text-lg font-normal text-gray-300 dark:text-gray-400">Cannot Shutdown</h3>
<p class="mb-5 text-sm text-gray-500 dark:text-gray-300">Shutdown is not possible while swaps are in progress. Please wait for all swaps to complete before shutting down.</p>
<button id="closeShutdownModal" type="button" class="text-white bg-red-600 hover:bg-red-800 focus:ring-0 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center">
Close
</button>
</div>
</div>
</div>
</div>
<!-- dropdown settings & tools -->
<!-- notifications -->
@ -507,9 +579,12 @@
{% endif %}
</ul>
<div class="pt-8 text-sm font-medium">
<a class="flex items-center pl-3 py-3 pr-4 text-gray-50 hover:bg-gray-900 rounded" href="/shutdown/{{ shutdown_token }}"> <span class="inline-block mr-3">
<a href="/shutdown/{{ shutdown_token }}"
class="shutdown-button flex items-center block py-4 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white"
data-active-swaps="{{ summary.num_swapping }}">
{{ shutdown_svg | safe }}
</span><span>Shutdown</span></a>
<span class="ml-2">Shutdown</span>
</a>
</div>
</div>
</nav>

View file

@ -2,12 +2,122 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel=icon sizes="32x32" type="image/png" href="/static/images/favicon-32.png">
<title>(BSX) BasicSwap - v{{ version }}</title>
<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/style.css" rel="stylesheet">
<script src="/static/js/main.js"></script>
<script src="/static/js/libs/flowbite.js"></script>
<script>
const isDarkMode =
localStorage.getItem('color-theme') === 'dark' ||
(!localStorage.getItem('color-theme') &&
window.matchMedia('(prefers-color-scheme: dark)').matches);
if (!localStorage.getItem('color-theme')) {
localStorage.setItem('color-theme', isDarkMode ? 'dark' : 'light');
}
document.documentElement.classList.toggle('dark', isDarkMode);
</script>
<link rel=icon sizes="32x32" type="image/png" href="/static/images/favicon/favicon-32.png">
<title>(BSX) BasicSwap - Info</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
}
.container {
width: 100%;
max-width: 600px;
}
</style>
</head>
<body>
<h2>{{ title_str }}</h2>
<p>Info: {{ message_str }}</p>
<p><a href="/">home</a></p>
<body class="dark:bg-gray-700">
<div class="container px-4 mx-auto">
<div class="text-center">
<a class="inline-block mb-6" href="#">
<img src="/static/images/logos/basicswap-logo.svg" class="h-20 imageshow dark-image">
<img src="/static/images/logos/basicswap-logo-dark.svg" class="h-20 imageshow light-image">
</a>
<div class="p-6 bg-coolGray-100 dark:bg-gray-800 rounded-lg shadow-md">
<h2 class="text-xl font-bold mb-4 text-coolGray-900 dark:text-white">INFO:</h2>
<p class="text-lg text-coolGray-500 dark:text-white mb-6">{{ message_str }}</p>
<a href="/" class="inline-block py-2 px-4 bg-blue-500 hover:bg-blue-600 text-white rounded-md transition duration-300">Home</a>
</div>
<p class="mt-10">
<span class="text-xs font-medium dark:text-white">Need help?</span>
<a class="inline-block text-xs font-medium text-blue-500 hover:text-blue-600 hover:underline" href="https://academy.particl.io/en/latest/faq/get_support.html" target="_blank">Help / Tutorials</a>
</p>
<p>
<span class="text-xs font-medium text-coolGray-500 dark:text-gray-500">{{ title }}</span>
</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Image toggling function
function toggleImages() {
const html = document.querySelector('html');
const darkImages = document.querySelectorAll('.dark-image');
const lightImages = document.querySelectorAll('.light-image');
if (html && html.classList.contains('dark')) {
toggleImageDisplay(darkImages, 'block');
toggleImageDisplay(lightImages, 'none');
} else {
toggleImageDisplay(darkImages, 'none');
toggleImageDisplay(lightImages, 'block');
}
}
function toggleImageDisplay(images, display) {
images.forEach(img => {
img.style.display = display;
});
}
// Theme toggle functionality
function setTheme(theme) {
if (theme === 'light') {
document.documentElement.classList.remove('dark');
localStorage.setItem('color-theme', 'light');
} else {
document.documentElement.classList.add('dark');
localStorage.setItem('color-theme', 'dark');
}
}
// Initialize theme
const themeToggle = document.getElementById('theme-toggle');
const themeToggleDarkIcon = document.getElementById('theme-toggle-dark-icon');
const themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
if (themeToggle && themeToggleDarkIcon && themeToggleLightIcon) {
if (localStorage.getItem('color-theme') === 'dark' || (!('color-theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
themeToggleLightIcon.classList.remove('hidden');
} else {
themeToggleDarkIcon.classList.remove('hidden');
}
themeToggle.addEventListener('click', () => {
if (localStorage.getItem('color-theme') === 'dark') {
setTheme('light');
} else {
setTheme('dark');
}
themeToggleDarkIcon.classList.toggle('hidden');
themeToggleLightIcon.classList.toggle('hidden');
toggleImages();
});
}
// Call toggleImages on load
toggleImages();
});
</script>
</body>
</html>