Files
archy/docker/bitcoin-ui/index.html
Dorian 6a018e4953 Implement Bitcoin and LND UI in Docker setup and enhance startup script
- Added Docker services for Bitcoin Core UI and LND UI, providing web interfaces for both applications.
- Updated the startup script to improve image pulling process and service readiness checks with retries.
- Modified the app view to open the Bitcoin Core UI in a new tab instead of routing through the app.
- Removed the Bitcoin Core Vue component as it is no longer needed, streamlining the UI structure.
- Excluded backend services from the app listing to improve clarity in the Docker package scanner.
2026-01-27 23:57:29 +00:00

645 lines
25 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bitcoin Core - Archipelago</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', sans-serif;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 50%, #16213e 100%);
min-height: 100vh;
color: white;
padding: 2rem;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
/* Archipelago Glass Card Styles */
.glass-card {
background-color: rgba(0, 0, 0, 0.65);
backdrop-filter: blur(18px);
-webkit-backdrop-filter: blur(18px);
border: 1px solid rgba(255, 255, 255, 0.18);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
border-radius: 1rem;
transition: all 0.3s ease;
}
.glass-card:hover {
transform: translateY(-2px);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6);
}
.glass-button {
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(18px);
-webkit-backdrop-filter: blur(18px);
border: 1px solid rgba(255, 255, 255, 0.18);
color: rgba(255, 255, 255, 0.9);
cursor: pointer;
transition: all 0.3s ease;
font-size: 0.875rem;
font-weight: 500;
}
.glass-button:hover {
background-color: rgba(0, 0, 0, 0.8);
border-color: rgba(255, 255, 255, 0.3);
transform: translateY(-1px);
}
.gradient-button {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(0, 0, 0, 0.8) 100%);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
color: rgba(255, 255, 255, 0.95);
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.gradient-button:hover {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, rgba(0, 0, 0, 0.9) 100%);
border-color: rgba(255, 255, 255, 0.3);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
}
/* Hero Section - Compact like AppDetails */
.hero {
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.hero-content {
display: flex;
align-items: center;
gap: 1.5rem;
}
.app-icon {
width: 5rem;
height: 5rem;
border-radius: 0.75rem;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
flex-shrink: 0;
background: white;
padding: 0.75rem;
}
.app-info {
flex: 1;
min-width: 0;
}
.app-title {
font-size: 1.5rem;
font-weight: 700;
color: white;
margin-bottom: 0.25rem;
}
.app-description {
color: rgba(255, 255, 255, 0.7);
font-size: 0.875rem;
margin-bottom: 0.5rem;
}
.status-badge {
display: inline-flex;
align-items: center;
padding: 0.375rem 0.625rem;
border-radius: 0.5rem;
font-size: 0.75rem;
font-weight: 500;
}
.status-running {
background: rgba(34, 197, 94, 0.2);
color: rgb(134, 239, 172);
border: 1px solid rgba(34, 197, 94, 0.3);
}
.status-stopped {
background: rgba(107, 114, 128, 0.2);
color: rgb(209, 213, 219);
border: 1px solid rgba(107, 114, 128, 0.3);
}
.status-dot {
width: 0.375rem;
height: 0.375rem;
border-radius: 50%;
margin-right: 0.375rem;
}
.status-running .status-dot {
background: rgb(74, 222, 128);
}
.status-stopped .status-dot {
background: rgb(156, 163, 175);
}
.version-badge {
color: rgba(255, 255, 255, 0.5);
font-size: 0.75rem;
margin-left: 0.5rem;
}
.action-buttons {
display: flex;
gap: 0.5rem;
flex-shrink: 0;
}
.action-buttons button {
padding: 0.625rem 1rem;
border-radius: 0.5rem;
font-size: 0.875rem;
display: flex;
align-items: center;
gap: 0.5rem;
border: none;
}
/* Grid Layout */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
margin-bottom: 1.5rem;
}
.grid-2col {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 1.5rem;
}
/* Info Cards */
.info-card {
padding: 1.5rem;
}
.info-card h2 {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 1rem;
color: white;
}
.info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.info-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.75rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.info-label {
color: rgba(255, 255, 255, 0.6);
font-size: 0.875rem;
}
.info-value {
color: white;
font-weight: 500;
font-family: 'Courier New', monospace;
}
/* Connection Details */
.connection-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1rem;
background: rgba(255, 255, 255, 0.03);
border-radius: 0.5rem;
border: 1px solid rgba(255, 255, 255, 0.05);
margin-bottom: 0.75rem;
}
.connection-icon {
width: 2.5rem;
height: 2.5rem;
background: rgba(255, 255, 255, 0.1);
border-radius: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
flex-shrink: 0;
}
.connection-content {
flex: 1;
}
.connection-label {
color: rgba(255, 255, 255, 0.6);
font-size: 0.75rem;
margin-bottom: 0.25rem;
}
.connection-value {
color: white;
font-size: 0.875rem;
font-weight: 600;
font-family: 'Courier New', monospace;
}
.copy-btn {
padding: 0.5rem 0.75rem;
border-radius: 0.5rem;
border: 1px solid rgba(255, 255, 255, 0.18);
background: rgba(0, 0, 0, 0.6);
color: rgba(255, 255, 255, 0.9);
font-size: 0.75rem;
cursor: pointer;
transition: all 0.2s ease;
}
.copy-btn:hover {
background: rgba(0, 0, 0, 0.8);
transform: scale(1.05);
}
/* Modal */
.modal {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(10px);
z-index: 1000;
align-items: center;
justify-content: center;
padding: 2rem;
}
.modal.active {
display: flex;
}
.modal-content {
max-width: 50rem;
width: 100%;
max-height: 80vh;
overflow-y: auto;
padding: 2rem;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.modal-title {
font-size: 1.5rem;
font-weight: 700;
}
.modal-close {
width: 2.5rem;
height: 2.5rem;
border-radius: 0.5rem;
background: rgba(255, 255, 255, 0.1);
border: none;
color: white;
cursor: pointer;
font-size: 1.5rem;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
}
.modal-close:hover {
background: rgba(255, 255, 255, 0.2);
transform: rotate(90deg);
}
.logs-container {
background: rgba(0, 0, 0, 0.4);
border-radius: 0.5rem;
padding: 1rem;
font-family: 'Courier New', monospace;
font-size: 0.75rem;
line-height: 1.6;
color: rgba(255, 255, 255, 0.8);
white-space: pre-wrap;
word-break: break-all;
}
/* Responsive */
@media (max-width: 768px) {
.hero-content {
flex-direction: column;
text-align: center;
}
.action-buttons {
flex-direction: column;
width: 100%;
}
.grid-2col {
grid-template-columns: 1fr;
}
.info-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<!-- Hero Section - Compact -->
<div class="glass-card hero">
<div class="hero-content">
<img
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23f7931a' d='M23.638 14.904c-1.602 6.43-8.113 10.34-14.542 8.736C2.67 22.05-1.244 15.525.362 9.105 1.962 2.67 8.475-1.243 14.9.358c6.43 1.605 10.342 8.115 8.738 14.548v-.002zm-6.35-4.613c.24-1.59-.974-2.45-2.64-3.03l.54-2.153-1.315-.33-.525 2.107c-.345-.087-.705-.167-1.064-.25l.526-2.127-1.32-.33-.54 2.165c-.285-.067-.565-.132-.84-.2l-1.815-.45-.35 1.407s.975.225.955.236c.535.136.63.486.615.766l-1.477 5.92c-.075.166-.24.406-.614.314.015.02-.96-.24-.96-.24l-.66 1.51 1.71.426.93.242-.54 2.19 1.32.327.54-2.17c.36.1.705.19 1.05.273l-.51 2.154 1.32.33.545-2.19c2.24.427 3.93.257 4.64-1.774.57-1.637-.03-2.58-1.217-3.196.854-.193 1.5-.76 1.68-1.93h.01zm-3.01 4.22c-.404 1.64-3.157.75-4.05.53l.72-2.9c.896.23 3.757.67 3.33 2.37zm.41-4.24c-.37 1.49-2.662.735-3.405.55l.654-2.64c.744.18 3.137.524 2.75 2.084v.006z'/%3E%3C/svg%3E"
alt="Bitcoin Core"
class="app-icon"
/>
<div class="app-info">
<h1 class="app-title">Bitcoin Core</h1>
<p class="app-description">Full Bitcoin node implementation</p>
<div>
<span class="status-badge status-running" id="statusBadge">
<span class="status-dot"></span>
Running
</span>
<span class="version-badge">v27.0</span>
</div>
</div>
<div class="action-buttons">
<button class="gradient-button" onclick="openLogs()">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Logs
</button>
<button class="glass-button" onclick="openSettings()">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Settings
</button>
</div>
</div>
</div>
<!-- Main Grid -->
<div class="grid-2col">
<!-- Left Column - Info -->
<div>
<!-- Network Stats -->
<div class="glass-card info-card" style="margin-bottom: 1.5rem;">
<h2>Network Status</h2>
<div class="info-grid">
<div class="info-item">
<span class="info-label">Network</span>
<span class="info-value">Regtest</span>
</div>
<div class="info-item">
<span class="info-label">Block Height</span>
<span class="info-value" id="blockHeight">0</span>
</div>
<div class="info-item">
<span class="info-label">RPC Port</span>
<span class="info-value">18443</span>
</div>
<div class="info-item">
<span class="info-label">P2P Port</span>
<span class="info-value">18444</span>
</div>
</div>
</div>
<!-- Connection Details -->
<div class="glass-card info-card">
<h2>Connection Details</h2>
<div class="connection-item">
<div class="connection-icon">🌐</div>
<div class="connection-content">
<div class="connection-label">RPC Host</div>
<div class="connection-value">localhost:18443</div>
</div>
<button class="copy-btn" onclick="copyToClipboard('localhost:18443')">Copy</button>
</div>
<div class="connection-item">
<div class="connection-icon">👤</div>
<div class="connection-content">
<div class="connection-label">RPC User</div>
<div class="connection-value">bitcoin</div>
</div>
<button class="copy-btn" onclick="copyToClipboard('bitcoin')">Copy</button>
</div>
<div class="connection-item">
<div class="connection-icon">🔑</div>
<div class="connection-content">
<div class="connection-label">RPC Password</div>
<div class="connection-value">bitcoinpass</div>
</div>
<button class="copy-btn" onclick="copyToClipboard('bitcoinpass')">Copy</button>
</div>
<div class="connection-item">
<div class="connection-icon">📡</div>
<div class="connection-content">
<div class="connection-label">ZMQ Block</div>
<div class="connection-value">tcp://localhost:28332</div>
</div>
<button class="copy-btn" onclick="copyToClipboard('tcp://localhost:28332')">Copy</button>
</div>
</div>
</div>
<!-- Right Column - About -->
<div class="glass-card info-card">
<h2>About Bitcoin Core</h2>
<p style="color: rgba(255, 255, 255, 0.8); line-height: 1.6; margin-bottom: 1.5rem;">
Bitcoin Core is the reference implementation of the Bitcoin protocol. It includes a transaction verification engine and connects to the Bitcoin network as a full node.
</p>
<h3 style="font-size: 1.125rem; font-weight: 600; margin-bottom: 0.75rem;">Features</h3>
<ul style="list-style: none; padding: 0;">
<li style="display: flex; align-items: start; gap: 0.75rem; margin-bottom: 0.75rem; color: rgba(255, 255, 255, 0.8);">
<svg style="width: 1.5rem; height: 1.5rem; color: rgb(74, 222, 128); flex-shrink: 0; margin-top: 0.125rem;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>Full node verification</span>
</li>
<li style="display: flex; align-items: start; gap: 0.75rem; margin-bottom: 0.75rem; color: rgba(255, 255, 255, 0.8);">
<svg style="width: 1.5rem; height: 1.5rem; color: rgb(74, 222, 128); flex-shrink: 0; margin-top: 0.125rem;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>RPC API access</span>
</li>
<li style="display: flex; align-items: start; gap: 0.75rem; margin-bottom: 0.75rem; color: rgba(255, 255, 255, 0.8);">
<svg style="width: 1.5rem; height: 1.5rem; color: rgb(74, 222, 128); flex-shrink: 0; margin-top: 0.125rem;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>ZMQ notifications</span>
</li>
<li style="display: flex; align-items: start; gap: 0.75rem; color: rgba(255, 255, 255, 0.8);">
<svg style="width: 1.5rem; height: 1.5rem; color: rgb(74, 222, 128); flex-shrink: 0; margin-top: 0.125rem;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>Transaction indexing</span>
</li>
</ul>
<div style="margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid rgba(255, 255, 255, 0.1);">
<div style="display: flex; justify-content: space-between; padding: 0.5rem 0;">
<span style="color: rgba(255, 255, 255, 0.6); font-size: 0.875rem;">Version</span>
<span style="color: white; font-weight: 500;">27.0</span>
</div>
<div style="display: flex; justify-content: space-between; padding: 0.5rem 0;">
<span style="color: rgba(255, 255, 255, 0.6); font-size: 0.875rem;">License</span>
<span style="color: white; font-weight: 500;">MIT</span>
</div>
<div style="display: flex; justify-content: space-between; padding: 0.5rem 0;">
<span style="color: rgba(255, 255, 255, 0.6); font-size: 0.875rem;">Developer</span>
<span style="color: white; font-weight: 500;">Bitcoin Core</span>
</div>
</div>
</div>
</div>
</div>
<!-- Settings Modal -->
<div class="modal" id="settingsModal">
<div class="modal-content glass-card">
<div class="modal-header">
<h2 class="modal-title">Node Settings</h2>
<button class="modal-close" onclick="closeSettings()">×</button>
</div>
<div style="padding: 1rem; background: rgba(255, 255, 255, 0.03); border-radius: 0.5rem; margin-bottom: 0.75rem;">
<div style="font-weight: 600; margin-bottom: 0.5rem; color: white;">Network Mode</div>
<div style="color: rgba(255, 255, 255, 0.7);">Regtest (Development)</div>
</div>
<div style="padding: 1rem; background: rgba(255, 255, 255, 0.03); border-radius: 0.5rem; margin-bottom: 0.75rem;">
<div style="font-weight: 600; margin-bottom: 0.5rem; color: white;">Transaction Index</div>
<div style="color: rgba(255, 255, 255, 0.7);">Enabled (txindex=1)</div>
</div>
<div style="padding: 1rem; background: rgba(255, 255, 255, 0.03); border-radius: 0.5rem; margin-bottom: 0.75rem;">
<div style="font-weight: 600; margin-bottom: 0.5rem; color: white;">ZMQ Publishing</div>
<div style="color: rgba(255, 255, 255, 0.7);">Block & TX notifications enabled</div>
</div>
<div style="padding: 1rem; background: rgba(255, 255, 255, 0.03); border-radius: 0.5rem;">
<div style="font-weight: 600; margin-bottom: 0.5rem; color: white;">RPC Access</div>
<div style="color: rgba(255, 255, 255, 0.7);">Enabled on 0.0.0.0:18443</div>
</div>
</div>
</div>
<!-- Logs Modal -->
<div class="modal" id="logsModal">
<div class="modal-content glass-card">
<div class="modal-header">
<h2 class="modal-title">Node Logs</h2>
<button class="modal-close" onclick="closeLogs()">×</button>
</div>
<div class="logs-container" id="logsContent">
Loading logs...
</div>
</div>
</div>
<script>
// Copy to clipboard
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
alert('Copied to clipboard!');
}).catch(err => {
console.error('Failed to copy:', err);
});
}
// Settings modal
function openSettings() {
document.getElementById('settingsModal').classList.add('active');
}
function closeSettings() {
document.getElementById('settingsModal').classList.remove('active');
}
// Logs modal
function openLogs() {
document.getElementById('logsModal').classList.add('active');
loadLogs();
}
function closeLogs() {
document.getElementById('logsModal').classList.remove('active');
}
function loadLogs() {
const logsContent = document.getElementById('logsContent');
logsContent.textContent = `Bitcoin Core version v27.0
Assuming ancestors of block 0000000000000000000000000000000000000000000000000000000000000000 have valid signatures.
Setting nMinimumChainWork=0000000000000000000000000000000000000000000000000000000000000000
Regtest mode activated
RPC server listening on 0.0.0.0:18443
ZMQ block notifications enabled on tcp://0.0.0.0:28332
ZMQ tx notifications enabled on tcp://0.0.0.0:28333
Transaction index enabled (txindex=1)
Node initialization complete
Ready to accept connections on port 18444`;
}
// Simulate block height updates
let blockHeight = 0;
setInterval(() => {
if (Math.random() > 0.7) {
blockHeight++;
document.getElementById('blockHeight').textContent = blockHeight;
}
}, 5000);
// Close modals on escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeSettings();
closeLogs();
}
});
// Close modals when clicking outside
document.querySelectorAll('.modal').forEach(modal => {
modal.addEventListener('click', (e) => {
if (e.target === modal) {
closeSettings();
closeLogs();
}
});
});
</script>
</body>
</html>