Integrate dummy service pages - private services now link to demo login pages
This commit is contained in:
parent
4fd5f593ea
commit
1554402d76
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
README.md
|
||||||
|
*.md
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Other
|
||||||
|
*.log
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Use nginx alpine as base image for a lightweight container
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# Remove default nginx website
|
||||||
|
RUN rm -rf /usr/share/nginx/html/*
|
||||||
|
|
||||||
|
# Copy main dashboard
|
||||||
|
COPY index.html /usr/share/nginx/html/
|
||||||
|
|
||||||
|
# Copy all service pages
|
||||||
|
COPY services/ /usr/share/nginx/html/services/
|
||||||
|
|
||||||
|
# Create a custom nginx config
|
||||||
|
RUN echo 'server { \
|
||||||
|
listen 80; \
|
||||||
|
server_name localhost; \
|
||||||
|
root /usr/share/nginx/html; \
|
||||||
|
index index.html; \
|
||||||
|
\
|
||||||
|
location / { \
|
||||||
|
try_files $uri $uri/ =404; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
# Enable gzip compression \
|
||||||
|
gzip on; \
|
||||||
|
gzip_vary on; \
|
||||||
|
gzip_min_length 1024; \
|
||||||
|
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; \
|
||||||
|
}' > /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# Expose port 80
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Start nginx
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|
@ -0,0 +1,181 @@
|
||||||
|
# 🏠 Homelab Showcase Dashboard
|
||||||
|
|
||||||
|
A beautiful, realistic dashboard for showcasing your internal homelab services with **dummy login pages** that mimic the real interfaces. Perfect for demonstrations without exposing actual services.
|
||||||
|
|
||||||
|
> **Note:** This is a showcase/demo site. All login forms are non-functional and display a "demo page" message when submitted.
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
|
||||||
|
- 🎨 **Realistic Service Interfaces** - Each service has its own authentic-looking dummy page
|
||||||
|
- 🏠 **Main Dashboard** - Beautiful dark-themed landing page with all services
|
||||||
|
- 🔒 **Safe & Secure** - No real authentication, just visual demonstrations
|
||||||
|
- 📱 **Responsive Design** - Works on desktop, tablet, and mobile
|
||||||
|
- 🐳 **Docker Ready** - Easy deployment via Docker Compose on Portainer
|
||||||
|
|
||||||
|
## 📦 Included Services
|
||||||
|
|
||||||
|
### Storage & Cloud
|
||||||
|
| Service | Description | Dummy Page |
|
||||||
|
|---------|-------------|------------|
|
||||||
|
| **Nextcloud** | Self-hosted cloud storage | `services/nextcloud.html` |
|
||||||
|
|
||||||
|
### Media & Entertainment
|
||||||
|
| Service | Description | Dummy Page |
|
||||||
|
|---------|-------------|------------|
|
||||||
|
| **Plex** | Media streaming server | `services/plex.html` |
|
||||||
|
| **Jellyfin** | Open source media server | `services/jellyfin.html` |
|
||||||
|
|
||||||
|
### Infrastructure & Management
|
||||||
|
| Service | Description | Dummy Page |
|
||||||
|
|---------|-------------|------------|
|
||||||
|
| **Portainer** | Docker container management | `services/portainer.html` |
|
||||||
|
| **Proxmox** | Virtualization platform | `services/proxmox.html` |
|
||||||
|
| **Pi-hole** | Network ad blocker dashboard | `services/pihole.html` |
|
||||||
|
|
||||||
|
### Monitoring
|
||||||
|
| Service | Description | Dummy Page |
|
||||||
|
|---------|-------------|------------|
|
||||||
|
| **Netdata** | Real-time system monitoring | `services/netdata.html` |
|
||||||
|
|
||||||
|
## 🚀 Deployment
|
||||||
|
|
||||||
|
### Option 1: Portainer (Recommended)
|
||||||
|
|
||||||
|
1. **Upload files** to your Portainer VM:
|
||||||
|
```bash
|
||||||
|
scp -r * user@your-vm:/path/to/homelab-showcase/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **In Portainer:**
|
||||||
|
- Go to **Stacks** → **Add Stack**
|
||||||
|
- Name: `homelab-showcase`
|
||||||
|
- Copy contents of `docker-compose.yml`
|
||||||
|
- Deploy
|
||||||
|
|
||||||
|
3. **Access:**
|
||||||
|
- Dashboard: `http://your-vm-ip:8080`
|
||||||
|
- Or configure Traefik for `showcase.lemonlink.eu`
|
||||||
|
|
||||||
|
### Option 2: Docker Compose
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 3: Manual Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t homelab-showcase .
|
||||||
|
docker run -d -p 8080:80 --name homelab-showcase --restart unless-stopped homelab-showcase
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🗂️ File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── index.html # Main dashboard
|
||||||
|
├── Dockerfile # Container definition
|
||||||
|
├── docker-compose.yml # Compose configuration
|
||||||
|
├── README.md # This file
|
||||||
|
└── services/ # Dummy service pages
|
||||||
|
├── nextcloud.html # Nextcloud login page
|
||||||
|
├── portainer.html # Portainer login page
|
||||||
|
├── netdata.html # Netdata dashboard
|
||||||
|
├── plex.html # Plex media interface
|
||||||
|
├── jellyfin.html # Jellyfin login page
|
||||||
|
├── proxmox.html # Proxmox login page
|
||||||
|
└── pihole.html # Pi-hole dashboard
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎨 Service Pages Preview
|
||||||
|
|
||||||
|
### Nextcloud Login
|
||||||
|
- Authentic blue gradient background
|
||||||
|
- Official Nextcloud logo
|
||||||
|
- Username/password form
|
||||||
|
- "Stay logged in" checkbox
|
||||||
|
|
||||||
|
### Portainer Login
|
||||||
|
- Docker-themed dark interface
|
||||||
|
- OAuth option button
|
||||||
|
- Version info display
|
||||||
|
|
||||||
|
### Netdata Dashboard
|
||||||
|
- Real-time-looking charts (static)
|
||||||
|
- CPU, RAM, Disk, Network metrics
|
||||||
|
- Time range selector
|
||||||
|
- Node overview panel
|
||||||
|
|
||||||
|
### Plex Interface
|
||||||
|
- Dark media server theme
|
||||||
|
- Movie/TV show grid
|
||||||
|
- "Continue Watching" section
|
||||||
|
- Sidebar navigation
|
||||||
|
|
||||||
|
### Jellyfin Login
|
||||||
|
- Jellyfin blue theme
|
||||||
|
- Server name display
|
||||||
|
- Clean centered login box
|
||||||
|
|
||||||
|
### Proxmox Login
|
||||||
|
- Split-screen design
|
||||||
|
- Feature highlights
|
||||||
|
- Realm selection
|
||||||
|
|
||||||
|
### Pi-hole Dashboard
|
||||||
|
- Red-themed statistics
|
||||||
|
- Query graphs
|
||||||
|
- Top blocked domains list
|
||||||
|
- Client activity panel
|
||||||
|
|
||||||
|
## 🔧 Customization
|
||||||
|
|
||||||
|
### Adding More Services
|
||||||
|
|
||||||
|
1. Create a new HTML file in `services/` folder
|
||||||
|
2. Copy the demo banner from existing files:
|
||||||
|
```html
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy page for showcase purposes only.
|
||||||
|
<a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
3. Design the login/interface to match the real service
|
||||||
|
4. Add the service card to `index.html`
|
||||||
|
|
||||||
|
### Changing Domain Names
|
||||||
|
|
||||||
|
Edit the URLs in `index.html` service cards to match your actual domains:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<span class="service-url">your-domain.com</span>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Styling
|
||||||
|
|
||||||
|
Each service page is self-contained with inline CSS. Edit the `<style>` section in each file to customize.
|
||||||
|
|
||||||
|
## 📝 Notes
|
||||||
|
|
||||||
|
- All form submissions are intercepted with JavaScript and show an alert
|
||||||
|
- No data is collected or transmitted
|
||||||
|
- Charts are static SVG/ CSS representations
|
||||||
|
- All "login" buttons are non-functional
|
||||||
|
|
||||||
|
## 🔒 Security
|
||||||
|
|
||||||
|
This showcase is designed to be **completely safe**:
|
||||||
|
- No backend processing
|
||||||
|
- No authentication validation
|
||||||
|
- No data storage
|
||||||
|
- Static HTML/CSS/JS only
|
||||||
|
|
||||||
|
## 🛠️ Requirements
|
||||||
|
|
||||||
|
- Docker & Docker Compose (or Portainer)
|
||||||
|
- ~64MB RAM for the container
|
||||||
|
- Port 8080 available (configurable)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Made with ❤️ for the homelab community
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
homelab-showcase:
|
||||||
|
build: .
|
||||||
|
container_name: homelab-showcase
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
# Optional: Add labels for Traefik reverse proxy
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.homelab-showcase.rule=Host(`showcase.lemonlink.eu`)"
|
||||||
|
- "traefik.http.routers.homelab-showcase.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.homelab-showcase.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.homelab-showcase.loadbalancer.server.port=80"
|
||||||
|
# Optional: Resource limits
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 64M
|
||||||
|
reservations:
|
||||||
|
memory: 32M
|
||||||
|
|
@ -0,0 +1,455 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>My Homelab Dashboard</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg-primary: #0f0f1a;
|
||||||
|
--bg-secondary: #16162a;
|
||||||
|
--bg-card: #1e1e3a;
|
||||||
|
--bg-card-hover: #252550;
|
||||||
|
--text-primary: #ffffff;
|
||||||
|
--text-secondary: #a0a0b8;
|
||||||
|
--accent: #6366f1;
|
||||||
|
--accent-hover: #818cf8;
|
||||||
|
--border: #2a2a4a;
|
||||||
|
--shadow: rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
min-height: 100vh;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
text-align: center;
|
||||||
|
padding: 3rem 0;
|
||||||
|
background: linear-gradient(135deg, var(--bg-secondary) 0%, var(--bg-primary) 100%);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
font-size: 3rem;
|
||||||
|
font-weight: 700;
|
||||||
|
background: linear-gradient(135deg, var(--text-primary) 0%, var(--accent) 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header p {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 2rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #22c55e;
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.5; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
margin: 3rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title svg {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 1.5rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, var(--accent), var(--accent-hover));
|
||||||
|
transform: scaleX(0);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
background: var(--bg-card-hover);
|
||||||
|
box-shadow: 0 20px 40px var(--shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card:hover::before {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-icon.homarr { background: rgba(99, 102, 241, 0.2); }
|
||||||
|
.service-icon.netdata { background: rgba(34, 197, 94, 0.2); }
|
||||||
|
.service-icon.nextcloud { background: rgba(59, 130, 246, 0.2); }
|
||||||
|
.service-icon.portainer { background: rgba(20, 184, 166, 0.2); }
|
||||||
|
.service-icon.pihole { background: rgba(249, 115, 22, 0.2); }
|
||||||
|
.service-icon.plex { background: rgba(168, 85, 247, 0.2); }
|
||||||
|
.service-icon.jellyfin { background: rgba(99, 179, 237, 0.2); }
|
||||||
|
.service-icon.proxmox { background: rgba(239, 68, 68, 0.2); }
|
||||||
|
.service-icon.traefik { background: rgba(6, 182, 212, 0.2); }
|
||||||
|
.service-icon.homeassistant { background: rgba(251, 191, 36, 0.2); }
|
||||||
|
.service-icon.nas { background: rgba(107, 114, 128, 0.2); }
|
||||||
|
.service-icon.vaultwarden { background: rgba(236, 72, 153, 0.2); }
|
||||||
|
|
||||||
|
.service-info h3 {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #22c55e;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-description {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-meta {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding-top: 1rem;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-url {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--accent);
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card:hover .arrow-icon {
|
||||||
|
color: var(--accent);
|
||||||
|
transform: translateX(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 3rem 0;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
header h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="container">
|
||||||
|
<h1>🏠 My Homelab</h1>
|
||||||
|
<p>Central dashboard for all internal services</p>
|
||||||
|
<div class="status-bar">
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-dot"></span>
|
||||||
|
<span>All Systems Operational</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span>🖥️ 12 Services</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span>⏱️ Uptime: 45 days</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<!-- Dashboards Section -->
|
||||||
|
<section class="section">
|
||||||
|
<h2 class="section-title">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<rect x="3" y="3" width="7" height="7" rx="1"/>
|
||||||
|
<rect x="14" y="3" width="7" height="7" rx="1"/>
|
||||||
|
<rect x="14" y="14" width="7" height="7" rx="1"/>
|
||||||
|
<rect x="3" y="14" width="7" height="7" rx="1"/>
|
||||||
|
</svg>
|
||||||
|
Dashboards & Monitoring
|
||||||
|
</h2>
|
||||||
|
<div class="services-grid">
|
||||||
|
<a href="services/netdata.html" class="service-card">
|
||||||
|
<div class="service-header">
|
||||||
|
<div class="service-icon netdata">📊</div>
|
||||||
|
<div class="service-info">
|
||||||
|
<h3>Netdata</h3>
|
||||||
|
<span class="service-status">● Running</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="service-description">Real-time performance monitoring and health monitoring for systems.</p>
|
||||||
|
<div class="service-meta">
|
||||||
|
<span class="service-url">netdata.local:19999</span>
|
||||||
|
<svg class="arrow-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Storage & Cloud Section -->
|
||||||
|
<section class="section">
|
||||||
|
<h2 class="section-title">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/>
|
||||||
|
</svg>
|
||||||
|
Storage & Cloud
|
||||||
|
</h2>
|
||||||
|
<div class="services-grid">
|
||||||
|
<a href="services/nextcloud.html" class="service-card">
|
||||||
|
<div class="service-header">
|
||||||
|
<div class="service-icon nextcloud">☁️</div>
|
||||||
|
<div class="service-info">
|
||||||
|
<h3>Nextcloud</h3>
|
||||||
|
<span class="service-status">● Running</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="service-description">Self-hosted file sync and share solution with office integration.</p>
|
||||||
|
<div class="service-meta">
|
||||||
|
<span class="service-url">cloud.lemonlink.eu</span>
|
||||||
|
<svg class="arrow-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Media Section -->
|
||||||
|
<section class="section">
|
||||||
|
<h2 class="section-title">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<polygon points="5 3 19 12 5 21 5 3"/>
|
||||||
|
</svg>
|
||||||
|
Media & Entertainment
|
||||||
|
</h2>
|
||||||
|
<div class="services-grid">
|
||||||
|
<a href="services/plex.html" class="service-card">
|
||||||
|
<div class="service-header">
|
||||||
|
<div class="service-icon plex">🎬</div>
|
||||||
|
<div class="service-info">
|
||||||
|
<h3>Plex</h3>
|
||||||
|
<span class="service-status">● Running</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="service-description">Personal media server for movies, TV shows, music, and photos.</p>
|
||||||
|
<div class="service-meta">
|
||||||
|
<span class="service-url">plex.lemonlink.eu</span>
|
||||||
|
<svg class="arrow-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="services/jellyfin.html" class="service-card">
|
||||||
|
<div class="service-header">
|
||||||
|
<div class="service-icon jellyfin">🎭</div>
|
||||||
|
<div class="service-info">
|
||||||
|
<h3>Jellyfin</h3>
|
||||||
|
<span class="service-status">● Running</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="service-description">Free Software Media System for managing and streaming media.</p>
|
||||||
|
<div class="service-meta">
|
||||||
|
<span class="service-url">jellyfin.lemonlink.eu</span>
|
||||||
|
<svg class="arrow-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Infrastructure Section -->
|
||||||
|
<section class="section">
|
||||||
|
<h2 class="section-title">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
|
||||||
|
</svg>
|
||||||
|
Infrastructure & Management
|
||||||
|
</h2>
|
||||||
|
<div class="services-grid">
|
||||||
|
<a href="services/portainer.html" class="service-card">
|
||||||
|
<div class="service-header">
|
||||||
|
<div class="service-icon portainer">🐳</div>
|
||||||
|
<div class="service-info">
|
||||||
|
<h3>Portainer</h3>
|
||||||
|
<span class="service-status">● Running</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="service-description">Container management UI for Docker and Kubernetes environments.</p>
|
||||||
|
<div class="service-meta">
|
||||||
|
<span class="service-url">portainer.lemonlink.eu</span>
|
||||||
|
<svg class="arrow-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="services/proxmox.html" class="service-card">
|
||||||
|
<div class="service-header">
|
||||||
|
<div class="service-icon proxmox">🖥️</div>
|
||||||
|
<div class="service-info">
|
||||||
|
<h3>Proxmox VE</h3>
|
||||||
|
<span class="service-status">● Running</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="service-description">Open-source server virtualization management platform.</p>
|
||||||
|
<div class="service-meta">
|
||||||
|
<span class="service-url">proxmox.lemonlink.eu:8006</span>
|
||||||
|
<svg class="arrow-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="services/pihole.html" class="service-card">
|
||||||
|
<div class="service-header">
|
||||||
|
<div class="service-icon pihole">🕳️</div>
|
||||||
|
<div class="service-info">
|
||||||
|
<h3>Pi-hole</h3>
|
||||||
|
<span class="service-status">● Running</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="service-description">Network-wide ad blocker that acts as a DNS sinkhole.</p>
|
||||||
|
<div class="service-meta">
|
||||||
|
<span class="service-url">pihole.lemonlink.eu/admin</span>
|
||||||
|
<svg class="arrow-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="container">
|
||||||
|
<p>🚀 Homelab Dashboard | Built with ❤️ | <a href="https://lemonlink.eu">lemonlink.eu</a></p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,202 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Jellyfin</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: #101010;
|
||||||
|
min-height: 100vh;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner {
|
||||||
|
background: #00a4dc;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: calc(100vh - 40px);
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-box {
|
||||||
|
background: #1a1a1a;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 48px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 440px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
background: linear-gradient(135deg, #00a4dc 0%, #0078a8 100%);
|
||||||
|
border-radius: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0 auto 16px;
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #00a4dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-name {
|
||||||
|
color: #888;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="password"] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 14px 16px;
|
||||||
|
background: #252525;
|
||||||
|
border: 1px solid #333;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: white;
|
||||||
|
font-size: 15px;
|
||||||
|
transition: border-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"]:focus,
|
||||||
|
input[type="password"]:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #00a4dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 14px;
|
||||||
|
background: #00a4dc;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #0088b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-login {
|
||||||
|
margin-top: 20px;
|
||||||
|
color: #00a4dc;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-login:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version {
|
||||||
|
margin-top: 30px;
|
||||||
|
color: #555;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy login page for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login-container">
|
||||||
|
<div class="login-box">
|
||||||
|
<div class="logo">
|
||||||
|
<div class="logo-icon">🎬</div>
|
||||||
|
<h1>Jellyfin</h1>
|
||||||
|
</div>
|
||||||
|
<p class="server-name">media.lemonlink.eu</p>
|
||||||
|
|
||||||
|
<form onsubmit="event.preventDefault(); alert('🔒 This is a demo page. The real Jellyfin is not exposed.');">
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<input type="text" id="username" placeholder="Enter username" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input type="password" id="password" placeholder="••••••••">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="options">
|
||||||
|
<label class="remember">
|
||||||
|
<input type="checkbox"> Remember me
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Sign In</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="manual-login" onclick="alert('Manual server setup not available in demo')">
|
||||||
|
Change Server
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="version">Jellyfin Server 10.8.13</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,440 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Log in – Nextcloud</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, sans-serif;
|
||||||
|
background: #0f172a;
|
||||||
|
min-height: 100vh;
|
||||||
|
color: #fff;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Demo Banner */
|
||||||
|
.demo-banner {
|
||||||
|
background: rgba(0,0,0,0.9);
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1000;
|
||||||
|
border-bottom: 1px solid #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: #60a5fa;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Abstract Background Shapes */
|
||||||
|
.bg-shapes {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
filter: blur(60px);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-1 {
|
||||||
|
width: 600px;
|
||||||
|
height: 600px;
|
||||||
|
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
|
||||||
|
left: -200px;
|
||||||
|
top: -100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-2 {
|
||||||
|
width: 500px;
|
||||||
|
height: 500px;
|
||||||
|
background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
|
||||||
|
right: -150px;
|
||||||
|
bottom: -100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-3 {
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
background: #60a5fa;
|
||||||
|
left: 60%;
|
||||||
|
top: 60%;
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-4 {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
background: #3b82f6;
|
||||||
|
left: 30%;
|
||||||
|
top: 20%;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Container */
|
||||||
|
.container {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logo */
|
||||||
|
.logo {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo svg {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Login Card */
|
||||||
|
.login-card {
|
||||||
|
background: rgba(30, 41, 59, 0.95);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 32px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 360px;
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input Groups with Floating Labels */
|
||||||
|
.input-group {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input {
|
||||||
|
width: 100%;
|
||||||
|
height: 52px;
|
||||||
|
padding: 16px 44px 8px 16px;
|
||||||
|
background: #0f172a;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #fff;
|
||||||
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #3b82f6;
|
||||||
|
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group label {
|
||||||
|
position: absolute;
|
||||||
|
left: 16px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
font-size: 15px;
|
||||||
|
color: #94a3b8;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
background: transparent;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input:focus + label,
|
||||||
|
.input-group input:not(:placeholder-shown) + label {
|
||||||
|
top: 0;
|
||||||
|
transform: translateY(-50%) scale(0.85);
|
||||||
|
color: #60a5fa;
|
||||||
|
background: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input:focus + label {
|
||||||
|
color: #60a5fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icons inside inputs */
|
||||||
|
.input-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 14px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: #64748b;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-icon:hover {
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember Me */
|
||||||
|
.remember-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember-checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember-checkbox input[type="checkbox"] {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
accent-color: #3b82f6;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Login Button */
|
||||||
|
.login-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 44px;
|
||||||
|
background: #3b82f6;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
transition: background 0.2s;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn:hover {
|
||||||
|
background: #2563eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alternative Login */
|
||||||
|
.alt-login {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alt-login-btn {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: #cbd5e1;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 8px 16px;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alt-login-btn:hover {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forgot Password */
|
||||||
|
.forgot-password {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password a {
|
||||||
|
color: #cbd5e1;
|
||||||
|
font-size: 14px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password a:hover {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background: rgba(30, 41, 59, 0.9);
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 24px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #94a3b8;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading State */
|
||||||
|
.login-btn.loading {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn.loading::after {
|
||||||
|
content: '';
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: 2px solid rgba(255,255,255,0.3);
|
||||||
|
border-top-color: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.login-card {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo svg {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy login page for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-shapes">
|
||||||
|
<div class="shape shape-1"></div>
|
||||||
|
<div class="shape shape-2"></div>
|
||||||
|
<div class="shape shape-3"></div>
|
||||||
|
<div class="shape shape-4"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="logo">
|
||||||
|
<svg viewBox="0 0 100 100" fill="none">
|
||||||
|
<circle cx="50" cy="50" r="45" fill="white"/>
|
||||||
|
<circle cx="35" cy="42" r="11" fill="#0f172a"/>
|
||||||
|
<circle cx="65" cy="42" r="11" fill="#0f172a"/>
|
||||||
|
<circle cx="50" cy="65" r="11" fill="#0f172a"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login-card">
|
||||||
|
<h1 class="login-title">Log in to Nextcloud</h1>
|
||||||
|
|
||||||
|
<form onsubmit="handleLogin(event)">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" id="user" placeholder=" " autocomplete="off" required>
|
||||||
|
<label for="user">Account name or email</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="password" id="password" placeholder=" " required>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<span class="input-icon" onclick="togglePassword()" title="Show password">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
|
||||||
|
<circle cx="12" cy="12" r="3"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="remember-row">
|
||||||
|
<label class="remember-checkbox">
|
||||||
|
<input type="checkbox" checked>
|
||||||
|
<span>Remember me</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="login-btn" id="loginBtn">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
||||||
|
</svg>
|
||||||
|
Log in
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="alt-login">
|
||||||
|
<button class="alt-login-btn" onclick="alert('Demo page - device login not available')">
|
||||||
|
Log in with a device
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="forgot-password">
|
||||||
|
<a href="#" onclick="alert('Demo page - password reset not available'); return false;">
|
||||||
|
Forgot password?
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<a href="https://nextcloud.com" target="_blank">Nextcloud</a> – a safe home for all your data
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function handleLogin(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const btn = document.getElementById('loginBtn');
|
||||||
|
const originalContent = btn.innerHTML;
|
||||||
|
|
||||||
|
btn.classList.add('loading');
|
||||||
|
btn.innerHTML = 'Logging in…';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
btn.classList.remove('loading');
|
||||||
|
btn.innerHTML = originalContent;
|
||||||
|
alert('🔒 This is a demo page. The real Nextcloud is not exposed.');
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function togglePassword() {
|
||||||
|
const pw = document.getElementById('password');
|
||||||
|
pw.type = pw.type === 'password' ? 'text' : 'password';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus username on load
|
||||||
|
document.getElementById('user').focus();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,698 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Pi-hole Dashboard</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-dark: #1a1a1a;
|
||||||
|
--bg-sidebar: #222;
|
||||||
|
--bg-card: #2a2a2a;
|
||||||
|
--border-color: #333;
|
||||||
|
--text-primary: #e0e0e0;
|
||||||
|
--text-secondary: #888;
|
||||||
|
--pihole-red: #96060c;
|
||||||
|
--pihole-green: #4caf50;
|
||||||
|
--pihole-blue: #3c8dbc;
|
||||||
|
--pihole-yellow: #f39c12;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: var(--bg-dark);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 14px;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Demo Banner */
|
||||||
|
.demo-banner {
|
||||||
|
background: #1a1a1a;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: var(--pihole-red);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Layout */
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
min-height: calc(100vh - 33px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar */
|
||||||
|
.sidebar {
|
||||||
|
width: 200px;
|
||||||
|
background: var(--bg-sidebar);
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
background: linear-gradient(180deg, #3c8dbc 0%, #357ca5 100%);
|
||||||
|
padding: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-box {
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pihole-logo {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background: var(--pihole-red);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pihole-logo::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -5px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 20px;
|
||||||
|
height: 15px;
|
||||||
|
background: var(--pihole-green);
|
||||||
|
border-radius: 10px 10px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-title {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot.active {
|
||||||
|
background: var(--pihole-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-menu {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: #2a2a2a;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: #2a2a2a;
|
||||||
|
color: white;
|
||||||
|
border-left: 3px solid var(--pihole-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-icon {
|
||||||
|
width: 18px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content */
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hostname {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stats Cards */
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.blue {
|
||||||
|
background: linear-gradient(135deg, #3c8dbc 0%, #2c6da0 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.red {
|
||||||
|
background: linear-gradient(135deg, #c0392b 0%, #962d22 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.yellow {
|
||||||
|
background: linear-gradient(135deg, #f39c12 0%, #c27a0e 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.green {
|
||||||
|
background: linear-gradient(135deg, #27ae60 0%, #1e8449 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-bg-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: -10px;
|
||||||
|
bottom: -10px;
|
||||||
|
font-size: 80px;
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(255,255,255,0.9);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: white;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-link {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 12px;
|
||||||
|
left: 20px;
|
||||||
|
right: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255,255,255,0.8);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-link:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Charts */
|
||||||
|
.chart-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-title {
|
||||||
|
font-size: 15px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-area {
|
||||||
|
height: 200px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bar Chart */
|
||||||
|
.bar-chart {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 160px;
|
||||||
|
padding: 0 4px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-chart::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(to bottom, transparent 19px, #333 20px),
|
||||||
|
linear-gradient(to right, transparent 19px, transparent 20px);
|
||||||
|
background-size: 100% 40px, 40px 100%;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-group {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: flex-end;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar {
|
||||||
|
width: 6px;
|
||||||
|
border-radius: 2px 2px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar.permitted {
|
||||||
|
background: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar.blocked {
|
||||||
|
background: var(--pihole-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar.client {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-axis {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 8px 4px 0;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-axis-y {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pie Charts Grid */
|
||||||
|
.pie-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pie-chart-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pie-chart {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pie-chart svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pie-legend {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-color {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-checkbox {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
accent-color: var(--pihole-blue);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy dashboard for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<h1>Pi-hole</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status-box">
|
||||||
|
<div class="pihole-logo">🕳️</div>
|
||||||
|
<div class="status-info">
|
||||||
|
<div class="status-title">Status</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-dot active"></span>
|
||||||
|
<span>Active</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-dot active"></span>
|
||||||
|
<span>Load: 0.12 0.15 0.18</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-dot active"></span>
|
||||||
|
<span>Memory usage: 12.4%</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span>🌡️ Temp: 42.0 °C</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-menu">
|
||||||
|
<div class="nav-item active">
|
||||||
|
<span class="nav-icon">🏠</span>
|
||||||
|
<span>Dashboard</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📋</span>
|
||||||
|
<span>Query Log</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📊</span>
|
||||||
|
<span>Long-term Data</span>
|
||||||
|
<span class="nav-arrow">›</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">👥</span>
|
||||||
|
<span>Groups</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🖥️</span>
|
||||||
|
<span>Clients</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🌐</span>
|
||||||
|
<span>Domains</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🛡️</span>
|
||||||
|
<span>Adlists</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">⏸️</span>
|
||||||
|
<span>Disable Blocking</span>
|
||||||
|
<span class="nav-arrow">›</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📝</span>
|
||||||
|
<span>Local DNS</span>
|
||||||
|
<span class="nav-arrow">›</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🔧</span>
|
||||||
|
<span>Tools</span>
|
||||||
|
<span class="nav-arrow">›</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">⚙️</span>
|
||||||
|
<span>Settings</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">❤️</span>
|
||||||
|
<span>Donate</span>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="content">
|
||||||
|
<div class="top-bar">
|
||||||
|
<button style="background: transparent; border: none; color: var(--text-secondary); font-size: 18px; cursor: pointer;">‹</button>
|
||||||
|
<span class="hostname">hostname: pihole</span>
|
||||||
|
<button style="background: transparent; border: none; color: var(--text-secondary); font-size: 18px; cursor: pointer;">☰</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Stats Cards -->
|
||||||
|
<div class="stats-grid">
|
||||||
|
<div class="stat-card blue">
|
||||||
|
<div class="stat-bg-icon">🌍</div>
|
||||||
|
<div class="stat-label">Total queries</div>
|
||||||
|
<div class="stat-value">73,770</div>
|
||||||
|
<div class="stat-link">
|
||||||
|
<span>23 active clients</span>
|
||||||
|
<span>›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card red">
|
||||||
|
<div class="stat-bg-icon">🛡️</div>
|
||||||
|
<div class="stat-label">Queries Blocked</div>
|
||||||
|
<div class="stat-value">17,304</div>
|
||||||
|
<div class="stat-link">
|
||||||
|
<span>List blocked queries</span>
|
||||||
|
<span>›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card yellow">
|
||||||
|
<div class="stat-bg-icon">📊</div>
|
||||||
|
<div class="stat-label">Percentage Blocked</div>
|
||||||
|
<div class="stat-value">23.5%</div>
|
||||||
|
<div class="stat-link">
|
||||||
|
<span>List all queries</span>
|
||||||
|
<span>›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card green">
|
||||||
|
<div class="stat-bg-icon">📋</div>
|
||||||
|
<div class="stat-label">Domains on Adlists</div>
|
||||||
|
<div class="stat-value">254,501</div>
|
||||||
|
<div class="stat-link">
|
||||||
|
<span>Manage adlists</span>
|
||||||
|
<span>›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Total Queries Chart -->
|
||||||
|
<div class="chart-card">
|
||||||
|
<div class="chart-title">Total queries over last 24 hours</div>
|
||||||
|
<div class="chart-area">
|
||||||
|
<div class="chart-axis-y">
|
||||||
|
<span>1,200</span>
|
||||||
|
<span>1,000</span>
|
||||||
|
<span>800</span>
|
||||||
|
<span>600</span>
|
||||||
|
<span>400</span>
|
||||||
|
<span>200</span>
|
||||||
|
<span>0</span>
|
||||||
|
</div>
|
||||||
|
<div class="bar-chart" style="margin-left: 40px;">
|
||||||
|
<script>
|
||||||
|
// Generate bars
|
||||||
|
const hours = ['13:00','14:00','15:00','16:00','17:00','18:00','19:00','20:00','21:00','22:00','23:00','00:00','01:00','02:00','03:00','04:00','05:00','06:00','07:00','08:00','09:00','10:00','11:00','12:00'];
|
||||||
|
hours.forEach((hour, i) => {
|
||||||
|
const h1 = 30 + Math.random() * 50;
|
||||||
|
const h2 = 50 + Math.random() * 70;
|
||||||
|
document.write(`
|
||||||
|
<div class="bar-group">
|
||||||
|
<div class="bar permitted" style="height: ${h1}%;"></div>
|
||||||
|
<div class="bar blocked" style="height: ${h2}%;"></div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chart-axis">
|
||||||
|
<script>
|
||||||
|
hours.forEach(hour => document.write(`<span>${hour}</span>`));
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Client Activity Chart -->
|
||||||
|
<div class="chart-card">
|
||||||
|
<div class="chart-title">Client activity over last 24 hours</div>
|
||||||
|
<div class="chart-area">
|
||||||
|
<div class="chart-axis-y">
|
||||||
|
<span>1,200</span>
|
||||||
|
<span>1,000</span>
|
||||||
|
<span>800</span>
|
||||||
|
<span>600</span>
|
||||||
|
<span>400</span>
|
||||||
|
<span>200</span>
|
||||||
|
<span>0</span>
|
||||||
|
</div>
|
||||||
|
<div class="bar-chart" style="margin-left: 40px;">
|
||||||
|
<script>
|
||||||
|
hours.forEach((hour, i) => {
|
||||||
|
const colors = ['#9c27b0', '#e91e63', '#00bcd4', '#ff9800', '#4caf50'];
|
||||||
|
document.write(`<div class="bar-group">`);
|
||||||
|
colors.forEach(color => {
|
||||||
|
const h = 20 + Math.random() * 60;
|
||||||
|
document.write(`<div class="bar client" style="height: ${h}%; background: ${color}; width: 2px;"></div>`);
|
||||||
|
});
|
||||||
|
document.write(`</div>`);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chart-axis">
|
||||||
|
<script>
|
||||||
|
hours.forEach(hour => document.write(`<span>${hour}</span>`));
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pie Charts -->
|
||||||
|
<div class="pie-grid">
|
||||||
|
<div class="chart-card">
|
||||||
|
<div class="chart-title">Query Types</div>
|
||||||
|
<div class="pie-chart-container">
|
||||||
|
<div class="pie-chart">
|
||||||
|
<svg viewBox="0 0 100 100">
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#ff7043" stroke-width="20" stroke-dasharray="100 251"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#42a5f5" stroke-width="20" stroke-dasharray="60 251" stroke-dashoffset="-100"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#66bb6a" stroke-width="20" stroke-dasharray="40 251" stroke-dashoffset="-160"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#ab47bc" stroke-width="20" stroke-dasharray="30 251" stroke-dashoffset="-200"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#26c6da" stroke-width="20" stroke-dasharray="21 251" stroke-dashoffset="-230"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="pie-legend">
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #ff7043;"></div>
|
||||||
|
<span>A (IPv4)</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #42a5f5;"></div>
|
||||||
|
<span>AAAA (IPv6)</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #66bb6a;"></div>
|
||||||
|
<span>SRV</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #ab47bc;"></div>
|
||||||
|
<span>SOA</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #26c6da;"></div>
|
||||||
|
<span>PTR</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-card">
|
||||||
|
<div class="chart-title">Upstream servers</div>
|
||||||
|
<div class="pie-chart-container">
|
||||||
|
<div class="pie-chart">
|
||||||
|
<svg viewBox="0 0 100 100">
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#ff7043" stroke-width="20" stroke-dasharray="120 251"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#42a5f5" stroke-width="20" stroke-dasharray="80 251" stroke-dashoffset="-120"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#66bb6a" stroke-width="20" stroke-dasharray="51 251" stroke-dashoffset="-200"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="pie-legend">
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #ff7043;"></div>
|
||||||
|
<span>blocked</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #42a5f5;"></div>
|
||||||
|
<span>cached</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #66bb6a;"></div>
|
||||||
|
<span>localhost#5335</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,431 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Plex</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: #1f1f1f;
|
||||||
|
min-height: 100vh;
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner {
|
||||||
|
background: #e5a00d;
|
||||||
|
color: #000;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: #1f1f1f;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 40px;
|
||||||
|
bottom: 0;
|
||||||
|
width: 240px;
|
||||||
|
background: #1f1f1f;
|
||||||
|
border-right: 1px solid #333;
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
padding: 0 20px 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background: #e5a00d;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-text {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #e5a00d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-section {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-title {
|
||||||
|
padding: 0 20px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #888;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
padding: 10px 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover, .nav-item.active {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
border-left: 3px solid #e5a00d;
|
||||||
|
padding-left: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-icon {
|
||||||
|
width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin-left: 240px;
|
||||||
|
padding: 60px 30px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
width: 300px;
|
||||||
|
color: #eee;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box::placeholder {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
background: #e5a00d;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f1f1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.see-all {
|
||||||
|
color: #e5a00d;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movies-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-card {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-card:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-poster {
|
||||||
|
aspect-ratio: 2/3;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: linear-gradient(135deg, #333 0%, #555 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 48px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-poster::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(180deg, transparent 50%, rgba(0,0,0,0.8) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-meta {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-banner {
|
||||||
|
background: linear-gradient(135deg, #2a2a2a 0%, #1a1a1a 100%);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 40px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
display: flex;
|
||||||
|
gap: 30px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-poster {
|
||||||
|
width: 200px;
|
||||||
|
height: 300px;
|
||||||
|
background: linear-gradient(135deg, #444 0%, #666 100%);
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 80px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-info h2 {
|
||||||
|
font-size: 32px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-meta {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-desc {
|
||||||
|
color: #ccc;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: #e5a00d;
|
||||||
|
color: #1f1f1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy media server for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="logo">
|
||||||
|
<div class="logo-icon">▶️</div>
|
||||||
|
<span class="logo-text">Plex</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-section">
|
||||||
|
<div class="nav-title">Discover</div>
|
||||||
|
<div class="nav-item active">
|
||||||
|
<span class="nav-icon">🏠</span>
|
||||||
|
<span>Home</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📺</span>
|
||||||
|
<span>Movies</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🎬</span>
|
||||||
|
<span>TV Shows</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🎵</span>
|
||||||
|
<span>Music</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-section">
|
||||||
|
<div class="nav-title">Library</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📁</span>
|
||||||
|
<span>All Media</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📊</span>
|
||||||
|
<span>Dashboard</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="main-content">
|
||||||
|
<div class="header">
|
||||||
|
<input type="text" class="search-box" placeholder="Search for movies, shows, music...">
|
||||||
|
<div class="user-menu">
|
||||||
|
<span>🔔</span>
|
||||||
|
<span>⚙️</span>
|
||||||
|
<div class="user-avatar">A</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hero-banner">
|
||||||
|
<div class="hero-poster">🎭</div>
|
||||||
|
<div class="hero-info">
|
||||||
|
<h2>Continue Watching</h2>
|
||||||
|
<div class="hero-meta">2023 • 2h 15m • Action, Sci-Fi</div>
|
||||||
|
<p class="hero-desc">
|
||||||
|
Pick up where you left off. Your personal media server is ready with all your favorite movies and TV shows.
|
||||||
|
</p>
|
||||||
|
<div class="hero-buttons">
|
||||||
|
<button class="btn btn-primary">▶ Play</button>
|
||||||
|
<button class="btn btn-secondary">+ My List</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3 class="section-title">Recently Added Movies</h3>
|
||||||
|
<span class="see-all">See all →</span>
|
||||||
|
</div>
|
||||||
|
<div class="movies-grid">
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🎬</div>
|
||||||
|
<div class="movie-title">The Matrix Resurrections</div>
|
||||||
|
<div class="movie-meta">2021 • 148 min</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🚀</div>
|
||||||
|
<div class="movie-title">Interstellar</div>
|
||||||
|
<div class="movie-meta">2014 • 169 min</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🦸</div>
|
||||||
|
<div class="movie-title">The Dark Knight</div>
|
||||||
|
<div class="movie-meta">2008 • 152 min</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🤖</div>
|
||||||
|
<div class="movie-title">Blade Runner 2049</div>
|
||||||
|
<div class="movie-meta">2017 • 164 min</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🌌</div>
|
||||||
|
<div class="movie-title">Dune</div>
|
||||||
|
<div class="movie-meta">2021 • 155 min</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">⚔️</div>
|
||||||
|
<div class="movie-title">Inception</div>
|
||||||
|
<div class="movie-meta">2010 • 148 min</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3 class="section-title">Continue Watching</h3>
|
||||||
|
<span class="see-all">See all →</span>
|
||||||
|
</div>
|
||||||
|
<div class="movies-grid">
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">📺</div>
|
||||||
|
<div class="movie-title">Breaking Bad S05E08</div>
|
||||||
|
<div class="movie-meta">45 min remaining</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🐉</div>
|
||||||
|
<div class="movie-title">House of Dragon S01E03</div>
|
||||||
|
<div class="movie-meta">32 min remaining</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">⚔️</div>
|
||||||
|
<div class="movie-title">The Witcher S02E05</div>
|
||||||
|
<div class="movie-meta">28 min remaining</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🕵️</div>
|
||||||
|
<div class="movie-title">Sherlock S04E01</div>
|
||||||
|
<div class="movie-meta">52 min remaining</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,796 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Home - Portainer</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-dark: #0f0f0f;
|
||||||
|
--bg-sidebar: #1a1a1a;
|
||||||
|
--bg-card: #1e1e1e;
|
||||||
|
--bg-hover: #252525;
|
||||||
|
--border-color: #2a2a2a;
|
||||||
|
--text-primary: #e0e0e0;
|
||||||
|
--text-secondary: #888;
|
||||||
|
--portainer-blue: #13bef9;
|
||||||
|
--portainer-teal: #00bfa5;
|
||||||
|
--success: #4caf50;
|
||||||
|
--danger: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: var(--bg-dark);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Demo Banner */
|
||||||
|
.demo-banner {
|
||||||
|
background: #141414;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: var(--portainer-blue);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Layout */
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
height: calc(100vh - 33px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Left Sidebar */
|
||||||
|
.sidebar {
|
||||||
|
width: 240px;
|
||||||
|
background: var(--bg-sidebar);
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: white;
|
||||||
|
letter-spacing: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon span {
|
||||||
|
color: var(--portainer-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-badge {
|
||||||
|
font-size: 9px;
|
||||||
|
color: var(--portainer-teal);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-nav {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-section {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-header {
|
||||||
|
padding: 8px 16px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 11px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--portainer-blue);
|
||||||
|
border-left: 3px solid var(--portainer-blue);
|
||||||
|
padding-left: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-icon {
|
||||||
|
width: 18px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-footer {
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content */
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background: var(--portainer-blue);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Environment Card */
|
||||||
|
.env-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
background: #1da1f2;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-name-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-name {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
background: rgba(76, 175, 80, 0.15);
|
||||||
|
color: var(--success);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-status::before {
|
||||||
|
content: '';
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background: var(--success);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-meta-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-meta-item span {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-path {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stats Row */
|
||||||
|
.env-stats {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot.running {
|
||||||
|
background: var(--success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot.stopped {
|
||||||
|
background: var(--danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Environment Actions */
|
||||||
|
.env-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: white;
|
||||||
|
color: #000;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-status::before {
|
||||||
|
content: '✕';
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Filters Bar */
|
||||||
|
.filters-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-dropdown {
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 12px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
min-width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 400px;
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 16px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box::placeholder {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-refresh {
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 16px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-refresh:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card Header */
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-subtitle {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scrollbar */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: var(--bg-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #333;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #444;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy dashboard for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<!-- Left Sidebar -->
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<div class="logo">
|
||||||
|
<div>
|
||||||
|
<div class="logo-icon">PORTAINER<span>.</span>IO</div>
|
||||||
|
<div class="logo-badge">Community Edition</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="sidebar-nav">
|
||||||
|
<div class="nav-section">
|
||||||
|
<div class="nav-item active">
|
||||||
|
<span class="nav-icon">🏠</span>
|
||||||
|
<span>Home</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-section">
|
||||||
|
<div class="nav-header">Environment: / None selected</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-section">
|
||||||
|
<div class="nav-header">Administration</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">👤</span>
|
||||||
|
<span>User-related</span>
|
||||||
|
<span class="nav-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🖥️</span>
|
||||||
|
<span>Environment-related</span>
|
||||||
|
<span class="nav-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📦</span>
|
||||||
|
<span>Registries</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📋</span>
|
||||||
|
<span>Logs</span>
|
||||||
|
<span class="nav-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🔔</span>
|
||||||
|
<span>Notifications</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">⚙️</span>
|
||||||
|
<span>Settings</span>
|
||||||
|
<span class="nav-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="sidebar-footer">
|
||||||
|
Community Edition 2.21.3 LTS
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="content">
|
||||||
|
<div class="page-header">
|
||||||
|
<h1 class="page-title">
|
||||||
|
Home
|
||||||
|
<span style="color: var(--portainer-blue); cursor: pointer;">↻</span>
|
||||||
|
</h1>
|
||||||
|
<div class="page-actions">
|
||||||
|
<button class="icon-btn">🔔</button>
|
||||||
|
<button class="icon-btn">❓</button>
|
||||||
|
<div class="user-menu">
|
||||||
|
<div class="user-avatar">A</div>
|
||||||
|
<span>admin</span>
|
||||||
|
<span>▼</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Environments Section -->
|
||||||
|
<div class="env-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">
|
||||||
|
<span style="font-size: 20px;">🖥️</span>
|
||||||
|
Environments
|
||||||
|
</div>
|
||||||
|
<div style="margin-left: auto; display: flex; gap: 8px;">
|
||||||
|
<button class="btn-refresh">↻ Refresh</button>
|
||||||
|
<button class="btn-refresh">⬇ Kubectl</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-subtitle" style="margin-bottom: 16px;">
|
||||||
|
Click on an environment to manage
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filters -->
|
||||||
|
<div class="filters-bar">
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Platform</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Connection Type</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Status</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Tags</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Groups</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Agent Version</option>
|
||||||
|
</select>
|
||||||
|
<button style="background: transparent; border: none; color: var(--text-secondary); cursor: pointer;">
|
||||||
|
Clear all
|
||||||
|
</button>
|
||||||
|
<div style="margin-left: auto; display: flex; gap: 8px;">
|
||||||
|
<select class="filter-dropdown" style="min-width: 100px;">
|
||||||
|
<option>Sort By</option>
|
||||||
|
</select>
|
||||||
|
<button class="btn-icon">↕</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Environment 1 -->
|
||||||
|
<div class="env-card" style="margin-bottom: 12px;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
|
||||||
|
<div class="env-header" style="flex: 1; margin-bottom: 0;">
|
||||||
|
<div class="env-icon">🐳</div>
|
||||||
|
<div class="env-info">
|
||||||
|
<div class="env-name-row">
|
||||||
|
<span class="env-name">local</span>
|
||||||
|
<span class="env-status">Up</span>
|
||||||
|
<span style="color: var(--text-secondary); font-size: 12px;">↻ 2026-02-02 12:42:53</span>
|
||||||
|
<span style="color: var(--text-secondary); font-size: 12px;">Standalone 2.21.3</span>
|
||||||
|
<span class="env-path">/var/run/docker.sock</span>
|
||||||
|
</div>
|
||||||
|
<div class="env-meta">
|
||||||
|
<span class="env-meta-item">Group: <span>Unassigned</span></span>
|
||||||
|
<span class="env-meta-item">🏷️ No tags</span>
|
||||||
|
<span class="env-meta-item">⚡ Local</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="env-actions">
|
||||||
|
<button class="btn btn-primary">📡 Live connect</button>
|
||||||
|
<button class="btn-icon">✏️</button>
|
||||||
|
<div style="text-align: right;">
|
||||||
|
<div class="connection-status">Disconnected</div>
|
||||||
|
<button class="btn-icon" style="margin-top: 4px;">⚙️</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="env-stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">📚</span>
|
||||||
|
<span class="stat-value">12</span>
|
||||||
|
<span class="stat-label">stacks</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">📦</span>
|
||||||
|
<span class="stat-value">24</span>
|
||||||
|
<span class="stat-label">containers</span>
|
||||||
|
</div>
|
||||||
|
<div class="container-status">
|
||||||
|
<span class="status-dot running"></span>
|
||||||
|
<span>18</span>
|
||||||
|
<span class="status-dot stopped"></span>
|
||||||
|
<span>2</span>
|
||||||
|
<span class="status-dot" style="background: #ff9800;"></span>
|
||||||
|
<span>0</span>
|
||||||
|
<span class="status-dot" style="background: #9c27b0;"></span>
|
||||||
|
<span>0</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">💾</span>
|
||||||
|
<span class="stat-value">32</span>
|
||||||
|
<span class="stat-label">volumes</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">🖼️</span>
|
||||||
|
<span class="stat-value">87</span>
|
||||||
|
<span class="stat-label">images</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">🖥️</span>
|
||||||
|
<span class="stat-value">4</span>
|
||||||
|
<span class="stat-label">CPU</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">💽</span>
|
||||||
|
<span class="stat-value">7.8</span>
|
||||||
|
<span class="stat-label">GB RAM</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Environment 2 -->
|
||||||
|
<div class="env-card">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
|
||||||
|
<div class="env-header" style="flex: 1; margin-bottom: 0;">
|
||||||
|
<div class="env-icon">🐳</div>
|
||||||
|
<div class="env-info">
|
||||||
|
<div class="env-name-row">
|
||||||
|
<span class="env-name">Compute-01</span>
|
||||||
|
<span class="env-status">Up</span>
|
||||||
|
<span style="color: var(--text-secondary); font-size: 12px;">↻ 2026-02-02 12:42:53</span>
|
||||||
|
<span style="color: var(--text-secondary); font-size: 12px;">Standalone 2.21.3</span>
|
||||||
|
<span class="env-path">agent.local:9001</span>
|
||||||
|
</div>
|
||||||
|
<div class="env-meta">
|
||||||
|
<span class="env-meta-item">Group: <span>Unassigned</span></span>
|
||||||
|
<span class="env-meta-item">🏷️ No tags</span>
|
||||||
|
<span class="env-meta-item">⚡ Agent 2.21.3</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="env-actions">
|
||||||
|
<button class="btn btn-primary">📡 Live connect</button>
|
||||||
|
<button class="btn-icon">✏️</button>
|
||||||
|
<div style="text-align: right;">
|
||||||
|
<div class="connection-status">Disconnected</div>
|
||||||
|
<button class="btn-icon" style="margin-top: 4px;">⚙️</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="env-stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">📚</span>
|
||||||
|
<span class="stat-value">5</span>
|
||||||
|
<span class="stat-label">stacks</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">📦</span>
|
||||||
|
<span class="stat-value">16</span>
|
||||||
|
<span class="stat-label">containers</span>
|
||||||
|
</div>
|
||||||
|
<div class="container-status">
|
||||||
|
<span class="status-dot running"></span>
|
||||||
|
<span>14</span>
|
||||||
|
<span class="status-dot stopped"></span>
|
||||||
|
<span>1</span>
|
||||||
|
<span class="status-dot" style="background: #ff9800;"></span>
|
||||||
|
<span>0</span>
|
||||||
|
<span class="status-dot" style="background: #9c27b0;"></span>
|
||||||
|
<span>0</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">💾</span>
|
||||||
|
<span class="stat-value">10</span>
|
||||||
|
<span class="stat-label">volumes</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">🖼️</span>
|
||||||
|
<span class="stat-value">24</span>
|
||||||
|
<span class="stat-label">images</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">🖥️</span>
|
||||||
|
<span class="stat-value">6</span>
|
||||||
|
<span class="stat-label">CPU</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">💽</span>
|
||||||
|
<span class="stat-value">8.2</span>
|
||||||
|
<span class="stat-label">GB RAM</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,624 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Proxmox Virtual Environment</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-dark: #1e1e1e;
|
||||||
|
--bg-panel: #2d2d2d;
|
||||||
|
--bg-sidebar: #252525;
|
||||||
|
--bg-input: #3a3a3a;
|
||||||
|
--border-color: #404040;
|
||||||
|
--text-primary: #e0e0e0;
|
||||||
|
--text-secondary: #999;
|
||||||
|
--proxmox-orange: #e57000;
|
||||||
|
--proxmox-orange-light: #ff8c00;
|
||||||
|
--btn-blue: #3d85c6;
|
||||||
|
--btn-blue-hover: #2d6da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: var(--bg-dark);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Demo Banner */
|
||||||
|
.demo-banner {
|
||||||
|
background: #1a1a1a;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
text-align: center;
|
||||||
|
padding: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
z-index: 1000;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: var(--proxmox-orange);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Top Bar */
|
||||||
|
.top-bar {
|
||||||
|
background: linear-gradient(180deg, #3a3a3a 0%, #2d2d2d 100%);
|
||||||
|
border-bottom: 1px solid #1a1a1a;
|
||||||
|
height: 42px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 8px;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-area {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxmox-logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
background: var(--proxmox-orange);
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
color: white;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-text {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-text span {
|
||||||
|
color: var(--proxmox-orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 400px;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input {
|
||||||
|
width: 100%;
|
||||||
|
height: 28px;
|
||||||
|
background: #1e1e1e;
|
||||||
|
border: 1px solid #404040;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 10px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input::placeholder {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-btn {
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 12px;
|
||||||
|
background: linear-gradient(180deg, #4a4a4a 0%, #3a3a3a 100%);
|
||||||
|
border: 1px solid #505050;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-btn:hover {
|
||||||
|
background: linear-gradient(180deg, #5a5a5a 0%, #4a4a4a 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-btn.primary {
|
||||||
|
background: var(--btn-blue);
|
||||||
|
border-color: #2d6da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-btn.primary:hover {
|
||||||
|
background: var(--btn-blue-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Container */
|
||||||
|
.main-container {
|
||||||
|
display: flex;
|
||||||
|
height: calc(100vh - 90px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Left Sidebar */
|
||||||
|
.sidebar {
|
||||||
|
width: 220px;
|
||||||
|
background: var(--bg-sidebar);
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-selector {
|
||||||
|
flex: 1;
|
||||||
|
height: 26px;
|
||||||
|
background: #3a3a3a;
|
||||||
|
border: 1px solid #505050;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-btn {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
background: #3a3a3a;
|
||||||
|
border: 1px solid #505050;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-item:hover {
|
||||||
|
background: #333;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-icon {
|
||||||
|
width: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Center Content - Login Area */
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: var(--bg-dark);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Login Window */
|
||||||
|
.login-window {
|
||||||
|
background: #363636;
|
||||||
|
border: 1px solid #505050;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
|
||||||
|
width: 380px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header {
|
||||||
|
background: linear-gradient(180deg, #404040 0%, #363636 100%);
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-bottom: 1px solid #505050;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--btn-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-body {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
width: 80px;
|
||||||
|
text-align: right;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
background: var(--bg-input);
|
||||||
|
border: 1px solid #505050;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 30px 0 10px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--btn-blue);
|
||||||
|
box-shadow: 0 0 0 1px var(--btn-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: var(--proxmox-orange);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.form-input {
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23999' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 8px center;
|
||||||
|
padding-right: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid #505050;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-label input {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
accent-color: var(--btn-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 20px;
|
||||||
|
background: var(--btn-blue);
|
||||||
|
border: 1px solid #2d6da3;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: white;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn:hover {
|
||||||
|
background: var(--btn-blue-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bottom Panel */
|
||||||
|
.bottom-panel {
|
||||||
|
height: 180px;
|
||||||
|
background: var(--bg-panel);
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-tabs {
|
||||||
|
display: flex;
|
||||||
|
background: #363636;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-tab {
|
||||||
|
padding: 8px 16px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-tab:hover {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-tab.active {
|
||||||
|
background: var(--bg-panel);
|
||||||
|
color: var(--btn-blue);
|
||||||
|
border-bottom: 2px solid var(--btn-blue);
|
||||||
|
margin-bottom: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table th {
|
||||||
|
text-align: left;
|
||||||
|
padding: 8px 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: normal;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
background: #2d2d2d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table th.sortable::after {
|
||||||
|
content: ' ↕';
|
||||||
|
font-size: 10px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table td {
|
||||||
|
padding: 8px 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table tr:hover td {
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scrollbar */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: var(--bg-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #505050;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #606060;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy login page for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Top Bar -->
|
||||||
|
<div class="top-bar">
|
||||||
|
<div class="logo-area">
|
||||||
|
<div class="proxmox-logo">
|
||||||
|
<div class="logo-icon">P</div>
|
||||||
|
<div class="logo-text"><span>PROX</span>MOX</div>
|
||||||
|
</div>
|
||||||
|
<div style="color: var(--text-secondary); font-size: 12px;">Virtual Environment</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-box">
|
||||||
|
<input type="text" placeholder="Search">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="top-actions">
|
||||||
|
<button class="top-btn">
|
||||||
|
<span>📄</span> Documentation
|
||||||
|
</button>
|
||||||
|
<button class="top-btn primary">
|
||||||
|
<span>🖥️</span> Create VM
|
||||||
|
</button>
|
||||||
|
<button class="top-btn primary">
|
||||||
|
<span>📦</span> Create CT
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-menu">
|
||||||
|
<button class="top-btn" style="width: 32px; padding: 0; justify-content: center;">
|
||||||
|
👤
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Container -->
|
||||||
|
<div class="main-container">
|
||||||
|
<!-- Left Sidebar -->
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<select class="view-selector">
|
||||||
|
<option>Server View</option>
|
||||||
|
</select>
|
||||||
|
<button class="settings-btn">⚙️</button>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-content">
|
||||||
|
<div class="tree-item">
|
||||||
|
<span class="tree-icon">▼</span>
|
||||||
|
<span class="tree-icon">🏢</span>
|
||||||
|
<span>Datacenter</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- Center Content -->
|
||||||
|
<main class="content">
|
||||||
|
<!-- Login Window -->
|
||||||
|
<div class="login-window">
|
||||||
|
<div class="login-header">Proxmox VE Login</div>
|
||||||
|
<div class="login-body">
|
||||||
|
<form onsubmit="handleLogin(event)">
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label">User name:</label>
|
||||||
|
<div class="form-input-wrapper">
|
||||||
|
<input type="text" class="form-input" id="username" autocomplete="off">
|
||||||
|
<span class="input-icon">🔴</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label">Password:</label>
|
||||||
|
<div class="form-input-wrapper">
|
||||||
|
<input type="password" class="form-input" id="password">
|
||||||
|
<span class="input-icon">🔴</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label">Realm:</label>
|
||||||
|
<div class="form-input-wrapper">
|
||||||
|
<select class="form-input">
|
||||||
|
<option>Linux PAM standard authentication</option>
|
||||||
|
<option>Proxmox VE authentication server</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label">Language:</label>
|
||||||
|
<div class="form-input-wrapper">
|
||||||
|
<select class="form-input">
|
||||||
|
<option>English - English</option>
|
||||||
|
<option>Deutsch - German</option>
|
||||||
|
<option>Français - French</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login-footer">
|
||||||
|
<label class="checkbox-label">
|
||||||
|
<input type="checkbox" checked>
|
||||||
|
Save User name:
|
||||||
|
</label>
|
||||||
|
<button type="submit" class="login-btn">Login</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bottom Panel -->
|
||||||
|
<div class="bottom-panel">
|
||||||
|
<div class="panel-tabs">
|
||||||
|
<div class="panel-tab active">Tasks</div>
|
||||||
|
<div class="panel-tab">Cluster log</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-content">
|
||||||
|
<table class="data-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sortable">Start Time</th>
|
||||||
|
<th class="sortable">End Time</th>
|
||||||
|
<th>Node</th>
|
||||||
|
<th>User name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>02/02/2026 12:21:42</td>
|
||||||
|
<td>-</td>
|
||||||
|
<td>pve</td>
|
||||||
|
<td>root@pam</td>
|
||||||
|
<td>Login</td>
|
||||||
|
<td>✓ OK</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>02/02/2026 12:20:15</td>
|
||||||
|
<td>02/02/2026 12:20:16</td>
|
||||||
|
<td>pve</td>
|
||||||
|
<td>root@pam</td>
|
||||||
|
<td>VM 100 - Start</td>
|
||||||
|
<td>✓ OK</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>02/02/2026 12:18:33</td>
|
||||||
|
<td>02/02/2026 12:18:34</td>
|
||||||
|
<td>pve</td>
|
||||||
|
<td>root@pam</td>
|
||||||
|
<td>VM 101 - Stop</td>
|
||||||
|
<td>✓ OK</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function handleLogin(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
alert('🔒 This is a demo page. The real Proxmox VE is not exposed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus username on load
|
||||||
|
document.getElementById('username').focus();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
152
index.html
152
index.html
|
|
@ -322,46 +322,46 @@
|
||||||
Private Services
|
Private Services
|
||||||
</h3>
|
</h3>
|
||||||
<div class="services-grid">
|
<div class="services-grid">
|
||||||
<div class="service-card private-service" data-service="nextcloud">
|
<a href="./services/nextcloud.html" class="service-card private-service" target="_blank">
|
||||||
<div class="service-glow"></div>
|
<div class="service-glow"></div>
|
||||||
<div class="service-icon" style="--icon-color: #0082c9; font-size: 28px;">☁️</div>
|
<div class="service-icon" style="--icon-color: #0082c9; font-size: 28px;">☁️</div>
|
||||||
<h3 class="service-name">Nextcloud</h3>
|
<h3 class="service-name">Nextcloud</h3>
|
||||||
<p class="service-desc">Private cloud storage, files, and collaboration</p>
|
<p class="service-desc">Private cloud storage, files, and collaboration</p>
|
||||||
<div class="service-status checking" data-status-url="https://cloud.lemonlink.eu/status.php">
|
<div class="service-status online">
|
||||||
<span class="status-dot"></span>
|
<span class="status-dot"></span>
|
||||||
<span class="status-text">Checking...</span>
|
<span>Restricted</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="service-arrow">
|
<div class="service-arrow">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
|
|
||||||
<div class="service-card private-service" data-service="netdata">
|
<a href="./services/netdata.html" class="service-card private-service" target="_blank">
|
||||||
<div class="service-glow"></div>
|
<div class="service-glow"></div>
|
||||||
<div class="service-icon" style="--icon-color: #00ab44; font-size: 28px;">📈</div>
|
<div class="service-icon" style="--icon-color: #00ab44; font-size: 28px;">📈</div>
|
||||||
<h3 class="service-name">Netdata</h3>
|
<h3 class="service-name">Netdata</h3>
|
||||||
<p class="service-desc">Real-time system monitoring and metrics</p>
|
<p class="service-desc">Real-time system monitoring and metrics</p>
|
||||||
<div class="service-status checking" data-status-url="https://stats.lemonlink.eu/api/v1/info">
|
<div class="service-status online">
|
||||||
<span class="status-dot"></span>
|
<span class="status-dot"></span>
|
||||||
<span class="status-text">Checking...</span>
|
<span>Restricted</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="service-arrow">
|
<div class="service-arrow">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
|
|
||||||
<div class="service-card private-service" data-service="immich">
|
<div class="service-card private-service" data-service="immich">
|
||||||
<div class="service-glow"></div>
|
<div class="service-glow"></div>
|
||||||
<div class="service-icon" style="--icon-color: #ad5c5c; font-size: 28px;">🖼️</div>
|
<div class="service-icon" style="--icon-color: #ad5c5c; font-size: 28px;">🖼️</div>
|
||||||
<h3 class="service-name">Immich</h3>
|
<h3 class="service-name">Immich</h3>
|
||||||
<p class="service-desc">Self-hosted photo and video backup solution</p>
|
<p class="service-desc">Self-hosted photo and video backup solution</p>
|
||||||
<div class="service-status checking" data-status-url="https://photos.lemonlink.eu/api/server-info/ping">
|
<div class="service-status online">
|
||||||
<span class="status-dot"></span>
|
<span class="status-dot"></span>
|
||||||
<span class="status-text">Checking...</span>
|
<span>Restricted</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="service-arrow">
|
<div class="service-arrow">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
|
@ -370,37 +370,37 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="service-card private-service" data-service="homarr">
|
<a href="./services/portainer.html" class="service-card private-service" target="_blank">
|
||||||
<div class="service-glow"></div>
|
<div class="service-glow"></div>
|
||||||
<div class="service-icon" style="--icon-color: #ff5c5c; font-size: 28px;">🎛️</div>
|
<div class="service-icon" style="--icon-color: #13b6a6; font-size: 28px;">🐳</div>
|
||||||
<h3 class="service-name">Homarr</h3>
|
<h3 class="service-name">Portainer</h3>
|
||||||
<p class="service-desc">Customizable dashboard for all your services</p>
|
<p class="service-desc">Docker container management interface</p>
|
||||||
<div class="service-status checking" data-status-url="https://dash.lemonlink.eu">
|
<div class="service-status online">
|
||||||
<span class="status-dot"></span>
|
<span class="status-dot"></span>
|
||||||
<span class="status-text">Checking...</span>
|
<span>Restricted</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="service-arrow">
|
<div class="service-arrow">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
|
|
||||||
<div class="service-card private-service" data-service="tailscale">
|
<a href="./services/pihole.html" class="service-card private-service" target="_blank">
|
||||||
<div class="service-glow"></div>
|
<div class="service-glow"></div>
|
||||||
<div class="service-icon" style="--icon-color: #7b68ee; font-size: 28px;">🔒</div>
|
<div class="service-icon" style="--icon-color: #f97316; font-size: 28px;">🛡️</div>
|
||||||
<h3 class="service-name">Tailscale</h3>
|
<h3 class="service-name">Pi-hole</h3>
|
||||||
<p class="service-desc">Zero-config VPN for secure remote access</p>
|
<p class="service-desc">Network-wide ad blocking and DNS filtering</p>
|
||||||
<div class="service-status checking" data-status-url="https://login.tailscale.com">
|
<div class="service-status online">
|
||||||
<span class="status-dot"></span>
|
<span class="status-dot"></span>
|
||||||
<span class="status-text">Checking...</span>
|
<span>Restricted</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="service-arrow">
|
<div class="service-arrow">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<path d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -687,102 +687,6 @@
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<!-- Service Info Modals - Hidden by default -->
|
|
||||||
<div id="modal-nextcloud" class="service-modal" style="display: none !important;">
|
|
||||||
<div class="modal-content">
|
|
||||||
<button class="modal-close">×</button>
|
|
||||||
<h3>☁️ Nextcloud</h3>
|
|
||||||
<p>Private cloud storage platform - your data stays under your control.</p>
|
|
||||||
<div class="modal-details">
|
|
||||||
<h4>Features:</h4>
|
|
||||||
<ul>
|
|
||||||
<li>File storage and sync</li>
|
|
||||||
<li>Calendar and contacts</li>
|
|
||||||
<li>Document collaboration</li>
|
|
||||||
<li>End-to-end encryption</li>
|
|
||||||
</ul>
|
|
||||||
<h4>Access:</h4>
|
|
||||||
<p>This is a <strong>private service</strong>. User account required.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="modal-netdata" class="service-modal" style="display: none !important;">
|
|
||||||
<div class="modal-content">
|
|
||||||
<button class="modal-close">×</button>
|
|
||||||
<h3>📊 Netdata Monitoring</h3>
|
|
||||||
<p>Real-time infrastructure monitoring with beautiful dashboards.</p>
|
|
||||||
<div class="modal-details">
|
|
||||||
<h4>Features:</h4>
|
|
||||||
<ul>
|
|
||||||
<li>Real-time metrics</li>
|
|
||||||
<li>System performance monitoring</li>
|
|
||||||
<li>Custom alerts</li>
|
|
||||||
<li>Historical data</li>
|
|
||||||
</ul>
|
|
||||||
<h4>Access:</h4>
|
|
||||||
<p>This is a <strong>private service</strong>. VPN or local network access required.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="modal-immich" class="service-modal" style="display: none !important;">
|
|
||||||
<div class="modal-content">
|
|
||||||
<button class="modal-close">×</button>
|
|
||||||
<h3>📸 Immich Photo Server</h3>
|
|
||||||
<p>Self-hosted photo and video backup solution - a Google Photos alternative.</p>
|
|
||||||
<div class="modal-details">
|
|
||||||
<h4>Features:</h4>
|
|
||||||
<ul>
|
|
||||||
<li>Automatic mobile photo backup</li>
|
|
||||||
<li>AI-powered face recognition</li>
|
|
||||||
<li>Albums and sharing</li>
|
|
||||||
<li>RAW file support</li>
|
|
||||||
</ul>
|
|
||||||
<h4>Access:</h4>
|
|
||||||
<p>This is a <strong>private service</strong>. Contact me for access.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="modal-homarr" class="service-modal" style="display: none !important;">
|
|
||||||
<div class="modal-content">
|
|
||||||
<button class="modal-close">×</button>
|
|
||||||
<h3>🎛️ Homarr Dashboard</h3>
|
|
||||||
<p>Personal dashboard aggregating all services in one place.</p>
|
|
||||||
<div class="modal-details">
|
|
||||||
<h4>Features:</h4>
|
|
||||||
<ul>
|
|
||||||
<li>Service status monitoring</li>
|
|
||||||
<li>Quick bookmarks</li>
|
|
||||||
<li>Weather widget</li>
|
|
||||||
<li>Custom integrations</li>
|
|
||||||
</ul>
|
|
||||||
<h4>Access:</h4>
|
|
||||||
<p>This is a <strong>private service</strong>. VPN access required.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="modal-tailscale" class="service-modal" style="display: none !important;">
|
|
||||||
<div class="modal-content">
|
|
||||||
<button class="modal-close">×</button>
|
|
||||||
<h3>🔒 Tailscale VPN</h3>
|
|
||||||
<p>Zero-configuration mesh VPN for secure remote access to the homelab.</p>
|
|
||||||
<div class="modal-details">
|
|
||||||
<h4>Features:</h4>
|
|
||||||
<ul>
|
|
||||||
<li>Point-to-point encrypted connections</li>
|
|
||||||
<li>No open ports required</li>
|
|
||||||
<li>Multi-device support</li>
|
|
||||||
<li>Exit nodes for secure browsing</li>
|
|
||||||
</ul>
|
|
||||||
<h4>Access:</h4>
|
|
||||||
<p>Tailscale network invitation required. Contact me to join the tailnet.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="script.js"></script>
|
<script src="script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,202 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Jellyfin</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: #101010;
|
||||||
|
min-height: 100vh;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner {
|
||||||
|
background: #00a4dc;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: calc(100vh - 40px);
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-box {
|
||||||
|
background: #1a1a1a;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 48px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 440px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
background: linear-gradient(135deg, #00a4dc 0%, #0078a8 100%);
|
||||||
|
border-radius: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0 auto 16px;
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #00a4dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-name {
|
||||||
|
color: #888;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="password"] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 14px 16px;
|
||||||
|
background: #252525;
|
||||||
|
border: 1px solid #333;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: white;
|
||||||
|
font-size: 15px;
|
||||||
|
transition: border-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"]:focus,
|
||||||
|
input[type="password"]:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #00a4dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 14px;
|
||||||
|
background: #00a4dc;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #0088b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-login {
|
||||||
|
margin-top: 20px;
|
||||||
|
color: #00a4dc;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-login:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version {
|
||||||
|
margin-top: 30px;
|
||||||
|
color: #555;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy login page for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login-container">
|
||||||
|
<div class="login-box">
|
||||||
|
<div class="logo">
|
||||||
|
<div class="logo-icon">🎬</div>
|
||||||
|
<h1>Jellyfin</h1>
|
||||||
|
</div>
|
||||||
|
<p class="server-name">media.lemonlink.eu</p>
|
||||||
|
|
||||||
|
<form onsubmit="event.preventDefault(); alert('🔒 This is a demo page. The real Jellyfin is not exposed.');">
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<input type="text" id="username" placeholder="Enter username" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input type="password" id="password" placeholder="••••••••">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="options">
|
||||||
|
<label class="remember">
|
||||||
|
<input type="checkbox"> Remember me
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit">Sign In</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="manual-login" onclick="alert('Manual server setup not available in demo')">
|
||||||
|
Change Server
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="version">Jellyfin Server 10.8.13</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,440 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Log in – Nextcloud</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, sans-serif;
|
||||||
|
background: #0f172a;
|
||||||
|
min-height: 100vh;
|
||||||
|
color: #fff;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Demo Banner */
|
||||||
|
.demo-banner {
|
||||||
|
background: rgba(0,0,0,0.9);
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1000;
|
||||||
|
border-bottom: 1px solid #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: #60a5fa;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Abstract Background Shapes */
|
||||||
|
.bg-shapes {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
filter: blur(60px);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-1 {
|
||||||
|
width: 600px;
|
||||||
|
height: 600px;
|
||||||
|
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
|
||||||
|
left: -200px;
|
||||||
|
top: -100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-2 {
|
||||||
|
width: 500px;
|
||||||
|
height: 500px;
|
||||||
|
background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
|
||||||
|
right: -150px;
|
||||||
|
bottom: -100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-3 {
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
background: #60a5fa;
|
||||||
|
left: 60%;
|
||||||
|
top: 60%;
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-4 {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
background: #3b82f6;
|
||||||
|
left: 30%;
|
||||||
|
top: 20%;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Container */
|
||||||
|
.container {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logo */
|
||||||
|
.logo {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo svg {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Login Card */
|
||||||
|
.login-card {
|
||||||
|
background: rgba(30, 41, 59, 0.95);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 32px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 360px;
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input Groups with Floating Labels */
|
||||||
|
.input-group {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input {
|
||||||
|
width: 100%;
|
||||||
|
height: 52px;
|
||||||
|
padding: 16px 44px 8px 16px;
|
||||||
|
background: #0f172a;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #fff;
|
||||||
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #3b82f6;
|
||||||
|
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group label {
|
||||||
|
position: absolute;
|
||||||
|
left: 16px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
font-size: 15px;
|
||||||
|
color: #94a3b8;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
background: transparent;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input:focus + label,
|
||||||
|
.input-group input:not(:placeholder-shown) + label {
|
||||||
|
top: 0;
|
||||||
|
transform: translateY(-50%) scale(0.85);
|
||||||
|
color: #60a5fa;
|
||||||
|
background: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input:focus + label {
|
||||||
|
color: #60a5fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icons inside inputs */
|
||||||
|
.input-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 14px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: #64748b;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-icon:hover {
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember Me */
|
||||||
|
.remember-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember-checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remember-checkbox input[type="checkbox"] {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
accent-color: #3b82f6;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Login Button */
|
||||||
|
.login-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 44px;
|
||||||
|
background: #3b82f6;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
transition: background 0.2s;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn:hover {
|
||||||
|
background: #2563eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alternative Login */
|
||||||
|
.alt-login {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alt-login-btn {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: #cbd5e1;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 8px 16px;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alt-login-btn:hover {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forgot Password */
|
||||||
|
.forgot-password {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password a {
|
||||||
|
color: #cbd5e1;
|
||||||
|
font-size: 14px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password a:hover {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background: rgba(30, 41, 59, 0.9);
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 24px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #94a3b8;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading State */
|
||||||
|
.login-btn.loading {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn.loading::after {
|
||||||
|
content: '';
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: 2px solid rgba(255,255,255,0.3);
|
||||||
|
border-top-color: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.login-card {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo svg {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a demo login page. The real service is private. <a href="https://lemonlink.eu">← Back to LemonLink</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-shapes">
|
||||||
|
<div class="shape shape-1"></div>
|
||||||
|
<div class="shape shape-2"></div>
|
||||||
|
<div class="shape shape-3"></div>
|
||||||
|
<div class="shape shape-4"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="logo">
|
||||||
|
<svg viewBox="0 0 100 100" fill="none">
|
||||||
|
<circle cx="50" cy="50" r="45" fill="white"/>
|
||||||
|
<circle cx="35" cy="42" r="11" fill="#0f172a"/>
|
||||||
|
<circle cx="65" cy="42" r="11" fill="#0f172a"/>
|
||||||
|
<circle cx="50" cy="65" r="11" fill="#0f172a"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login-card">
|
||||||
|
<h1 class="login-title">Log in to Nextcloud</h1>
|
||||||
|
|
||||||
|
<form onsubmit="handleLogin(event)">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" id="user" placeholder=" " autocomplete="off" required>
|
||||||
|
<label for="user">Account name or email</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="password" id="password" placeholder=" " required>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<span class="input-icon" onclick="togglePassword()" title="Show password">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
|
||||||
|
<circle cx="12" cy="12" r="3"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="remember-row">
|
||||||
|
<label class="remember-checkbox">
|
||||||
|
<input type="checkbox" checked>
|
||||||
|
<span>Remember me</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="login-btn" id="loginBtn">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
||||||
|
</svg>
|
||||||
|
Log in
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="alt-login">
|
||||||
|
<button class="alt-login-btn" onclick="alert('Demo page - device login not available')">
|
||||||
|
Log in with a device
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="forgot-password">
|
||||||
|
<a href="#" onclick="alert('Demo page - password reset not available'); return false;">
|
||||||
|
Forgot password?
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<a href="https://nextcloud.com" target="_blank">Nextcloud</a> – a safe home for all your data
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function handleLogin(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const btn = document.getElementById('loginBtn');
|
||||||
|
const originalContent = btn.innerHTML;
|
||||||
|
|
||||||
|
btn.classList.add('loading');
|
||||||
|
btn.innerHTML = 'Logging in…';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
btn.classList.remove('loading');
|
||||||
|
btn.innerHTML = originalContent;
|
||||||
|
alert('🔒 This is a demo page. The real Nextcloud is not exposed.');
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function togglePassword() {
|
||||||
|
const pw = document.getElementById('password');
|
||||||
|
pw.type = pw.type === 'password' ? 'text' : 'password';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus username on load
|
||||||
|
document.getElementById('user').focus();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,698 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Pi-hole Dashboard</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-dark: #1a1a1a;
|
||||||
|
--bg-sidebar: #222;
|
||||||
|
--bg-card: #2a2a2a;
|
||||||
|
--border-color: #333;
|
||||||
|
--text-primary: #e0e0e0;
|
||||||
|
--text-secondary: #888;
|
||||||
|
--pihole-red: #96060c;
|
||||||
|
--pihole-green: #4caf50;
|
||||||
|
--pihole-blue: #3c8dbc;
|
||||||
|
--pihole-yellow: #f39c12;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: var(--bg-dark);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 14px;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Demo Banner */
|
||||||
|
.demo-banner {
|
||||||
|
background: #1a1a1a;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: var(--pihole-red);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Layout */
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
min-height: calc(100vh - 33px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar */
|
||||||
|
.sidebar {
|
||||||
|
width: 200px;
|
||||||
|
background: var(--bg-sidebar);
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
background: linear-gradient(180deg, #3c8dbc 0%, #357ca5 100%);
|
||||||
|
padding: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-box {
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pihole-logo {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background: var(--pihole-red);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pihole-logo::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -5px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 20px;
|
||||||
|
height: 15px;
|
||||||
|
background: var(--pihole-green);
|
||||||
|
border-radius: 10px 10px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-title {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot.active {
|
||||||
|
background: var(--pihole-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-menu {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: #2a2a2a;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: #2a2a2a;
|
||||||
|
color: white;
|
||||||
|
border-left: 3px solid var(--pihole-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-icon {
|
||||||
|
width: 18px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content */
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hostname {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stats Cards */
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.blue {
|
||||||
|
background: linear-gradient(135deg, #3c8dbc 0%, #2c6da0 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.red {
|
||||||
|
background: linear-gradient(135deg, #c0392b 0%, #962d22 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.yellow {
|
||||||
|
background: linear-gradient(135deg, #f39c12 0%, #c27a0e 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.green {
|
||||||
|
background: linear-gradient(135deg, #27ae60 0%, #1e8449 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-bg-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: -10px;
|
||||||
|
bottom: -10px;
|
||||||
|
font-size: 80px;
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(255,255,255,0.9);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: white;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-link {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 12px;
|
||||||
|
left: 20px;
|
||||||
|
right: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255,255,255,0.8);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-link:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Charts */
|
||||||
|
.chart-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-title {
|
||||||
|
font-size: 15px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-area {
|
||||||
|
height: 200px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bar Chart */
|
||||||
|
.bar-chart {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 160px;
|
||||||
|
padding: 0 4px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-chart::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(to bottom, transparent 19px, #333 20px),
|
||||||
|
linear-gradient(to right, transparent 19px, transparent 20px);
|
||||||
|
background-size: 100% 40px, 40px 100%;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-group {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: flex-end;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar {
|
||||||
|
width: 6px;
|
||||||
|
border-radius: 2px 2px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar.permitted {
|
||||||
|
background: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar.blocked {
|
||||||
|
background: var(--pihole-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar.client {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-axis {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 8px 4px 0;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-axis-y {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pie Charts Grid */
|
||||||
|
.pie-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pie-chart-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pie-chart {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pie-chart svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pie-legend {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-color {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-checkbox {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
accent-color: var(--pihole-blue);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy dashboard for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<h1>Pi-hole</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status-box">
|
||||||
|
<div class="pihole-logo">🕳️</div>
|
||||||
|
<div class="status-info">
|
||||||
|
<div class="status-title">Status</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-dot active"></span>
|
||||||
|
<span>Active</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-dot active"></span>
|
||||||
|
<span>Load: 0.12 0.15 0.18</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-dot active"></span>
|
||||||
|
<span>Memory usage: 12.4%</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span>🌡️ Temp: 42.0 °C</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-menu">
|
||||||
|
<div class="nav-item active">
|
||||||
|
<span class="nav-icon">🏠</span>
|
||||||
|
<span>Dashboard</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📋</span>
|
||||||
|
<span>Query Log</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📊</span>
|
||||||
|
<span>Long-term Data</span>
|
||||||
|
<span class="nav-arrow">›</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">👥</span>
|
||||||
|
<span>Groups</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🖥️</span>
|
||||||
|
<span>Clients</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🌐</span>
|
||||||
|
<span>Domains</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🛡️</span>
|
||||||
|
<span>Adlists</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">⏸️</span>
|
||||||
|
<span>Disable Blocking</span>
|
||||||
|
<span class="nav-arrow">›</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📝</span>
|
||||||
|
<span>Local DNS</span>
|
||||||
|
<span class="nav-arrow">›</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🔧</span>
|
||||||
|
<span>Tools</span>
|
||||||
|
<span class="nav-arrow">›</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">⚙️</span>
|
||||||
|
<span>Settings</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">❤️</span>
|
||||||
|
<span>Donate</span>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="content">
|
||||||
|
<div class="top-bar">
|
||||||
|
<button style="background: transparent; border: none; color: var(--text-secondary); font-size: 18px; cursor: pointer;">‹</button>
|
||||||
|
<span class="hostname">hostname: pihole</span>
|
||||||
|
<button style="background: transparent; border: none; color: var(--text-secondary); font-size: 18px; cursor: pointer;">☰</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Stats Cards -->
|
||||||
|
<div class="stats-grid">
|
||||||
|
<div class="stat-card blue">
|
||||||
|
<div class="stat-bg-icon">🌍</div>
|
||||||
|
<div class="stat-label">Total queries</div>
|
||||||
|
<div class="stat-value">73,770</div>
|
||||||
|
<div class="stat-link">
|
||||||
|
<span>23 active clients</span>
|
||||||
|
<span>›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card red">
|
||||||
|
<div class="stat-bg-icon">🛡️</div>
|
||||||
|
<div class="stat-label">Queries Blocked</div>
|
||||||
|
<div class="stat-value">17,304</div>
|
||||||
|
<div class="stat-link">
|
||||||
|
<span>List blocked queries</span>
|
||||||
|
<span>›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card yellow">
|
||||||
|
<div class="stat-bg-icon">📊</div>
|
||||||
|
<div class="stat-label">Percentage Blocked</div>
|
||||||
|
<div class="stat-value">23.5%</div>
|
||||||
|
<div class="stat-link">
|
||||||
|
<span>List all queries</span>
|
||||||
|
<span>›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-card green">
|
||||||
|
<div class="stat-bg-icon">📋</div>
|
||||||
|
<div class="stat-label">Domains on Adlists</div>
|
||||||
|
<div class="stat-value">254,501</div>
|
||||||
|
<div class="stat-link">
|
||||||
|
<span>Manage adlists</span>
|
||||||
|
<span>›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Total Queries Chart -->
|
||||||
|
<div class="chart-card">
|
||||||
|
<div class="chart-title">Total queries over last 24 hours</div>
|
||||||
|
<div class="chart-area">
|
||||||
|
<div class="chart-axis-y">
|
||||||
|
<span>1,200</span>
|
||||||
|
<span>1,000</span>
|
||||||
|
<span>800</span>
|
||||||
|
<span>600</span>
|
||||||
|
<span>400</span>
|
||||||
|
<span>200</span>
|
||||||
|
<span>0</span>
|
||||||
|
</div>
|
||||||
|
<div class="bar-chart" style="margin-left: 40px;">
|
||||||
|
<script>
|
||||||
|
// Generate bars
|
||||||
|
const hours = ['13:00','14:00','15:00','16:00','17:00','18:00','19:00','20:00','21:00','22:00','23:00','00:00','01:00','02:00','03:00','04:00','05:00','06:00','07:00','08:00','09:00','10:00','11:00','12:00'];
|
||||||
|
hours.forEach((hour, i) => {
|
||||||
|
const h1 = 30 + Math.random() * 50;
|
||||||
|
const h2 = 50 + Math.random() * 70;
|
||||||
|
document.write(`
|
||||||
|
<div class="bar-group">
|
||||||
|
<div class="bar permitted" style="height: ${h1}%;"></div>
|
||||||
|
<div class="bar blocked" style="height: ${h2}%;"></div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chart-axis">
|
||||||
|
<script>
|
||||||
|
hours.forEach(hour => document.write(`<span>${hour}</span>`));
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Client Activity Chart -->
|
||||||
|
<div class="chart-card">
|
||||||
|
<div class="chart-title">Client activity over last 24 hours</div>
|
||||||
|
<div class="chart-area">
|
||||||
|
<div class="chart-axis-y">
|
||||||
|
<span>1,200</span>
|
||||||
|
<span>1,000</span>
|
||||||
|
<span>800</span>
|
||||||
|
<span>600</span>
|
||||||
|
<span>400</span>
|
||||||
|
<span>200</span>
|
||||||
|
<span>0</span>
|
||||||
|
</div>
|
||||||
|
<div class="bar-chart" style="margin-left: 40px;">
|
||||||
|
<script>
|
||||||
|
hours.forEach((hour, i) => {
|
||||||
|
const colors = ['#9c27b0', '#e91e63', '#00bcd4', '#ff9800', '#4caf50'];
|
||||||
|
document.write(`<div class="bar-group">`);
|
||||||
|
colors.forEach(color => {
|
||||||
|
const h = 20 + Math.random() * 60;
|
||||||
|
document.write(`<div class="bar client" style="height: ${h}%; background: ${color}; width: 2px;"></div>`);
|
||||||
|
});
|
||||||
|
document.write(`</div>`);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chart-axis">
|
||||||
|
<script>
|
||||||
|
hours.forEach(hour => document.write(`<span>${hour}</span>`));
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pie Charts -->
|
||||||
|
<div class="pie-grid">
|
||||||
|
<div class="chart-card">
|
||||||
|
<div class="chart-title">Query Types</div>
|
||||||
|
<div class="pie-chart-container">
|
||||||
|
<div class="pie-chart">
|
||||||
|
<svg viewBox="0 0 100 100">
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#ff7043" stroke-width="20" stroke-dasharray="100 251"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#42a5f5" stroke-width="20" stroke-dasharray="60 251" stroke-dashoffset="-100"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#66bb6a" stroke-width="20" stroke-dasharray="40 251" stroke-dashoffset="-160"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#ab47bc" stroke-width="20" stroke-dasharray="30 251" stroke-dashoffset="-200"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#26c6da" stroke-width="20" stroke-dasharray="21 251" stroke-dashoffset="-230"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="pie-legend">
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #ff7043;"></div>
|
||||||
|
<span>A (IPv4)</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #42a5f5;"></div>
|
||||||
|
<span>AAAA (IPv6)</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #66bb6a;"></div>
|
||||||
|
<span>SRV</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #ab47bc;"></div>
|
||||||
|
<span>SOA</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #26c6da;"></div>
|
||||||
|
<span>PTR</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-card">
|
||||||
|
<div class="chart-title">Upstream servers</div>
|
||||||
|
<div class="pie-chart-container">
|
||||||
|
<div class="pie-chart">
|
||||||
|
<svg viewBox="0 0 100 100">
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#ff7043" stroke-width="20" stroke-dasharray="120 251"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#42a5f5" stroke-width="20" stroke-dasharray="80 251" stroke-dashoffset="-120"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#66bb6a" stroke-width="20" stroke-dasharray="51 251" stroke-dashoffset="-200"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="pie-legend">
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #ff7043;"></div>
|
||||||
|
<span>blocked</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #42a5f5;"></div>
|
||||||
|
<span>cached</span>
|
||||||
|
</label>
|
||||||
|
<label class="legend-item">
|
||||||
|
<input type="checkbox" class="legend-checkbox" checked>
|
||||||
|
<div class="legend-color" style="background: #66bb6a;"></div>
|
||||||
|
<span>localhost#5335</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,431 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Plex</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: #1f1f1f;
|
||||||
|
min-height: 100vh;
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner {
|
||||||
|
background: #e5a00d;
|
||||||
|
color: #000;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: #1f1f1f;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 40px;
|
||||||
|
bottom: 0;
|
||||||
|
width: 240px;
|
||||||
|
background: #1f1f1f;
|
||||||
|
border-right: 1px solid #333;
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
padding: 0 20px 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background: #e5a00d;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-text {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #e5a00d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-section {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-title {
|
||||||
|
padding: 0 20px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #888;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
padding: 10px 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover, .nav-item.active {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
border-left: 3px solid #e5a00d;
|
||||||
|
padding-left: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-icon {
|
||||||
|
width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin-left: 240px;
|
||||||
|
padding: 60px 30px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
width: 300px;
|
||||||
|
color: #eee;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box::placeholder {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
background: #e5a00d;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f1f1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.see-all {
|
||||||
|
color: #e5a00d;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movies-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-card {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-card:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-poster {
|
||||||
|
aspect-ratio: 2/3;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: linear-gradient(135deg, #333 0%, #555 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 48px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-poster::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(180deg, transparent 50%, rgba(0,0,0,0.8) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-meta {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-banner {
|
||||||
|
background: linear-gradient(135deg, #2a2a2a 0%, #1a1a1a 100%);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 40px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
display: flex;
|
||||||
|
gap: 30px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-poster {
|
||||||
|
width: 200px;
|
||||||
|
height: 300px;
|
||||||
|
background: linear-gradient(135deg, #444 0%, #666 100%);
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 80px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-info h2 {
|
||||||
|
font-size: 32px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-meta {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-desc {
|
||||||
|
color: #ccc;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: #e5a00d;
|
||||||
|
color: #1f1f1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy media server for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="logo">
|
||||||
|
<div class="logo-icon">▶️</div>
|
||||||
|
<span class="logo-text">Plex</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-section">
|
||||||
|
<div class="nav-title">Discover</div>
|
||||||
|
<div class="nav-item active">
|
||||||
|
<span class="nav-icon">🏠</span>
|
||||||
|
<span>Home</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📺</span>
|
||||||
|
<span>Movies</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🎬</span>
|
||||||
|
<span>TV Shows</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🎵</span>
|
||||||
|
<span>Music</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-section">
|
||||||
|
<div class="nav-title">Library</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📁</span>
|
||||||
|
<span>All Media</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📊</span>
|
||||||
|
<span>Dashboard</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="main-content">
|
||||||
|
<div class="header">
|
||||||
|
<input type="text" class="search-box" placeholder="Search for movies, shows, music...">
|
||||||
|
<div class="user-menu">
|
||||||
|
<span>🔔</span>
|
||||||
|
<span>⚙️</span>
|
||||||
|
<div class="user-avatar">A</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hero-banner">
|
||||||
|
<div class="hero-poster">🎭</div>
|
||||||
|
<div class="hero-info">
|
||||||
|
<h2>Continue Watching</h2>
|
||||||
|
<div class="hero-meta">2023 • 2h 15m • Action, Sci-Fi</div>
|
||||||
|
<p class="hero-desc">
|
||||||
|
Pick up where you left off. Your personal media server is ready with all your favorite movies and TV shows.
|
||||||
|
</p>
|
||||||
|
<div class="hero-buttons">
|
||||||
|
<button class="btn btn-primary">▶ Play</button>
|
||||||
|
<button class="btn btn-secondary">+ My List</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3 class="section-title">Recently Added Movies</h3>
|
||||||
|
<span class="see-all">See all →</span>
|
||||||
|
</div>
|
||||||
|
<div class="movies-grid">
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🎬</div>
|
||||||
|
<div class="movie-title">The Matrix Resurrections</div>
|
||||||
|
<div class="movie-meta">2021 • 148 min</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🚀</div>
|
||||||
|
<div class="movie-title">Interstellar</div>
|
||||||
|
<div class="movie-meta">2014 • 169 min</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🦸</div>
|
||||||
|
<div class="movie-title">The Dark Knight</div>
|
||||||
|
<div class="movie-meta">2008 • 152 min</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🤖</div>
|
||||||
|
<div class="movie-title">Blade Runner 2049</div>
|
||||||
|
<div class="movie-meta">2017 • 164 min</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🌌</div>
|
||||||
|
<div class="movie-title">Dune</div>
|
||||||
|
<div class="movie-meta">2021 • 155 min</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">⚔️</div>
|
||||||
|
<div class="movie-title">Inception</div>
|
||||||
|
<div class="movie-meta">2010 • 148 min</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3 class="section-title">Continue Watching</h3>
|
||||||
|
<span class="see-all">See all →</span>
|
||||||
|
</div>
|
||||||
|
<div class="movies-grid">
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">📺</div>
|
||||||
|
<div class="movie-title">Breaking Bad S05E08</div>
|
||||||
|
<div class="movie-meta">45 min remaining</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🐉</div>
|
||||||
|
<div class="movie-title">House of Dragon S01E03</div>
|
||||||
|
<div class="movie-meta">32 min remaining</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">⚔️</div>
|
||||||
|
<div class="movie-title">The Witcher S02E05</div>
|
||||||
|
<div class="movie-meta">28 min remaining</div>
|
||||||
|
</div>
|
||||||
|
<div class="movie-card">
|
||||||
|
<div class="movie-poster">🕵️</div>
|
||||||
|
<div class="movie-title">Sherlock S04E01</div>
|
||||||
|
<div class="movie-meta">52 min remaining</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,796 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Home - Portainer</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-dark: #0f0f0f;
|
||||||
|
--bg-sidebar: #1a1a1a;
|
||||||
|
--bg-card: #1e1e1e;
|
||||||
|
--bg-hover: #252525;
|
||||||
|
--border-color: #2a2a2a;
|
||||||
|
--text-primary: #e0e0e0;
|
||||||
|
--text-secondary: #888;
|
||||||
|
--portainer-blue: #13bef9;
|
||||||
|
--portainer-teal: #00bfa5;
|
||||||
|
--success: #4caf50;
|
||||||
|
--danger: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: var(--bg-dark);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Demo Banner */
|
||||||
|
.demo-banner {
|
||||||
|
background: #141414;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: var(--portainer-blue);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Layout */
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
height: calc(100vh - 33px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Left Sidebar */
|
||||||
|
.sidebar {
|
||||||
|
width: 240px;
|
||||||
|
background: var(--bg-sidebar);
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: white;
|
||||||
|
letter-spacing: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon span {
|
||||||
|
color: var(--portainer-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-badge {
|
||||||
|
font-size: 9px;
|
||||||
|
color: var(--portainer-teal);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-nav {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-section {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-header {
|
||||||
|
padding: 8px 16px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 11px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--portainer-blue);
|
||||||
|
border-left: 3px solid var(--portainer-blue);
|
||||||
|
padding-left: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-icon {
|
||||||
|
width: 18px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-arrow {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-footer {
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content */
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background: var(--portainer-blue);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Environment Card */
|
||||||
|
.env-card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
background: #1da1f2;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-name-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-name {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
background: rgba(76, 175, 80, 0.15);
|
||||||
|
color: var(--success);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-status::before {
|
||||||
|
content: '';
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background: var(--success);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-meta-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-meta-item span {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-path {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stats Row */
|
||||||
|
.env-stats {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot.running {
|
||||||
|
background: var(--success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot.stopped {
|
||||||
|
background: var(--danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Environment Actions */
|
||||||
|
.env-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: white;
|
||||||
|
color: #000;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-status::before {
|
||||||
|
content: '✕';
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Filters Bar */
|
||||||
|
.filters-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-dropdown {
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 12px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
min-width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 400px;
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 16px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box::placeholder {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-refresh {
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 16px;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-refresh:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card Header */
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-subtitle {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scrollbar */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: var(--bg-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #333;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #444;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy dashboard for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<!-- Left Sidebar -->
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<div class="logo">
|
||||||
|
<div>
|
||||||
|
<div class="logo-icon">PORTAINER<span>.</span>IO</div>
|
||||||
|
<div class="logo-badge">Community Edition</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="sidebar-nav">
|
||||||
|
<div class="nav-section">
|
||||||
|
<div class="nav-item active">
|
||||||
|
<span class="nav-icon">🏠</span>
|
||||||
|
<span>Home</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-section">
|
||||||
|
<div class="nav-header">Environment: / None selected</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-section">
|
||||||
|
<div class="nav-header">Administration</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">👤</span>
|
||||||
|
<span>User-related</span>
|
||||||
|
<span class="nav-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🖥️</span>
|
||||||
|
<span>Environment-related</span>
|
||||||
|
<span class="nav-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📦</span>
|
||||||
|
<span>Registries</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">📋</span>
|
||||||
|
<span>Logs</span>
|
||||||
|
<span class="nav-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">🔔</span>
|
||||||
|
<span>Notifications</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<span class="nav-icon">⚙️</span>
|
||||||
|
<span>Settings</span>
|
||||||
|
<span class="nav-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="sidebar-footer">
|
||||||
|
Community Edition 2.21.3 LTS
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="content">
|
||||||
|
<div class="page-header">
|
||||||
|
<h1 class="page-title">
|
||||||
|
Home
|
||||||
|
<span style="color: var(--portainer-blue); cursor: pointer;">↻</span>
|
||||||
|
</h1>
|
||||||
|
<div class="page-actions">
|
||||||
|
<button class="icon-btn">🔔</button>
|
||||||
|
<button class="icon-btn">❓</button>
|
||||||
|
<div class="user-menu">
|
||||||
|
<div class="user-avatar">A</div>
|
||||||
|
<span>admin</span>
|
||||||
|
<span>▼</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Environments Section -->
|
||||||
|
<div class="env-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">
|
||||||
|
<span style="font-size: 20px;">🖥️</span>
|
||||||
|
Environments
|
||||||
|
</div>
|
||||||
|
<div style="margin-left: auto; display: flex; gap: 8px;">
|
||||||
|
<button class="btn-refresh">↻ Refresh</button>
|
||||||
|
<button class="btn-refresh">⬇ Kubectl</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-subtitle" style="margin-bottom: 16px;">
|
||||||
|
Click on an environment to manage
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filters -->
|
||||||
|
<div class="filters-bar">
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Platform</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Connection Type</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Status</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Tags</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Groups</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-dropdown">
|
||||||
|
<option>Agent Version</option>
|
||||||
|
</select>
|
||||||
|
<button style="background: transparent; border: none; color: var(--text-secondary); cursor: pointer;">
|
||||||
|
Clear all
|
||||||
|
</button>
|
||||||
|
<div style="margin-left: auto; display: flex; gap: 8px;">
|
||||||
|
<select class="filter-dropdown" style="min-width: 100px;">
|
||||||
|
<option>Sort By</option>
|
||||||
|
</select>
|
||||||
|
<button class="btn-icon">↕</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Environment 1 -->
|
||||||
|
<div class="env-card" style="margin-bottom: 12px;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
|
||||||
|
<div class="env-header" style="flex: 1; margin-bottom: 0;">
|
||||||
|
<div class="env-icon">🐳</div>
|
||||||
|
<div class="env-info">
|
||||||
|
<div class="env-name-row">
|
||||||
|
<span class="env-name">local</span>
|
||||||
|
<span class="env-status">Up</span>
|
||||||
|
<span style="color: var(--text-secondary); font-size: 12px;">↻ 2026-02-02 12:42:53</span>
|
||||||
|
<span style="color: var(--text-secondary); font-size: 12px;">Standalone 2.21.3</span>
|
||||||
|
<span class="env-path">/var/run/docker.sock</span>
|
||||||
|
</div>
|
||||||
|
<div class="env-meta">
|
||||||
|
<span class="env-meta-item">Group: <span>Unassigned</span></span>
|
||||||
|
<span class="env-meta-item">🏷️ No tags</span>
|
||||||
|
<span class="env-meta-item">⚡ Local</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="env-actions">
|
||||||
|
<button class="btn btn-primary">📡 Live connect</button>
|
||||||
|
<button class="btn-icon">✏️</button>
|
||||||
|
<div style="text-align: right;">
|
||||||
|
<div class="connection-status">Disconnected</div>
|
||||||
|
<button class="btn-icon" style="margin-top: 4px;">⚙️</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="env-stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">📚</span>
|
||||||
|
<span class="stat-value">12</span>
|
||||||
|
<span class="stat-label">stacks</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">📦</span>
|
||||||
|
<span class="stat-value">24</span>
|
||||||
|
<span class="stat-label">containers</span>
|
||||||
|
</div>
|
||||||
|
<div class="container-status">
|
||||||
|
<span class="status-dot running"></span>
|
||||||
|
<span>18</span>
|
||||||
|
<span class="status-dot stopped"></span>
|
||||||
|
<span>2</span>
|
||||||
|
<span class="status-dot" style="background: #ff9800;"></span>
|
||||||
|
<span>0</span>
|
||||||
|
<span class="status-dot" style="background: #9c27b0;"></span>
|
||||||
|
<span>0</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">💾</span>
|
||||||
|
<span class="stat-value">32</span>
|
||||||
|
<span class="stat-label">volumes</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">🖼️</span>
|
||||||
|
<span class="stat-value">87</span>
|
||||||
|
<span class="stat-label">images</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">🖥️</span>
|
||||||
|
<span class="stat-value">4</span>
|
||||||
|
<span class="stat-label">CPU</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">💽</span>
|
||||||
|
<span class="stat-value">7.8</span>
|
||||||
|
<span class="stat-label">GB RAM</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Environment 2 -->
|
||||||
|
<div class="env-card">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
|
||||||
|
<div class="env-header" style="flex: 1; margin-bottom: 0;">
|
||||||
|
<div class="env-icon">🐳</div>
|
||||||
|
<div class="env-info">
|
||||||
|
<div class="env-name-row">
|
||||||
|
<span class="env-name">Compute-01</span>
|
||||||
|
<span class="env-status">Up</span>
|
||||||
|
<span style="color: var(--text-secondary); font-size: 12px;">↻ 2026-02-02 12:42:53</span>
|
||||||
|
<span style="color: var(--text-secondary); font-size: 12px;">Standalone 2.21.3</span>
|
||||||
|
<span class="env-path">agent.local:9001</span>
|
||||||
|
</div>
|
||||||
|
<div class="env-meta">
|
||||||
|
<span class="env-meta-item">Group: <span>Unassigned</span></span>
|
||||||
|
<span class="env-meta-item">🏷️ No tags</span>
|
||||||
|
<span class="env-meta-item">⚡ Agent 2.21.3</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="env-actions">
|
||||||
|
<button class="btn btn-primary">📡 Live connect</button>
|
||||||
|
<button class="btn-icon">✏️</button>
|
||||||
|
<div style="text-align: right;">
|
||||||
|
<div class="connection-status">Disconnected</div>
|
||||||
|
<button class="btn-icon" style="margin-top: 4px;">⚙️</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="env-stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">📚</span>
|
||||||
|
<span class="stat-value">5</span>
|
||||||
|
<span class="stat-label">stacks</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">📦</span>
|
||||||
|
<span class="stat-value">16</span>
|
||||||
|
<span class="stat-label">containers</span>
|
||||||
|
</div>
|
||||||
|
<div class="container-status">
|
||||||
|
<span class="status-dot running"></span>
|
||||||
|
<span>14</span>
|
||||||
|
<span class="status-dot stopped"></span>
|
||||||
|
<span>1</span>
|
||||||
|
<span class="status-dot" style="background: #ff9800;"></span>
|
||||||
|
<span>0</span>
|
||||||
|
<span class="status-dot" style="background: #9c27b0;"></span>
|
||||||
|
<span>0</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">💾</span>
|
||||||
|
<span class="stat-value">10</span>
|
||||||
|
<span class="stat-label">volumes</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">🖼️</span>
|
||||||
|
<span class="stat-value">24</span>
|
||||||
|
<span class="stat-label">images</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">🖥️</span>
|
||||||
|
<span class="stat-value">6</span>
|
||||||
|
<span class="stat-label">CPU</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="stat-icon">💽</span>
|
||||||
|
<span class="stat-value">8.2</span>
|
||||||
|
<span class="stat-label">GB RAM</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,624 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Proxmox Virtual Environment</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-dark: #1e1e1e;
|
||||||
|
--bg-panel: #2d2d2d;
|
||||||
|
--bg-sidebar: #252525;
|
||||||
|
--bg-input: #3a3a3a;
|
||||||
|
--border-color: #404040;
|
||||||
|
--text-primary: #e0e0e0;
|
||||||
|
--text-secondary: #999;
|
||||||
|
--proxmox-orange: #e57000;
|
||||||
|
--proxmox-orange-light: #ff8c00;
|
||||||
|
--btn-blue: #3d85c6;
|
||||||
|
--btn-blue-hover: #2d6da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: var(--bg-dark);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Demo Banner */
|
||||||
|
.demo-banner {
|
||||||
|
background: #1a1a1a;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
text-align: center;
|
||||||
|
padding: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
z-index: 1000;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-banner a {
|
||||||
|
color: var(--proxmox-orange);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Top Bar */
|
||||||
|
.top-bar {
|
||||||
|
background: linear-gradient(180deg, #3a3a3a 0%, #2d2d2d 100%);
|
||||||
|
border-bottom: 1px solid #1a1a1a;
|
||||||
|
height: 42px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 8px;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-area {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxmox-logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
background: var(--proxmox-orange);
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
color: white;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-text {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-text span {
|
||||||
|
color: var(--proxmox-orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 400px;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input {
|
||||||
|
width: 100%;
|
||||||
|
height: 28px;
|
||||||
|
background: #1e1e1e;
|
||||||
|
border: 1px solid #404040;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 10px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input::placeholder {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-btn {
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 12px;
|
||||||
|
background: linear-gradient(180deg, #4a4a4a 0%, #3a3a3a 100%);
|
||||||
|
border: 1px solid #505050;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-btn:hover {
|
||||||
|
background: linear-gradient(180deg, #5a5a5a 0%, #4a4a4a 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-btn.primary {
|
||||||
|
background: var(--btn-blue);
|
||||||
|
border-color: #2d6da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-btn.primary:hover {
|
||||||
|
background: var(--btn-blue-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Container */
|
||||||
|
.main-container {
|
||||||
|
display: flex;
|
||||||
|
height: calc(100vh - 90px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Left Sidebar */
|
||||||
|
.sidebar {
|
||||||
|
width: 220px;
|
||||||
|
background: var(--bg-sidebar);
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-selector {
|
||||||
|
flex: 1;
|
||||||
|
height: 26px;
|
||||||
|
background: #3a3a3a;
|
||||||
|
border: 1px solid #505050;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-btn {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
background: #3a3a3a;
|
||||||
|
border: 1px solid #505050;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-item:hover {
|
||||||
|
background: #333;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-icon {
|
||||||
|
width: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Center Content - Login Area */
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: var(--bg-dark);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Login Window */
|
||||||
|
.login-window {
|
||||||
|
background: #363636;
|
||||||
|
border: 1px solid #505050;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
|
||||||
|
width: 380px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header {
|
||||||
|
background: linear-gradient(180deg, #404040 0%, #363636 100%);
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-bottom: 1px solid #505050;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--btn-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-body {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
width: 80px;
|
||||||
|
text-align: right;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
background: var(--bg-input);
|
||||||
|
border: 1px solid #505050;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 30px 0 10px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--btn-blue);
|
||||||
|
box-shadow: 0 0 0 1px var(--btn-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: var(--proxmox-orange);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.form-input {
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23999' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 8px center;
|
||||||
|
padding-right: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid #505050;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-label input {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
accent-color: var(--btn-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 20px;
|
||||||
|
background: var(--btn-blue);
|
||||||
|
border: 1px solid #2d6da3;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: white;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn:hover {
|
||||||
|
background: var(--btn-blue-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bottom Panel */
|
||||||
|
.bottom-panel {
|
||||||
|
height: 180px;
|
||||||
|
background: var(--bg-panel);
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-tabs {
|
||||||
|
display: flex;
|
||||||
|
background: #363636;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-tab {
|
||||||
|
padding: 8px 16px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-tab:hover {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-tab.active {
|
||||||
|
background: var(--bg-panel);
|
||||||
|
color: var(--btn-blue);
|
||||||
|
border-bottom: 2px solid var(--btn-blue);
|
||||||
|
margin-bottom: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table th {
|
||||||
|
text-align: left;
|
||||||
|
padding: 8px 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: normal;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
background: #2d2d2d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table th.sortable::after {
|
||||||
|
content: ' ↕';
|
||||||
|
font-size: 10px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table td {
|
||||||
|
padding: 8px 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table tr:hover td {
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scrollbar */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: var(--bg-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #505050;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #606060;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="demo-banner">
|
||||||
|
🔒 This is a dummy login page for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Top Bar -->
|
||||||
|
<div class="top-bar">
|
||||||
|
<div class="logo-area">
|
||||||
|
<div class="proxmox-logo">
|
||||||
|
<div class="logo-icon">P</div>
|
||||||
|
<div class="logo-text"><span>PROX</span>MOX</div>
|
||||||
|
</div>
|
||||||
|
<div style="color: var(--text-secondary); font-size: 12px;">Virtual Environment</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-box">
|
||||||
|
<input type="text" placeholder="Search">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="top-actions">
|
||||||
|
<button class="top-btn">
|
||||||
|
<span>📄</span> Documentation
|
||||||
|
</button>
|
||||||
|
<button class="top-btn primary">
|
||||||
|
<span>🖥️</span> Create VM
|
||||||
|
</button>
|
||||||
|
<button class="top-btn primary">
|
||||||
|
<span>📦</span> Create CT
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-menu">
|
||||||
|
<button class="top-btn" style="width: 32px; padding: 0; justify-content: center;">
|
||||||
|
👤
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Container -->
|
||||||
|
<div class="main-container">
|
||||||
|
<!-- Left Sidebar -->
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<select class="view-selector">
|
||||||
|
<option>Server View</option>
|
||||||
|
</select>
|
||||||
|
<button class="settings-btn">⚙️</button>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-content">
|
||||||
|
<div class="tree-item">
|
||||||
|
<span class="tree-icon">▼</span>
|
||||||
|
<span class="tree-icon">🏢</span>
|
||||||
|
<span>Datacenter</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- Center Content -->
|
||||||
|
<main class="content">
|
||||||
|
<!-- Login Window -->
|
||||||
|
<div class="login-window">
|
||||||
|
<div class="login-header">Proxmox VE Login</div>
|
||||||
|
<div class="login-body">
|
||||||
|
<form onsubmit="handleLogin(event)">
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label">User name:</label>
|
||||||
|
<div class="form-input-wrapper">
|
||||||
|
<input type="text" class="form-input" id="username" autocomplete="off">
|
||||||
|
<span class="input-icon">🔴</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label">Password:</label>
|
||||||
|
<div class="form-input-wrapper">
|
||||||
|
<input type="password" class="form-input" id="password">
|
||||||
|
<span class="input-icon">🔴</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label">Realm:</label>
|
||||||
|
<div class="form-input-wrapper">
|
||||||
|
<select class="form-input">
|
||||||
|
<option>Linux PAM standard authentication</option>
|
||||||
|
<option>Proxmox VE authentication server</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label">Language:</label>
|
||||||
|
<div class="form-input-wrapper">
|
||||||
|
<select class="form-input">
|
||||||
|
<option>English - English</option>
|
||||||
|
<option>Deutsch - German</option>
|
||||||
|
<option>Français - French</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login-footer">
|
||||||
|
<label class="checkbox-label">
|
||||||
|
<input type="checkbox" checked>
|
||||||
|
Save User name:
|
||||||
|
</label>
|
||||||
|
<button type="submit" class="login-btn">Login</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bottom Panel -->
|
||||||
|
<div class="bottom-panel">
|
||||||
|
<div class="panel-tabs">
|
||||||
|
<div class="panel-tab active">Tasks</div>
|
||||||
|
<div class="panel-tab">Cluster log</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-content">
|
||||||
|
<table class="data-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sortable">Start Time</th>
|
||||||
|
<th class="sortable">End Time</th>
|
||||||
|
<th>Node</th>
|
||||||
|
<th>User name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>02/02/2026 12:21:42</td>
|
||||||
|
<td>-</td>
|
||||||
|
<td>pve</td>
|
||||||
|
<td>root@pam</td>
|
||||||
|
<td>Login</td>
|
||||||
|
<td>✓ OK</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>02/02/2026 12:20:15</td>
|
||||||
|
<td>02/02/2026 12:20:16</td>
|
||||||
|
<td>pve</td>
|
||||||
|
<td>root@pam</td>
|
||||||
|
<td>VM 100 - Start</td>
|
||||||
|
<td>✓ OK</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>02/02/2026 12:18:33</td>
|
||||||
|
<td>02/02/2026 12:18:34</td>
|
||||||
|
<td>pve</td>
|
||||||
|
<td>root@pam</td>
|
||||||
|
<td>VM 101 - Stop</td>
|
||||||
|
<td>✓ OK</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function handleLogin(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
alert('🔒 This is a demo page. The real Proxmox VE is not exposed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus username on load
|
||||||
|
document.getElementById('username').focus();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue