Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,22 @@ cargo build --workspace
# Release build (optimized)
cargo build --workspace --release

# WASM build
cd crates/wasm && wasm-pack build --release --target web
# WASM build (for extension)
wasm-pack build crates/wasm --target web --out-dir ../../extension/pkg

# Run benchmarks
cargo bench
```

## Project Status

- [x] **Stage 1**: Core Foundation & WebRTC Signaling
- [x] **Stage 2**: WASM Bridge & Chrome Extension Interface
- [x] **Stage 3**: Media Stream Management & Peer Connections
- [x] **Stage 4**: Rust-to-JS Bridge & UI Utilities
- [x] **Stage 5**: UI Components & Admin Interface
- [ ] **Stage 6**: Production Readiness (bundle size, benchmarks)

## Documentation

- [Implementation Plan](docs/implementation_plan.md) - Detailed development roadmap
Expand Down
16 changes: 16 additions & 0 deletions admin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Rust Video Chat - Admin Interface

A standalone dashboard for managing video chat rooms and participants.

## Features
- **Room Monitoring**: View active rooms and participant counts.
- **Management**: Create or close rooms remotely.
- **Analytics**: Monitor server health and latency.

## Usage
Simply open `index.html` in a modern web browser.
In a production environment, this would be served by the SFU server or a static site host.

## Development
To modify the dashboard, edit `app.js` and `styles.css`.
Currently uses mock data for demonstration.
51 changes: 51 additions & 0 deletions admin/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
document.addEventListener('DOMContentLoaded', () => {
console.log('Admin Dashboard Initialized');

// Mock Data
const mockRooms = [
{ id: 'room-101', created: '2026-01-22 10:30', participants: 4, status: 'Active' },
{ id: 'dev-session', created: '2026-01-22 11:45', participants: 2, status: 'Active' },
{ id: 'quick-chat', created: '2026-01-22 12:10', participants: 0, status: 'Idle' }
];

const roomTableBody = document.getElementById('roomTableBody');
const totalRoomsEl = document.getElementById('totalRooms');
const totalParticipantsEl = document.getElementById('totalParticipants');

function renderRooms() {
roomTableBody.innerHTML = '';
let totalParts = 0;

mockRooms.forEach(room => {
totalParts += room.participants;
const tr = document.createElement('tr');
tr.innerHTML = `
<td><code>${room.id}</code></td>
<td>${room.created}</td>
<td>${room.participants}</td>
<td><span class="status-badge">${room.status}</span></td>
<td>
<button class="action-btn">View</button>
<button class="action-btn delete">Close</button>
</td>
`;
roomTableBody.appendChild(tr);
});

totalRoomsEl.textContent = mockRooms.length;
totalParticipantsEl.textContent = totalParts;
}

document.getElementById('createRoomBtn').addEventListener('click', () => {
const id = 'room-' + Math.floor(Math.random() * 1000);
mockRooms.push({
id: id,
created: new Date().toISOString().slice(0, 16).replace('T', ' '),
participants: 0,
status: 'Idle'
});
renderRooms();
});

renderRooms();
});
71 changes: 71 additions & 0 deletions admin/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rust Video Chat - Admin Dashboard</title>
<link rel="stylesheet" href="styles.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
</head>

<body>
<div class="sidebar">
<div class="sidebar-header">
<div class="logo-box">R</div>
<span>Admin Panel</span>
</div>
<nav>
<a href="#" class="active">Rooms</a>
<a href="#">Participants</a>
<a href="#">Analytics</a>
<a href="#">Settings</a>
</nav>
<div class="sidebar-footer">
v0.1.0-alpha
</div>
</div>

<main class="content">
<header>
<h2>Active Rooms</h2>
<button class="primary-btn" id="createRoomBtn">+ Create Room</button>
</header>

<div class="stats-grid">
<div class="stat-card">
<span class="stat-label">Total Rooms</span>
<span class="stat-value" id="totalRooms">--</span>
</div>
<div class="stat-card">
<span class="stat-label">Active Participants</span>
<span class="stat-value" id="totalParticipants">--</span>
</div>
<div class="stat-card">
<span class="stat-label">Avg. Latency</span>
<span class="stat-value" id="avgLatency">-- ms</span>
</div>
</div>

<section class="room-list-container">
<table class="room-table">
<thead>
<tr>
<th>Room ID</th>
<th>Created</th>
<th>Participants</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="roomTableBody">
<!-- Dynamic content -->
</tbody>
</table>
</section>
</main>

<script src="app.js"></script>
</body>

</html>
201 changes: 201 additions & 0 deletions admin/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
:root {
--bg-dark: #0a0a0c;
--sidebar-bg: #111114;
--card-bg: #1a1a1e;
--text-main: #e1e1e6;
--text-dim: #a1a1aa;
--accent: #00d2ff;
--accent-hover: #00b8e6;
--border: #27272a;
--success: #10b981;
}

* {
box-sizing: border-box;
}

body {
margin: 0;
padding: 0;
background-color: var(--bg-dark);
color: var(--text-main);
font-family: 'Inter', sans-serif;
display: flex;
height: 100vh;
}

/* Sidebar */
.sidebar {
width: 260px;
background-color: var(--sidebar-bg);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
}

.sidebar-header {
padding: 24px;
display: flex;
align-items: center;
gap: 12px;
font-weight: 700;
font-size: 1.1rem;
}

.logo-box {
width: 32px;
height: 32px;
background: linear-gradient(135deg, var(--accent), #3a7bd5);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: #000;
}

nav {
flex: 1;
padding: 12px;
}

nav a {
display: block;
padding: 12px 16px;
color: var(--text-dim);
text-decoration: none;
border-radius: 8px;
margin-bottom: 4px;
transition: all 0.2s;
}

nav a:hover,
nav a.active {
background-color: #27272a;
color: var(--text-main);
}

nav a.active {
border-left: 3px solid var(--accent);
}

.sidebar-footer {
padding: 24px;
color: var(--text-dim);
font-size: 0.8rem;
border-top: 1px solid var(--border);
}

/* Main Content */
.content {
flex: 1;
padding: 40px;
overflow-y: auto;
}

header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32px;
}

h2 {
margin: 0;
font-size: 1.5rem;
}

.primary-btn {
background-color: var(--accent);
color: #000;
border: none;
padding: 10px 20px;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
}

.primary-btn:hover {
background-color: var(--accent-hover);
}

/* Stats */
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin-bottom: 40px;
}

.stat-card {
background-color: var(--card-bg);
padding: 24px;
border-radius: 12px;
border: 1px solid var(--border);
display: flex;
flex-direction: column;
gap: 8px;
}

.stat-label {
color: var(--text-dim);
font-size: 0.9rem;
}

.stat-value {
font-size: 1.8rem;
font-weight: 700;
}

/* Table */
.room-list-container {
background-color: var(--sidebar-bg);
border-radius: 12px;
border: 1px solid var(--border);
overflow: hidden;
}

.room-table {
width: 100%;
border-collapse: collapse;
text-align: left;
}

.room-table th {
padding: 16px 24px;
border-bottom: 1px solid var(--border);
color: var(--text-dim);
font-weight: 600;
text-transform: uppercase;
font-size: 0.75rem;
letter-spacing: 0.05em;
}

.room-table td {
padding: 16px 24px;
border-bottom: 1px solid var(--border);
font-size: 0.95rem;
}

.status-badge {
padding: 4px 8px;
border-radius: 6px;
font-size: 0.75rem;
font-weight: 600;
background-color: #065f46;
color: #34d399;
}

.action-btn {
background: none;
border: none;
color: var(--accent);
cursor: pointer;
font-size: 0.9rem;
padding: 0;
margin-right: 12px;
}

.action-btn.delete {
color: #ef4444;
}
Loading