archy/.cursor/rules/APP-UI-STANDARDS.md
Dorian 47a56e2212 Enhance UI styling and components for Archipelago
- Updated the glass-card and glass-button styles for improved aesthetics and functionality, including gradient borders and hover effects.
- Introduced new info-card and info-card-button components with enhanced styling and interactive features.
- Refactored existing HTML structure to utilize new card components, improving consistency across the UI.
- Enhanced button interactions for better user experience during settings and logs access.
2026-02-03 21:49:30 +00:00

589 lines
15 KiB
Markdown
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.

# 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