589 lines
15 KiB
Markdown
589 lines
15 KiB
Markdown
|
|
# Archipelago App UI Standards - For Apps Without Native UIs
|
|||
|
|
|
|||
|
|
**Version:** 1.0
|
|||
|
|
**Last Updated:** 2026-02-03
|
|||
|
|
|
|||
|
|
## Overview
|
|||
|
|
|
|||
|
|
This document defines the **standard UI pattern** for containerized applications that don't have their own web interface (e.g., Bitcoin Core, LND, Core Lightning, mempool backend services, etc.).
|
|||
|
|
|
|||
|
|
These UIs provide a simple, elegant way to:
|
|||
|
|
- Monitor service status and metrics
|
|||
|
|
- View connection information (RPC, REST, gRPC endpoints)
|
|||
|
|
- Access logs and settings
|
|||
|
|
- Copy configuration details for external tools
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Architecture
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────┐
|
|||
|
|
│ Nginx Container (Alpine) │
|
|||
|
|
│ - Serves static HTML/CSS/JS │
|
|||
|
|
│ - Port 8XXX (unique per service) │
|
|||
|
|
│ - Optional: Proxies RPC/API calls │
|
|||
|
|
└─────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### File Structure
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
docker/
|
|||
|
|
├── {service-name}-ui/
|
|||
|
|
│ ├── index.html # Main UI file
|
|||
|
|
│ ├── Dockerfile # Container build
|
|||
|
|
│ ├── nginx.conf # Nginx config
|
|||
|
|
│ ├── {service-icon} # App icon (svg/webp/png)
|
|||
|
|
│ └── bg-{theme}.jpg # Background image
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Standard UI Components
|
|||
|
|
|
|||
|
|
### 1. **CSS Class System**
|
|||
|
|
|
|||
|
|
#### `.glass-card` - Main Container Cards
|
|||
|
|
Used for: Header, main sections, modals
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
.glass-card {
|
|||
|
|
position: relative;
|
|||
|
|
background: rgba(0, 0, 0, 0.60);
|
|||
|
|
backdrop-filter: blur(24px);
|
|||
|
|
-webkit-backdrop-filter: blur(24px);
|
|||
|
|
box-shadow:
|
|||
|
|
0 8px 24px rgba(0, 0, 0, 0.45),
|
|||
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.22);
|
|||
|
|
border-radius: 1rem;
|
|||
|
|
overflow-x: hidden;
|
|||
|
|
overflow-y: visible;
|
|||
|
|
border: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.glass-card::before {
|
|||
|
|
content: '';
|
|||
|
|
position: absolute;
|
|||
|
|
inset: 0;
|
|||
|
|
border-radius: inherit;
|
|||
|
|
padding: 2px;
|
|||
|
|
background: linear-gradient(135deg, rgba(0, 0, 0, 0.8), transparent);
|
|||
|
|
-webkit-mask:
|
|||
|
|
linear-gradient(#fff 0 0) content-box,
|
|||
|
|
linear-gradient(#fff 0 0);
|
|||
|
|
-webkit-mask-composite: xor;
|
|||
|
|
mask-composite: exclude;
|
|||
|
|
pointer-events: none;
|
|||
|
|
z-index: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.glass-card > * {
|
|||
|
|
position: relative;
|
|||
|
|
z-index: 2;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `.info-card` - Stat Display Cards
|
|||
|
|
Used for: Status badges, metric displays (non-interactive)
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
.info-card {
|
|||
|
|
position: relative;
|
|||
|
|
background: rgba(0, 0, 0, 0.60);
|
|||
|
|
backdrop-filter: blur(24px);
|
|||
|
|
-webkit-backdrop-filter: blur(24px);
|
|||
|
|
box-shadow:
|
|||
|
|
0 8px 24px rgba(0, 0, 0, 0.45),
|
|||
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.22);
|
|||
|
|
border-radius: 16px;
|
|||
|
|
padding: 12px;
|
|||
|
|
border: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.info-card::before {
|
|||
|
|
content: '';
|
|||
|
|
position: absolute;
|
|||
|
|
inset: 0;
|
|||
|
|
border-radius: inherit;
|
|||
|
|
padding: 2px;
|
|||
|
|
background: linear-gradient(135deg, rgba(0, 0, 0, 0.8), transparent);
|
|||
|
|
-webkit-mask:
|
|||
|
|
linear-gradient(#fff 0 0) content-box,
|
|||
|
|
linear-gradient(#fff 0 0);
|
|||
|
|
-webkit-mask-composite: xor;
|
|||
|
|
mask-composite: exclude;
|
|||
|
|
pointer-events: none;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**No hover effects** - These are display-only elements.
|
|||
|
|
|
|||
|
|
#### `.info-card-button` - Interactive Action Buttons
|
|||
|
|
Used for: Primary action buttons (Copy Info, View Logs, etc.)
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
.info-card-button {
|
|||
|
|
/* Same base styles as .info-card */
|
|||
|
|
position: relative;
|
|||
|
|
background: rgba(0, 0, 0, 0.60);
|
|||
|
|
backdrop-filter: blur(24px);
|
|||
|
|
-webkit-backdrop-filter: blur(24px);
|
|||
|
|
box-shadow:
|
|||
|
|
0 8px 24px rgba(0, 0, 0, 0.45),
|
|||
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.22);
|
|||
|
|
border-radius: 16px;
|
|||
|
|
padding: 12px;
|
|||
|
|
transition: all 0.3s ease;
|
|||
|
|
border: none;
|
|||
|
|
cursor: pointer;
|
|||
|
|
color: rgba(255, 255, 255, 0.9);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.info-card-button::before {
|
|||
|
|
/* Same gradient as .info-card */
|
|||
|
|
content: '';
|
|||
|
|
position: absolute;
|
|||
|
|
inset: 0;
|
|||
|
|
border-radius: inherit;
|
|||
|
|
padding: 2px;
|
|||
|
|
background: linear-gradient(135deg, rgba(0, 0, 0, 0.8), transparent);
|
|||
|
|
-webkit-mask:
|
|||
|
|
linear-gradient(#fff 0 0) content-box,
|
|||
|
|
linear-gradient(#fff 0 0);
|
|||
|
|
-webkit-mask-composite: xor;
|
|||
|
|
mask-composite: exclude;
|
|||
|
|
pointer-events: none;
|
|||
|
|
transition: all 0.3s ease;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Hover state - lifts and brightens */
|
|||
|
|
.info-card-button:hover {
|
|||
|
|
transform: translateY(-2px);
|
|||
|
|
background: rgba(0, 0, 0, 0.35);
|
|||
|
|
box-shadow:
|
|||
|
|
0 12px 32px rgba(0, 0, 0, 0.6),
|
|||
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.25);
|
|||
|
|
color: rgba(255, 255, 255, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.info-card-button:hover::before {
|
|||
|
|
background: linear-gradient(135deg, rgba(255, 255, 255, 0.3), transparent);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Active state - press down */
|
|||
|
|
.info-card-button:active {
|
|||
|
|
transform: translateY(1px);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `.glass-button` - Secondary Buttons
|
|||
|
|
Used for: Settings, Close (×), secondary actions
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
.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);
|
|||
|
|
transition: all 0.3s ease;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.glass-button:hover {
|
|||
|
|
color: white;
|
|||
|
|
background-color: rgba(0, 0, 0, 0.7);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Simple Info Rows - `bg-white/5`
|
|||
|
|
Used for: Non-interactive info rows (RPC Host, Network, Status, etc.)
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
|||
|
|
<div class="flex items-center gap-3">
|
|||
|
|
<svg class="w-5 h-5 text-white/60"><!-- icon --></svg>
|
|||
|
|
<span class="text-white/80 text-sm">Label</span>
|
|||
|
|
</div>
|
|||
|
|
<span class="text-white/60 text-sm">Value</span>
|
|||
|
|
</div>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**No gradient borders** - These are simple read-only display elements.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Standard Layout Pattern
|
|||
|
|
|
|||
|
|
### 1. **Header Section** (`.glass-card`)
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<div class="glass-card p-6 mb-6">
|
|||
|
|
<div class="flex flex-col md:flex-row items-center md:items-center gap-4 md:gap-6">
|
|||
|
|
<!-- Logo (left) -->
|
|||
|
|
<div class="flex-shrink-0">
|
|||
|
|
<div class="logo-gradient-border">
|
|||
|
|
<img src="/assets/img/app-icons/{service-icon}" alt="{Service Name}" />
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- Title and Description (center) -->
|
|||
|
|
<div class="flex-1 min-w-0">
|
|||
|
|
<h1 class="text-3xl font-bold text-white mb-2">{Service Name}</h1>
|
|||
|
|
<p class="text-white/70">{Service Description}</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- Status Info (right) - OPTIONAL for headers with status -->
|
|||
|
|
<div class="w-full md:w-auto flex flex-col md:flex-row gap-3 md:gap-4">
|
|||
|
|
<div class="info-card flex items-center gap-3">
|
|||
|
|
<!-- Status info -->
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. **Quick Status Bar** (`.glass-card` with `.info-card` grid)
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<div class="glass-card p-6 mb-6">
|
|||
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|||
|
|
<div class="info-card flex items-center justify-between">
|
|||
|
|
<!-- Status indicator -->
|
|||
|
|
</div>
|
|||
|
|
<!-- ... more status cards -->
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. **Main Content Sections** (`.glass-card` grid)
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
|||
|
|
<!-- Service 1: Node Status -->
|
|||
|
|
<div class="glass-card p-6">
|
|||
|
|
<div class="flex items-start gap-4 mb-4">
|
|||
|
|
<div class="flex-shrink-0 w-12 h-12 rounded-lg bg-white/10 flex items-center justify-center">
|
|||
|
|
<svg><!-- icon --></svg>
|
|||
|
|
</div>
|
|||
|
|
<div class="flex-1">
|
|||
|
|
<h2 class="text-xl font-semibold text-white mb-2">Section Title</h2>
|
|||
|
|
<p class="text-white/70 text-sm mb-4">Section description</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="space-y-3">
|
|||
|
|
<!-- Info rows (bg-white/5) -->
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<button class="mt-4 w-full info-card-button text-sm font-medium" onclick="action()">
|
|||
|
|
Action Button
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- ... more sections -->
|
|||
|
|
</div>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. **Modals** (`.glass-card` with backdrop)
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<div class="modal hidden fixed inset-0 bg-black/80 backdrop-blur-sm z-50 items-center justify-center p-4" id="modalId">
|
|||
|
|
<div class="glass-card p-6 max-w-2xl w-full max-h-[80vh] overflow-y-auto">
|
|||
|
|
<div class="flex justify-between items-center mb-4">
|
|||
|
|
<h2 class="text-2xl font-bold text-white">Modal Title</h2>
|
|||
|
|
<button onclick="closeModal()" class="glass-button px-3 py-2 rounded-lg text-xl font-medium">×</button>
|
|||
|
|
</div>
|
|||
|
|
<!-- Modal content -->
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Visual Hierarchy
|
|||
|
|
|
|||
|
|
### **Container Importance (Most → Least)**
|
|||
|
|
|
|||
|
|
1. **`.glass-card`** - Main containers, sections, modals
|
|||
|
|
- Gradient border, strong blur (24px), inset highlights
|
|||
|
|
|
|||
|
|
2. **`.info-card`** - Stat displays, status badges
|
|||
|
|
- Gradient border, backdrop blur, **NO hover effects**
|
|||
|
|
|
|||
|
|
3. **`.info-card-button`** - Primary action buttons
|
|||
|
|
- Same as `.info-card` in default state
|
|||
|
|
- **WITH hover effects** (lift, brighten, enhanced gradient)
|
|||
|
|
|
|||
|
|
4. **`bg-white/5`** - Simple info rows
|
|||
|
|
- Dark background, **NO borders**, **NO hover**
|
|||
|
|
|
|||
|
|
5. **`.glass-button`** - Secondary buttons
|
|||
|
|
- Simple glass effect, minimal hover
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Port Assignments
|
|||
|
|
|
|||
|
|
Reserve unique ports for each service UI:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
8334 - Bitcoin Knots UI
|
|||
|
|
8081 - LND UI
|
|||
|
|
8082 - Core Lightning UI (future)
|
|||
|
|
8083 - Mempool UI (future)
|
|||
|
|
8084 - BTCPay Server UI (future)
|
|||
|
|
...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Update backend's `docker_packages.rs` to map these ports:
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
} else if app_id == "lnd" {
|
|||
|
|
Some("http://localhost:8081".to_string())
|
|||
|
|
} else if app_id == "bitcoin-knots" {
|
|||
|
|
Some("http://localhost:8334".to_string())
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Dockerfile Template
|
|||
|
|
|
|||
|
|
```dockerfile
|
|||
|
|
FROM docker.io/library/nginx:alpine
|
|||
|
|
|
|||
|
|
# Copy the HTML file
|
|||
|
|
COPY index.html /usr/share/nginx/html/
|
|||
|
|
|
|||
|
|
# Create directories for assets
|
|||
|
|
RUN mkdir -p /usr/share/nginx/html/assets/img/app-icons && \
|
|||
|
|
mkdir -p /usr/share/nginx/html/assets/img
|
|||
|
|
|
|||
|
|
# Copy assets
|
|||
|
|
COPY {service-icon} /usr/share/nginx/html/assets/img/app-icons/
|
|||
|
|
COPY bg-{theme}.jpg /usr/share/nginx/html/assets/img/
|
|||
|
|
|
|||
|
|
# Copy nginx config
|
|||
|
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|||
|
|
|
|||
|
|
EXPOSE 80
|
|||
|
|
|
|||
|
|
CMD ["nginx", "-g", "daemon off;"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Nginx Config Template
|
|||
|
|
|
|||
|
|
### Simple Static Serving (LND, most services)
|
|||
|
|
|
|||
|
|
```nginx
|
|||
|
|
server {
|
|||
|
|
listen 8XXX; # Unique port for this service
|
|||
|
|
server_name _;
|
|||
|
|
|
|||
|
|
root /usr/share/nginx/html;
|
|||
|
|
index index.html;
|
|||
|
|
|
|||
|
|
location / {
|
|||
|
|
try_files $uri $uri/ /index.html;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### With RPC Proxy (Bitcoin Knots)
|
|||
|
|
|
|||
|
|
```nginx
|
|||
|
|
server {
|
|||
|
|
listen 8334;
|
|||
|
|
server_name _;
|
|||
|
|
|
|||
|
|
root /usr/share/nginx/html;
|
|||
|
|
index index.html;
|
|||
|
|
|
|||
|
|
# RPC proxy to avoid CORS issues
|
|||
|
|
location /bitcoin-rpc/ {
|
|||
|
|
proxy_pass http://127.0.0.1:8332/;
|
|||
|
|
proxy_http_version 1.1;
|
|||
|
|
proxy_set_header Host $host;
|
|||
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|||
|
|
proxy_set_header Authorization "Basic {BASE64_ENCODED_CREDS}";
|
|||
|
|
add_header Access-Control-Allow-Origin *;
|
|||
|
|
add_header Access-Control-Allow-Methods "POST, GET, OPTIONS";
|
|||
|
|
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
|||
|
|
if ($request_method = OPTIONS) {
|
|||
|
|
return 204;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
location / {
|
|||
|
|
try_files $uri $uri/ /index.html;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Deployment
|
|||
|
|
|
|||
|
|
### Build and Run
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Build the image
|
|||
|
|
cd docker/{service}-ui
|
|||
|
|
sudo podman build -t {service}-ui:latest .
|
|||
|
|
|
|||
|
|
# Run the container
|
|||
|
|
sudo podman run -d \
|
|||
|
|
--name {service}-ui \
|
|||
|
|
--restart unless-stopped \
|
|||
|
|
--network=host \
|
|||
|
|
--label 'com.archipelago.parent-app={service-id}' \
|
|||
|
|
{service}-ui:latest
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Backend Integration
|
|||
|
|
|
|||
|
|
Update `core/archipelago/src/container/docker_packages.rs`:
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
} else if app_id == "{service-id}" {
|
|||
|
|
Some("http://localhost:8XXX".to_string())
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Reference Implementations
|
|||
|
|
|
|||
|
|
### ✅ Bitcoin Knots UI
|
|||
|
|
- **Location:** `docker/bitcoin-ui/`
|
|||
|
|
- **Port:** 8334
|
|||
|
|
- **Features:**
|
|||
|
|
- Live sync status with animations
|
|||
|
|
- RPC proxy for CORS handling
|
|||
|
|
- Real-time block updates
|
|||
|
|
- Connection info display
|
|||
|
|
|
|||
|
|
### ✅ LND UI
|
|||
|
|
- **Location:** `docker/lnd-ui/`
|
|||
|
|
- **Port:** 8081
|
|||
|
|
- **Features:**
|
|||
|
|
- Node status monitoring
|
|||
|
|
- Channel count display
|
|||
|
|
- REST API + gRPC info
|
|||
|
|
- Settings and logs modals
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Benefits of This Approach
|
|||
|
|
|
|||
|
|
1. **Consistency** - All service UIs look and feel the same
|
|||
|
|
2. **Lightweight** - Nginx Alpine base (~10MB)
|
|||
|
|
3. **Fast Development** - Copy template, customize content
|
|||
|
|
4. **Mobile Responsive** - Works on all screen sizes
|
|||
|
|
5. **Low Resource Usage** - Static files, minimal CPU/RAM
|
|||
|
|
6. **Easy Maintenance** - Single pattern to update globally
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Creating a New Service UI
|
|||
|
|
|
|||
|
|
### Step-by-Step Process
|
|||
|
|
|
|||
|
|
1. **Create Directory Structure**
|
|||
|
|
```bash
|
|||
|
|
mkdir -p docker/{service}-ui
|
|||
|
|
cd docker/{service}-ui
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **Copy Template Files**
|
|||
|
|
```bash
|
|||
|
|
cp ../bitcoin-ui/index.html ./
|
|||
|
|
cp ../bitcoin-ui/Dockerfile ./
|
|||
|
|
cp ../bitcoin-ui/nginx.conf ./
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **Customize `index.html`**
|
|||
|
|
- Update title, service name, description
|
|||
|
|
- Modify status cards for your service's metrics
|
|||
|
|
- Update connection info sections (RPC/REST/gRPC)
|
|||
|
|
- Adjust modal content
|
|||
|
|
|
|||
|
|
4. **Copy Assets**
|
|||
|
|
```bash
|
|||
|
|
cp ../../neode-ui/public/assets/img/app-icons/{service-icon} ./
|
|||
|
|
cp ../../neode-ui/public/assets/img/bg-{theme}.jpg ./
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
5. **Update Nginx Config**
|
|||
|
|
- Set unique port number
|
|||
|
|
- Add RPC proxy if needed
|
|||
|
|
|
|||
|
|
6. **Update Dockerfile**
|
|||
|
|
- Update asset COPY commands
|
|||
|
|
- Verify port EXPOSE
|
|||
|
|
|
|||
|
|
7. **Build and Deploy**
|
|||
|
|
```bash
|
|||
|
|
# Deploy to dev server
|
|||
|
|
sshpass -p "archipelago" rsync -avz --delete ./ archipelago@192.168.1.228:/tmp/{service}-ui-build/
|
|||
|
|
|
|||
|
|
# Build on server
|
|||
|
|
sshpass -p "archipelago" ssh archipelago@192.168.1.228 \
|
|||
|
|
"cd /tmp/{service}-ui-build && \
|
|||
|
|
sudo podman build -t {service}-ui:latest . && \
|
|||
|
|
sudo podman stop {service}-ui 2>/dev/null || true && \
|
|||
|
|
sudo podman rm {service}-ui 2>/dev/null || true && \
|
|||
|
|
sudo podman run -d --name {service}-ui --restart unless-stopped \
|
|||
|
|
--network=host --label 'com.archipelago.parent-app={service-id}' \
|
|||
|
|
{service}-ui:latest"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
8. **Update Backend**
|
|||
|
|
- Edit `core/archipelago/src/container/docker_packages.rs`
|
|||
|
|
- Add port mapping for your service
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Testing Checklist
|
|||
|
|
|
|||
|
|
- [ ] UI loads correctly at `http://{server}:8XXX/`
|
|||
|
|
- [ ] Logo displays properly
|
|||
|
|
- [ ] Background image loads
|
|||
|
|
- [ ] All status cards show correct info
|
|||
|
|
- [ ] Buttons have proper hover effects
|
|||
|
|
- [ ] Modals open and close correctly
|
|||
|
|
- [ ] Mobile responsive (test on phone)
|
|||
|
|
- [ ] Glass effects render correctly
|
|||
|
|
- [ ] Gradient borders visible
|
|||
|
|
- [ ] Cache busting works (no stale content)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Future Enhancements
|
|||
|
|
|
|||
|
|
- **Live Data Updates** - WebSocket connections for real-time status
|
|||
|
|
- **Interactive Charts** - Add Chart.js for visualizing metrics
|
|||
|
|
- **Theme Variations** - Allow users to select background themes
|
|||
|
|
- **Dark/Light Mode** - Toggle between color schemes
|
|||
|
|
- **Internationalization** - Support multiple languages
|
|||
|
|
- **Accessibility** - Improve screen reader support
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## File Locations
|
|||
|
|
|
|||
|
|
- **UI Standards Doc:** `/Users/dorian/Projects/archy/.cursor/rules/APP-UI-STANDARDS.md`
|
|||
|
|
- **Global UI Standards:** `/Users/dorian/Projects/archy/.cursor/rules/UI-STANDARDS.md`
|
|||
|
|
- **Reference Implementations:**
|
|||
|
|
- Bitcoin UI: `/Users/dorian/Projects/archy/docker/bitcoin-ui/`
|
|||
|
|
- LND UI: `/Users/dorian/Projects/archy/docker/lnd-ui/`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**Version:** 1.0
|
|||
|
|
**Maintained by:** Archipelago Development Team
|
|||
|
|
**Last Updated:** 2026-02-03
|