S-Dreamer commited on
Commit
d21a748
·
verified ·
1 Parent(s): 497ff34

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +939 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Esp32 Cam Dashboard
3
- emoji: 🚀
4
- colorFrom: gray
5
- colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: esp32-cam-dashboard
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
+ colorTo: yellow
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,939 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ESP32-CAM Admin Panel</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .sidebar {
11
+ transition: all 0.3s ease;
12
+ }
13
+ .stream-container {
14
+ aspect-ratio: 16/9;
15
+ background-color: #1a202c;
16
+ }
17
+ .progress-bar {
18
+ transition: width 0.3s ease;
19
+ }
20
+ .device-card:hover {
21
+ transform: translateY(-2px);
22
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
23
+ }
24
+ .tab-content {
25
+ display: none;
26
+ }
27
+ .tab-content.active {
28
+ display: block;
29
+ animation: fadeIn 0.3s ease;
30
+ }
31
+ @keyframes fadeIn {
32
+ from { opacity: 0; }
33
+ to { opacity: 1; }
34
+ }
35
+ .toast {
36
+ animation: slideIn 0.3s ease, fadeOut 0.3s ease 2.7s forwards;
37
+ }
38
+ @keyframes slideIn {
39
+ from { transform: translateX(100%); }
40
+ to { transform: translateX(0); }
41
+ }
42
+ @keyframes fadeOut {
43
+ to { opacity: 0; }
44
+ }
45
+ .flash-progress {
46
+ height: 6px;
47
+ background-color: #e5e7eb;
48
+ border-radius: 3px;
49
+ overflow: hidden;
50
+ }
51
+ .flash-progress-bar {
52
+ height: 100%;
53
+ background-color: #3b82f6;
54
+ transition: width 0.3s ease;
55
+ }
56
+ .console-output {
57
+ font-family: 'Courier New', monospace;
58
+ background-color: #1e293b;
59
+ color: #f8fafc;
60
+ height: 200px;
61
+ overflow-y: auto;
62
+ padding: 1rem;
63
+ border-radius: 0.375rem;
64
+ font-size: 0.875rem;
65
+ line-height: 1.25rem;
66
+ }
67
+ </style>
68
+ </head>
69
+ <body class="bg-gray-100 font-sans">
70
+ <!-- Main Container -->
71
+ <div class="flex h-screen overflow-hidden">
72
+ <!-- Sidebar -->
73
+ <div class="sidebar bg-gray-800 text-white w-64 flex-shrink-0">
74
+ <div class="p-4 border-b border-gray-700">
75
+ <h1 class="text-xl font-bold flex items-center">
76
+ <i class="fas fa-camera mr-2"></i>
77
+ ESP32-CAM Admin
78
+ </h1>
79
+ </div>
80
+ <nav class="p-4">
81
+ <ul>
82
+ <li class="mb-2">
83
+ <a href="#" class="flex items-center p-2 rounded hover:bg-gray-700 transition tab-link active" data-tab="dashboard">
84
+ <i class="fas fa-tachometer-alt mr-3"></i>
85
+ Dashboard
86
+ </a>
87
+ </li>
88
+ <li class="mb-2">
89
+ <a href="#" class="flex items-center p-2 rounded hover:bg-gray-700 transition tab-link" data-tab="devices">
90
+ <i class="fas fa-microchip mr-3"></i>
91
+ Devices
92
+ </a>
93
+ </li>
94
+ <li class="mb-2">
95
+ <a href="#" class="flex items-center p-2 rounded hover:bg-gray-700 transition tab-link" data-tab="streaming">
96
+ <i class="fas fa-video mr-3"></i>
97
+ Streaming
98
+ </a>
99
+ </li>
100
+ <li class="mb-2">
101
+ <a href="#" class="flex items-center p-2 rounded hover:bg-gray-700 transition tab-link" data-tab="firmware">
102
+ <i class="fas fa-file-upload mr-3"></i>
103
+ Firmware
104
+ </a>
105
+ </li>
106
+ <li class="mb-2">
107
+ <a href="#" class="flex items-center p-2 rounded hover:bg-gray-700 transition tab-link" data-tab="settings">
108
+ <i class="fas fa-cog mr-3"></i>
109
+ Settings
110
+ </a>
111
+ </li>
112
+ </ul>
113
+ </nav>
114
+ <div class="absolute bottom-0 w-full p-4 border-t border-gray-700">
115
+ <div class="flex items-center">
116
+ <div class="w-10 h-10 rounded-full bg-gray-600 flex items-center justify-center mr-3">
117
+ <i class="fas fa-user"></i>
118
+ </div>
119
+ <div>
120
+ <p class="font-medium">Admin User</p>
121
+ <p class="text-xs text-gray-400">Super Admin</p>
122
+ </div>
123
+ </div>
124
+ </div>
125
+ </div>
126
+
127
+ <!-- Main Content -->
128
+ <div class="flex-1 overflow-auto">
129
+ <!-- Header -->
130
+ <header class="bg-white shadow-sm p-4 flex justify-between items-center">
131
+ <div class="flex items-center">
132
+ <button id="sidebar-toggle" class="mr-4 text-gray-600 hover:text-gray-900">
133
+ <i class="fas fa-bars"></i>
134
+ </button>
135
+ <h2 class="text-lg font-semibold">Dashboard</h2>
136
+ </div>
137
+ <div class="flex items-center space-x-4">
138
+ <div class="relative">
139
+ <button class="text-gray-600 hover:text-gray-900">
140
+ <i class="fas fa-bell"></i>
141
+ <span class="absolute top-0 right-0 w-2 h-2 bg-red-500 rounded-full"></span>
142
+ </button>
143
+ </div>
144
+ <button class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">
145
+ <i class="fas fa-sync-alt mr-2"></i> Refresh
146
+ </button>
147
+ </div>
148
+ </header>
149
+
150
+ <!-- Tab Contents -->
151
+ <main class="p-4">
152
+ <!-- Dashboard Tab -->
153
+ <div id="dashboard" class="tab-content active">
154
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
155
+ <div class="bg-white p-4 rounded-lg shadow">
156
+ <div class="flex justify-between">
157
+ <div>
158
+ <p class="text-gray-500">Total Devices</p>
159
+ <h3 class="text-2xl font-bold">24</h3>
160
+ </div>
161
+ <div class="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center">
162
+ <i class="fas fa-microchip text-blue-600"></i>
163
+ </div>
164
+ </div>
165
+ <div class="mt-2 text-sm text-green-600">
166
+ <i class="fas fa-arrow-up mr-1"></i> 5.2% from last week
167
+ </div>
168
+ </div>
169
+ <div class="bg-white p-4 rounded-lg shadow">
170
+ <div class="flex justify-between">
171
+ <div>
172
+ <p class="text-gray-500">Online Devices</p>
173
+ <h3 class="text-2xl font-bold">18</h3>
174
+ </div>
175
+ <div class="w-12 h-12 bg-green-100 rounded-full flex items-center justify-center">
176
+ <i class="fas fa-wifi text-green-600"></i>
177
+ </div>
178
+ </div>
179
+ <div class="mt-2 text-sm text-green-600">
180
+ <i class="fas fa-arrow-up mr-1"></i> 3.1% from last week
181
+ </div>
182
+ </div>
183
+ <div class="bg-white p-4 rounded-lg shadow">
184
+ <div class="flex justify-between">
185
+ <div>
186
+ <p class="text-gray-500">Active Streams</p>
187
+ <h3 class="text-2xl font-bold">12</h3>
188
+ </div>
189
+ <div class="w-12 h-12 bg-purple-100 rounded-full flex items-center justify-center">
190
+ <i class="fas fa-video text-purple-600"></i>
191
+ </div>
192
+ </div>
193
+ <div class="mt-2 text-sm text-red-600">
194
+ <i class="fas fa-arrow-down mr-1"></i> 2.4% from last week
195
+ </div>
196
+ </div>
197
+ <div class="bg-white p-4 rounded-lg shadow">
198
+ <div class="flex justify-between">
199
+ <div>
200
+ <p class="text-gray-500">Latest Firmware</p>
201
+ <h3 class="text-2xl font-bold">v2.4.1</h3>
202
+ </div>
203
+ <div class="w-12 h-12 bg-yellow-100 rounded-full flex items-center justify-center">
204
+ <i class="fas fa-code-branch text-yellow-600"></i>
205
+ </div>
206
+ </div>
207
+ <div class="mt-2 text-sm text-gray-500">
208
+ Released: 2 days ago
209
+ </div>
210
+ </div>
211
+ </div>
212
+
213
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
214
+ <!-- Recent Activity -->
215
+ <div class="bg-white p-4 rounded-lg shadow">
216
+ <div class="flex justify-between items-center mb-4">
217
+ <h3 class="font-semibold">Recent Activity</h3>
218
+ <button class="text-blue-600 text-sm">View All</button>
219
+ </div>
220
+ <div class="space-y-4">
221
+ <div class="flex items-start">
222
+ <div class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center mr-3 mt-1">
223
+ <i class="fas fa-upload text-blue-600 text-xs"></i>
224
+ </div>
225
+ <div>
226
+ <p class="text-sm">Firmware v2.4.1 was uploaded</p>
227
+ <p class="text-xs text-gray-500">2 hours ago</p>
228
+ </div>
229
+ </div>
230
+ <div class="flex items-start">
231
+ <div class="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center mr-3 mt-1">
232
+ <i class="fas fa-sync-alt text-green-600 text-xs"></i>
233
+ </div>
234
+ <div>
235
+ <p class="text-sm">Device ESP32-CAM-15 updated to v2.4.1</p>
236
+ <p class="text-xs text-gray-500">3 hours ago</p>
237
+ </div>
238
+ </div>
239
+ <div class="flex items-start">
240
+ <div class="w-8 h-8 bg-red-100 rounded-full flex items-center justify-center mr-3 mt-1">
241
+ <i class="fas fa-exclamation-triangle text-red-600 text-xs"></i>
242
+ </div>
243
+ <div>
244
+ <p class="text-sm">Device ESP32-CAM-07 went offline</p>
245
+ <p class="text-xs text-gray-500">5 hours ago</p>
246
+ </div>
247
+ </div>
248
+ <div class="flex items-start">
249
+ <div class="w-8 h-8 bg-purple-100 rounded-full flex items-center justify-center mr-3 mt-1">
250
+ <i class="fas fa-video text-purple-600 text-xs"></i>
251
+ </div>
252
+ <div>
253
+ <p class="text-sm">Stream started on ESP32-CAM-12</p>
254
+ <p class="text-xs text-gray-500">7 hours ago</p>
255
+ </div>
256
+ </div>
257
+ </div>
258
+ </div>
259
+
260
+ <!-- Quick Actions -->
261
+ <div class="bg-white p-4 rounded-lg shadow">
262
+ <h3 class="font-semibold mb-4">Quick Actions</h3>
263
+ <div class="grid grid-cols-2 gap-4">
264
+ <button class="bg-blue-100 text-blue-700 p-4 rounded-lg flex flex-col items-center justify-center hover:bg-blue-200 transition">
265
+ <i class="fas fa-file-upload text-2xl mb-2"></i>
266
+ <span class="text-sm">Upload Firmware</span>
267
+ </button>
268
+ <button class="bg-green-100 text-green-700 p-4 rounded-lg flex flex-col items-center justify-center hover:bg-green-200 transition">
269
+ <i class="fas fa-sync-alt text-2xl mb-2"></i>
270
+ <span class="text-sm">Mass Update</span>
271
+ </button>
272
+ <button class="bg-purple-100 text-purple-700 p-4 rounded-lg flex flex-col items-center justify-center hover:bg-purple-200 transition">
273
+ <i class="fas fa-video text-2xl mb-2"></i>
274
+ <span class="text-sm">Start All Streams</span>
275
+ </button>
276
+ <button class="bg-yellow-100 text-yellow-700 p-4 rounded-lg flex flex-col items-center justify-center hover:bg-yellow-200 transition">
277
+ <i class="fas fa-cog text-2xl mb-2"></i>
278
+ <span class="text-sm">Settings</span>
279
+ </button>
280
+ </div>
281
+ </div>
282
+ </div>
283
+ </div>
284
+
285
+ <!-- Devices Tab -->
286
+ <div id="devices" class="tab-content">
287
+ <div class="flex justify-between items-center mb-6">
288
+ <h2 class="text-xl font-semibold">Device Management</h2>
289
+ <div class="flex space-x-2">
290
+ <div class="relative">
291
+ <input type="text" placeholder="Search devices..." class="pl-8 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
292
+ <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
293
+ </div>
294
+ <button class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
295
+ <i class="fas fa-plus mr-2"></i> Add Device
296
+ </button>
297
+ </div>
298
+ </div>
299
+
300
+ <div class="bg-white rounded-lg shadow overflow-hidden">
301
+ <div class="p-4 border-b flex justify-between items-center">
302
+ <div class="flex items-center space-x-4">
303
+ <div class="relative">
304
+ <select class="appearance-none bg-gray-100 border border-gray-300 rounded-lg px-4 py-2 pr-8 focus:outline-none focus:ring-2 focus:ring-blue-500">
305
+ <option>All Status</option>
306
+ <option>Online</option>
307
+ <option>Offline</option>
308
+ </select>
309
+ <i class="fas fa-chevron-down absolute right-3 top-3 text-gray-500 pointer-events-none"></i>
310
+ </div>
311
+ <div class="relative">
312
+ <select class="appearance-none bg-gray-100 border border-gray-300 rounded-lg px-4 py-2 pr-8 focus:outline-none focus:ring-2 focus:ring-blue-500">
313
+ <option>All Firmware</option>
314
+ <option>v2.4.1</option>
315
+ <option>v2.3.0</option>
316
+ <option>v2.2.5</option>
317
+ </select>
318
+ <i class="fas fa-chevron-down absolute right-3 top-3 text-gray-500 pointer-events-none"></i>
319
+ </div>
320
+ </div>
321
+ <div class="flex items-center space-x-2">
322
+ <button class="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg">
323
+ <i class="fas fa-download"></i>
324
+ </button>
325
+ <button class="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg">
326
+ <i class="fas fa-filter"></i>
327
+ </button>
328
+ </div>
329
+ </div>
330
+ <div class="overflow-x-auto">
331
+ <table class="min-w-full divide-y divide-gray-200">
332
+ <thead class="bg-gray-50">
333
+ <tr>
334
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
335
+ <input type="checkbox" class="rounded text-blue-600">
336
+ </th>
337
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Device ID</th>
338
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
339
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
340
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">IP Address</th>
341
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Firmware</th>
342
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Seen</th>
343
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
344
+ </tr>
345
+ </thead>
346
+ <tbody class="bg-white divide-y divide-gray-200">
347
+ <!-- Device Rows -->
348
+ <tr class="hover:bg-gray-50">
349
+ <td class="px-6 py-4 whitespace-nowrap">
350
+ <input type="checkbox" class="rounded text-blue-600">
351
+ </td>
352
+ <td class="px-6 py-4 whitespace-nowrap">
353
+ <div class="text-sm font-medium text-gray-900">ESP32-CAM-01</div>
354
+ </td>
355
+ <td class="px-6 py-4 whitespace-nowrap">
356
+ <div class="text-sm text-gray-900">Front Entrance</div>
357
+ </td>
358
+ <td class="px-6 py-4 whitespace-nowrap">
359
+ <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">
360
+ Online
361
+ </span>
362
+ </td>
363
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">192.168.1.101</td>
364
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">v2.4.1</td>
365
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">2 minutes ago</td>
366
+ <td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
367
+ <button class="text-blue-600 hover:text-blue-900 mr-3"><i class="fas fa-eye"></i></button>
368
+ <button class="text-yellow-600 hover:text-yellow-900 mr-3"><i class="fas fa-edit"></i></button>
369
+ <button class="text-red-600 hover:text-red-900"><i class="fas fa-trash"></i></button>
370
+ </td>
371
+ </tr>
372
+ <!-- More device rows... -->
373
+ </tbody>
374
+ </table>
375
+ </div>
376
+ <div class="bg-gray-50 px-4 py-3 flex items-center justify-between border-t border-gray-200">
377
+ <div class="flex-1 flex justify-between items-center">
378
+ <div>
379
+ <p class="text-sm text-gray-700">
380
+ Showing <span class="font-medium">1</span> to <span class="font-medium">10</span> of <span class="font-medium">24</span> devices
381
+ </p>
382
+ </div>
383
+ <div>
384
+ <nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination">
385
+ <a href="#" class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
386
+ <span class="sr-only">Previous</span>
387
+ <i class="fas fa-chevron-left"></i>
388
+ </a>
389
+ <a href="#" aria-current="page" class="z-10 bg-blue-50 border-blue-500 text-blue-600 relative inline-flex items-center px-4 py-2 border text-sm font-medium">
390
+ 1
391
+ </a>
392
+ <a href="#" class="bg-white border-gray-300 text-gray-500 hover:bg-gray-50 relative inline-flex items-center px-4 py-2 border text-sm font-medium">
393
+ 2
394
+ </a>
395
+ <a href="#" class="bg-white border-gray-300 text-gray-500 hover:bg-gray-50 relative inline-flex items-center px-4 py-2 border text-sm font-medium">
396
+ 3
397
+ </a>
398
+ <a href="#" class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
399
+ <span class="sr-only">Next</span>
400
+ <i class="fas fa-chevron-right"></i>
401
+ </a>
402
+ </nav>
403
+ </div>
404
+ </div>
405
+ </div>
406
+ </div>
407
+ </div>
408
+
409
+ <!-- Streaming Tab -->
410
+ <div id="streaming" class="tab-content">
411
+ <div class="flex justify-between items-center mb-6">
412
+ <h2 class="text-xl font-semibold">Live Streaming</h2>
413
+ <div class="flex space-x-2">
414
+ <button class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition">
415
+ <i class="fas fa-play mr-2"></i> Start All
416
+ </button>
417
+ <button class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 transition">
418
+ <i class="fas fa-stop mr-2"></i> Stop All
419
+ </button>
420
+ </div>
421
+ </div>
422
+
423
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
424
+ <!-- Stream Card -->
425
+ <div class="bg-white rounded-lg shadow overflow-hidden device-card transition">
426
+ <div class="stream-container relative">
427
+ <img src="https://via.placeholder.com/640x360" alt="Camera Stream" class="w-full h-full object-cover">
428
+ <div class="absolute top-2 left-2 bg-black bg-opacity-50 text-white text-xs px-2 py-1 rounded">
429
+ ESP32-CAM-01
430
+ </div>
431
+ <div class="absolute bottom-2 left-2 right-2 flex justify-between items-center">
432
+ <div class="bg-black bg-opacity-50 text-white text-xs px-2 py-1 rounded">
433
+ 1280x720 @ 30fps
434
+ </div>
435
+ <div class="flex space-x-1">
436
+ <button class="bg-black bg-opacity-50 text-white p-1 rounded hover:bg-opacity-70">
437
+ <i class="fas fa-expand text-xs"></i>
438
+ </button>
439
+ <button class="bg-black bg-opacity-50 text-white p-1 rounded hover:bg-opacity-70">
440
+ <i class="fas fa-cog text-xs"></i>
441
+ </button>
442
+ </div>
443
+ </div>
444
+ </div>
445
+ <div class="p-3 flex justify-between items-center">
446
+ <div>
447
+ <h3 class="font-medium">Front Entrance</h3>
448
+ <p class="text-xs text-gray-500">192.168.1.101</p>
449
+ </div>
450
+ <div class="flex space-x-2">
451
+ <button class="text-green-600 hover:text-green-800">
452
+ <i class="fas fa-play"></i>
453
+ </button>
454
+ <button class="text-red-600 hover:text-red-800">
455
+ <i class="fas fa-stop"></i>
456
+ </button>
457
+ <button class="text-blue-600 hover:text-blue-800">
458
+ <i class="fas fa-camera"></i>
459
+ </button>
460
+ </div>
461
+ </div>
462
+ </div>
463
+ <!-- More stream cards... -->
464
+ </div>
465
+ </div>
466
+
467
+ <!-- Firmware Tab -->
468
+ <div id="firmware" class="tab-content">
469
+ <div class="flex justify-between items-center mb-6">
470
+ <h2 class="text-xl font-semibold">Firmware Management</h2>
471
+ <button id="upload-firmware-btn" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
472
+ <i class="fas fa-file-upload mr-2"></i> Upload Firmware
473
+ </button>
474
+ </div>
475
+
476
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
477
+ <!-- Firmware Upload Card -->
478
+ <div class="bg-white p-6 rounded-lg shadow">
479
+ <h3 class="font-semibold mb-4">Upload New Firmware</h3>
480
+ <div class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center">
481
+ <i class="fas fa-file-upload text-4xl text-gray-400 mb-3"></i>
482
+ <p class="text-gray-600 mb-3">Drag & drop your firmware file here</p>
483
+ <p class="text-xs text-gray-500 mb-4">Supports .bin files up to 4MB</p>
484
+ <label for="firmware-file" class="cursor-pointer bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition inline-block">
485
+ Select File
486
+ </label>
487
+ <input type="file" id="firmware-file" class="hidden" accept=".bin">
488
+ </div>
489
+ <div class="mt-4">
490
+ <div class="flex justify-between text-sm mb-1">
491
+ <span>File name:</span>
492
+ <span class="font-medium" id="file-name">No file selected</span>
493
+ </div>
494
+ <div class="flex justify-between text-sm mb-1">
495
+ <span>File size:</span>
496
+ <span class="font-medium" id="file-size">0 MB</span>
497
+ </div>
498
+ <div class="flex justify-between text-sm">
499
+ <span>Version:</span>
500
+ <input type="text" placeholder="e.g. 2.4.1" class="border-b border-gray-300 text-right focus:outline-none focus:border-blue-500 w-20">
501
+ </div>
502
+ </div>
503
+ <button class="w-full mt-4 bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition disabled:opacity-50" disabled id="upload-btn">
504
+ Upload Firmware
505
+ </button>
506
+ </div>
507
+
508
+ <!-- Firmware List -->
509
+ <div class="lg:col-span-2">
510
+ <div class="bg-white rounded-lg shadow overflow-hidden">
511
+ <div class="p-4 border-b">
512
+ <h3 class="font-semibold">Available Firmware Versions</h3>
513
+ </div>
514
+ <div class="divide-y divide-gray-200">
515
+ <!-- Firmware Item -->
516
+ <div class="p-4 hover:bg-gray-50 transition">
517
+ <div class="flex justify-between items-center">
518
+ <div>
519
+ <h4 class="font-medium">v2.4.1</h4>
520
+ <p class="text-sm text-gray-500">Stable release - CCTV improvements</p>
521
+ </div>
522
+ <div class="flex items-center space-x-2">
523
+ <span class="text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">Latest</span>
524
+ <span class="text-xs text-gray-500">2.1 MB</span>
525
+ <button class="text-blue-600 hover:text-blue-800">
526
+ <i class="fas fa-download"></i>
527
+ </button>
528
+ </div>
529
+ </div>
530
+ <div class="mt-2 flex justify-between text-xs text-gray-500">
531
+ <span>Uploaded: 2 days ago</span>
532
+ <span>Used by 12 devices</span>
533
+ </div>
534
+ </div>
535
+ <!-- More firmware items... -->
536
+ </div>
537
+ </div>
538
+
539
+ <!-- Flash Section -->
540
+ <div class="bg-white rounded-lg shadow overflow-hidden mt-6">
541
+ <div class="p-4 border-b">
542
+ <h3 class="font-semibold">Flash Device</h3>
543
+ </div>
544
+ <div class="p-4">
545
+ <div class="mb-4">
546
+ <label class="block text-sm font-medium text-gray-700 mb-2">Select Firmware Version</label>
547
+ <select id="flash-firmware-select" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
548
+ <option>v2.4.1 (Latest)</option>
549
+ <option>v2.3.0</option>
550
+ <option>v2.2.5</option>
551
+ </select>
552
+ </div>
553
+
554
+ <div class="mb-4">
555
+ <label class="block text-sm font-medium text-gray-700 mb-2">Flash Method</label>
556
+ <div class="grid grid-cols-2 gap-2">
557
+ <button id="serial-flash-btn" class="bg-blue-100 text-blue-700 p-3 rounded-lg hover:bg-blue-200 transition flex flex-col items-center">
558
+ <i class="fas fa-usb text-xl mb-1"></i>
559
+ <span class="text-sm">Serial (USB)</span>
560
+ </button>
561
+ <button id="ota-flash-btn" class="bg-green-100 text-green-700 p-3 rounded-lg hover:bg-green-200 transition flex flex-col items-center">
562
+ <i class="fas fa-wifi text-xl mb-1"></i>
563
+ <span class="text-sm">OTA (WiFi)</span>
564
+ </button>
565
+ </div>
566
+ </div>
567
+
568
+ <!-- Serial Flash Console -->
569
+ <div id="serial-flash-console" class="hidden">
570
+ <div class="mb-4">
571
+ <label class="block text-sm font-medium text-gray-700 mb-2">Flash Progress</label>
572
+ <div class="flash-progress">
573
+ <div id="flash-progress-bar" class="flash-progress-bar" style="width: 0%"></div>
574
+ </div>
575
+ <div class="flex justify-between text-xs text-gray-500 mt-1">
576
+ <span id="flash-status">Ready to flash</span>
577
+ <span id="flash-percentage">0%</span>
578
+ </div>
579
+ </div>
580
+
581
+ <div class="mb-4">
582
+ <label class="block text-sm font-medium text-gray-700 mb-2">Console Output</label>
583
+ <div id="console-output" class="console-output">
584
+ <div>> Connect your ESP32 via USB and click "Connect"</div>
585
+ </div>
586
+ </div>
587
+
588
+ <div class="flex justify-between">
589
+ <button id="connect-serial-btn" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
590
+ <i class="fas fa-plug mr-2"></i> Connect
591
+ </button>
592
+ <button id="start-flash-btn" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition disabled:opacity-50" disabled>
593
+ <i class="fas fa-bolt mr-2"></i> Start Flash
594
+ </button>
595
+ <button id="cancel-flash-btn" class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 transition">
596
+ <i class="fas fa-times mr-2"></i> Cancel
597
+ </button>
598
+ </div>
599
+ </div>
600
+
601
+ <!-- OTA Flash Form -->
602
+ <div id="ota-flash-form" class="hidden">
603
+ <div class="mb-4">
604
+ <label class="block text-sm font-medium text-gray-700 mb-2">Device IP Address</label>
605
+ <input type="text" id="ota-ip-address" placeholder="192.168.1.100" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
606
+ </div>
607
+ <div class="mb-4">
608
+ <label class="block text-sm font-medium text-gray-700 mb-2">OTA Port</label>
609
+ <input type="number" id="ota-port" value="3232" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
610
+ </div>
611
+ <div class="mb-4">
612
+ <label class="block text-sm font-medium text-gray-700 mb-2">Password (if required)</label>
613
+ <input type="password" id="ota-password" placeholder="Leave empty if no password" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
614
+ </div>
615
+ <div class="flex justify-end">
616
+ <button id="start-ota-flash-btn" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition">
617
+ <i class="fas fa-bolt mr-2"></i> Start OTA Update
618
+ </button>
619
+ </div>
620
+ </div>
621
+ </div>
622
+ </div>
623
+ </div>
624
+ </div>
625
+ </div>
626
+
627
+ <!-- Settings Tab -->
628
+ <div id="settings" class="tab-content">
629
+ <div class="flex justify-between items-center mb-6">
630
+ <h2 class="text-xl font-semibold">System Settings</h2>
631
+ </div>
632
+
633
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
634
+ <!-- General Settings -->
635
+ <div class="bg-white p-6 rounded-lg shadow">
636
+ <h3 class="font-semibold mb-4">General Settings</h3>
637
+ <div class="space-y-4">
638
+ <div>
639
+ <label class="block text-sm font-medium text-gray-700 mb-1">Admin Panel Theme</label>
640
+ <select class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
641
+ <option>Light</option>
642
+ <option>Dark</option>
643
+ <option>System Preference</option>
644
+ </select>
645
+ </div>
646
+ <div>
647
+ <label class="block text-sm font-medium text-gray-700 mb-1">Stream Quality</label>
648
+ <select class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
649
+ <option>High (1080p)</option>
650
+ <option>Medium (720p)</option>
651
+ <option>Low (480p)</option>
652
+ </select>
653
+ </div>
654
+ <div>
655
+ <label class="block text-sm font-medium text-gray-700 mb-1">Auto Refresh Interval</label>
656
+ <select class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
657
+ <option>30 seconds</option>
658
+ <option>1 minute</option>
659
+ <option>5 minutes</option>
660
+ <option>Disabled</option>
661
+ </select>
662
+ </div>
663
+ <div class="pt-2">
664
+ <button class="w-full bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
665
+ Save Changes
666
+ </button>
667
+ </div>
668
+ </div>
669
+ </div>
670
+
671
+ <!-- Network Settings -->
672
+ <div class="bg-white p-6 rounded-lg shadow">
673
+ <h3 class="font-semibold mb-4">Network Settings</h3>
674
+ <div class="space-y-4">
675
+ <div>
676
+ <label class="block text-sm font-medium text-gray-700 mb-1">Server Port</label>
677
+ <input type="number" value="8080" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
678
+ </div>
679
+ <div>
680
+ <label class="block text-sm font-medium text-gray-700 mb-1">Streaming Protocol</label>
681
+ <select class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
682
+ <option>WebRTC</option>
683
+ <option>MJPEG</option>
684
+ <option>RTSP</option>
685
+ </select>
686
+ </div>
687
+ <div>
688
+ <label class="block text-sm font-medium text-gray-700 mb-1">Enable HTTPS</label>
689
+ <div class="flex items-center">
690
+ <input type="checkbox" id="enable-https" class="mr-2 rounded text-blue-600">
691
+ <label for="enable-https" class="text-sm">Secure connections with SSL/TLS</label>
692
+ </div>
693
+ </div>
694
+ <div class="pt-2">
695
+ <button class="w-full bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">
696
+ Save Changes
697
+ </button>
698
+ </div>
699
+ </div>
700
+ </div>
701
+
702
+ <!-- System Info -->
703
+ <div class="bg-white p-6 rounded-lg shadow">
704
+ <h3 class="font-semibold mb-4">System Information</h3>
705
+ <div class="space-y-3">
706
+ <div class="flex justify-between text-sm">
707
+ <span class="text-gray-600">Admin Panel Version</span>
708
+ <span class="font-medium">v1.2.0</span>
709
+ </div>
710
+ <div class="flex justify-between text-sm">
711
+ <span class="text-gray-600">Last Backup</span>
712
+ <span class="font-medium">2023-06-15 14:30</span>
713
+ </div>
714
+ <div class="flex justify-between text-sm">
715
+ <span class="text-gray-600">Database Size</span>
716
+ <span class="font-medium">24.5 MB</span>
717
+ </div>
718
+ <div class="flex justify-between text-sm">
719
+ <span class="text-gray-600">Uptime</span>
720
+ <span class="font-medium">7 days 3 hours</span>
721
+ </div>
722
+ <div class="pt-4">
723
+ <button class="w-full bg-gray-100 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-200 transition flex items-center justify-center">
724
+ <i class="fas fa-download mr-2"></i> Backup System
725
+ </button>
726
+ </div>
727
+ <div class="pt-2">
728
+ <button class="w-full bg-red-100 text-red-700 px-4 py-2 rounded-lg hover:bg-red-200 transition flex items-center justify-center">
729
+ <i class="fas fa-trash mr-2"></i> Reset System
730
+ </button>
731
+ </div>
732
+ </div>
733
+ </div>
734
+ </div>
735
+ </div>
736
+ </main>
737
+ </div>
738
+ </div>
739
+
740
+ <!-- Firmware Upload Modal -->
741
+ <div id="firmware-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
742
+ <div class="bg-white rounded-lg shadow-xl w-full max-w-md">
743
+ <div class="p-4 border-b">
744
+ <h3 class="text-lg font-semibold">Upload Firmware</h3>
745
+ </div>
746
+ <div class="p-6">
747
+ <div class="mb-4">
748
+ <label class="block text-sm font-medium text-gray-700 mb-2">Firmware Version</label>
749
+ <input type="text" placeholder="e.g. 2.4.1" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
750
+ </div>
751
+ <div class="mb-4">
752
+ <label class="block text-sm font-medium text-gray-700 mb-2">Release Notes</label>
753
+ <textarea class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 h-24" placeholder="What's new in this version..."></textarea>
754
+ </div>
755
+ <div class="mb-4">
756
+ <label class="block text-sm font-medium text-gray-700 mb-2">Firmware File</label>
757
+ <div class="border-2 border-dashed border-gray-300 rounded-lg p-4 text-center">
758
+ <i class="fas fa-file-upload text-3xl text-gray-400 mb-2"></i>
759
+ <p class="text-gray-600 mb-2">Drag & drop your firmware file here</p>
760
+ <label for="modal-firmware-file" class="cursor-pointer bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition inline-block">
761
+ Select File
762
+ </label>
763
+ <input type="file" id="modal-firmware-file" class="hidden" accept=".bin">
764
+ </div>
765
+ </div>
766
+ </div>
767
+ <div class="p-4 border-t flex justify-end space-x-3">
768
+ <button id="cancel-upload" class="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition">Cancel</button>
769
+ <button id="confirm-upload" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition">Upload</button>
770
+ </div>
771
+ </div>
772
+ </div>
773
+
774
+ <!-- Toast Notification -->
775
+ <div id="toast" class="fixed bottom-4 right-4 bg-green-600 text-white px-4 py-2 rounded-lg shadow-lg flex items-center hidden">
776
+ <i class="fas fa-check-circle mr-2"></i>
777
+ <span id="toast-message">Firmware uploaded successfully!</span>
778
+ </div>
779
+
780
+ <script>
781
+ // Tab switching functionality
782
+ document.querySelectorAll('.tab-link').forEach(link => {
783
+ link.addEventListener('click', function(e) {
784
+ e.preventDefault();
785
+
786
+ // Update active tab in sidebar
787
+ document.querySelectorAll('.tab-link').forEach(l => l.classList.remove('active'));
788
+ this.classList.add('active');
789
+
790
+ // Update header title
791
+ const headerTitle = document.querySelector('header h2');
792
+ headerTitle.textContent = this.textContent.trim();
793
+
794
+ // Show corresponding tab content
795
+ const tabId = this.getAttribute('data-tab');
796
+ document.querySelectorAll('.tab-content').forEach(content => {
797
+ content.classList.remove('active');
798
+ });
799
+ document.getElementById(tabId).classList.add('active');
800
+ });
801
+ });
802
+
803
+ // Sidebar toggle for mobile
804
+ document.getElementById('sidebar-toggle').addEventListener('click', function() {
805
+ document.querySelector('.sidebar').classList.toggle('-translate-x-full');
806
+ });
807
+
808
+ // Firmware file selection
809
+ document.getElementById('firmware-file').addEventListener('change', function(e) {
810
+ const file = e.target.files[0];
811
+ if (file) {
812
+ document.getElementById('file-name').textContent = file.name;
813
+ document.getElementById('file-size').textContent = (file.size / (1024 * 1024)).toFixed(2) + ' MB';
814
+ document.getElementById('upload-btn').disabled = false;
815
+ }
816
+ });
817
+
818
+ // Firmware upload modal
819
+ document.getElementById('upload-firmware-btn').addEventListener('click', function() {
820
+ document.getElementById('firmware-modal').classList.remove('hidden');
821
+ });
822
+
823
+ document.getElementById('cancel-upload').addEventListener('click', function() {
824
+ document.getElementById('firmware-modal').classList.add('hidden');
825
+ });
826
+
827
+ document.getElementById('confirm-upload').addEventListener('click', function() {
828
+ // Simulate upload process
829
+ const progressBar = document.createElement('div');
830
+ progressBar.className = 'w-full bg-gray-200 rounded-full h-2.5 mt-2';
831
+ progressBar.innerHTML = '<div class="progress-bar bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div>';
832
+ document.querySelector('#firmware-modal .p-6').appendChild(progressBar);
833
+
834
+ let progress = 0;
835
+ const interval = setInterval(() => {
836
+ progress += 5;
837
+ document.querySelector('.progress-bar').style.width = `${progress}%`;
838
+
839
+ if (progress >= 100) {
840
+ clearInterval(interval);
841
+ document.getElementById('firmware-modal').classList.add('hidden');
842
+ showToast('Firmware uploaded successfully!');
843
+
844
+ // Reset form
845
+ setTimeout(() => {
846
+ progressBar.remove();
847
+ }, 500);
848
+ }
849
+ }, 100);
850
+ });
851
+
852
+ // Show toast notification
853
+ function showToast(message) {
854
+ const toast = document.getElementById('toast');
855
+ document.getElementById('toast-message').textContent = message;
856
+ toast.classList.remove('hidden');
857
+
858
+ setTimeout(() => {
859
+ toast.classList.add('hidden');
860
+ }, 3000);
861
+ }
862
+
863
+ // Simulate device status changes
864
+ setInterval(() => {
865
+ const statuses = document.querySelectorAll('.device-status');
866
+ statuses.forEach(status => {
867
+ if (Math.random() > 0.9) { // 10% chance to change status
868
+ if (status.textContent === 'Online') {
869
+ status.textContent = 'Offline';
870
+ status.classList.remove('bg-green-100', 'text-green-800');
871
+ status.classList.add('bg-red-100', 'text-red-800');
872
+ } else {
873
+ status.textContent = 'Online';
874
+ status.classList.remove('bg-red-100', 'text-red-800');
875
+ status.classList.add('bg-green-100', 'text-green-800');
876
+ }
877
+ }
878
+ });
879
+ }, 5000);
880
+
881
+ // Flash functionality
882
+ let serialPort;
883
+ let firmwareFile;
884
+ let isFlashing = false;
885
+ let flashCanceled = false;
886
+
887
+ // Toggle between serial and OTA flash
888
+ document.getElementById('serial-flash-btn').addEventListener('click', function() {
889
+ document.getElementById('serial-flash-console').classList.remove('hidden');
890
+ document.getElementById('ota-flash-form').classList.add('hidden');
891
+ });
892
+
893
+ document.getElementById('ota-flash-btn').addEventListener('click', function() {
894
+ document.getElementById('serial-flash-console').classList.add('hidden');
895
+ document.getElementById('ota-flash-form').classList.remove('hidden');
896
+ });
897
+
898
+ // Connect to serial port
899
+ document.getElementById('connect-serial-btn').addEventListener('click', async function() {
900
+ if (!('serial' in navigator)) {
901
+ appendConsoleOutput('> Web Serial API not supported in this browser. Use Chrome or Edge.');
902
+ return;
903
+ }
904
+
905
+ try {
906
+ appendConsoleOutput('> Requesting serial port access...');
907
+ serialPort = await navigator.serial.requestPort();
908
+
909
+ appendConsoleOutput('> Opening serial port...');
910
+ await serialPort.open({ baudRate: 115200 });
911
+
912
+ appendConsoleOutput('> Connected to serial port');
913
+ updateFlashStatus('Connected to device', 0);
914
+ document.getElementById('start-flash-btn').disabled = false;
915
+ document.getElementById('connect-serial-btn').disabled = true;
916
+
917
+ // Listen for incoming data
918
+ const reader = serialPort.readable.getReader();
919
+ while (true) {
920
+ const { value, done } = await reader.read();
921
+ if (done) break;
922
+ const text = new TextDecoder().decode(value);
923
+ appendConsoleOutput(text);
924
+ }
925
+
926
+ } catch (error) {
927
+ appendConsoleOutput(`> Error: ${error.message}`);
928
+ }
929
+ });
930
+
931
+ // Start flashing process
932
+ document.getElementById('start-flash-btn').addEventListener('click', async function() {
933
+ if (!serialPort || !serialPort.readable) {
934
+ appendConsoleOutput('> Error: Not connected to a serial port');
935
+ return;
936
+ }
937
+
938
+
939
+ </html>