S-Dreamer commited on
Commit
4eb5d66
·
verified ·
1 Parent(s): d21a748

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +450 -875
index.html CHANGED
@@ -3,937 +3,512 @@
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>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ESP32-CAM Dashboard</title>
 
7
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
  <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
14
  }
15
+
16
+ :root {
17
+ --primary: #3498db;
18
+ --secondary: #2c3e50;
19
+ --success: #27ae60;
20
+ --warning: #f39c12;
21
+ --danger: #e74c3c;
22
+ --dark: #34495e;
23
+ --light: #ecf0f1;
24
+ --gray: #95a5a6;
25
  }
26
+
27
+ body {
28
+ background: linear-gradient(135deg, #1a2a6c, #2c3e50);
29
+ color: var(--light);
30
+ min-height: 100vh;
31
+ padding: 20px;
32
  }
33
+
34
+ .container {
35
+ max-width: 1200px;
36
+ margin: 0 auto;
37
  }
38
+
39
+ header {
40
+ text-align: center;
41
+ padding: 30px 0;
42
+ margin-bottom: 30px;
43
  }
44
+
45
+ header h1 {
46
+ font-size: 2.8rem;
47
+ margin-bottom: 10px;
48
+ background: linear-gradient(to right, #3498db, #2ecc71);
49
+ -webkit-background-clip: text;
50
+ -webkit-text-fill-color: transparent;
51
+ text-shadow: 0 2px 4px rgba(0,0,0,0.1);
52
  }
53
+
54
+ header p {
55
+ font-size: 1.2rem;
56
+ color: var(--light);
57
+ max-width: 800px;
58
+ margin: 0 auto;
59
+ line-height: 1.6;
60
  }
61
+
62
+ .dashboard {
63
+ display: grid;
64
+ grid-template-columns: 1fr 1fr;
65
+ gap: 25px;
66
+ margin-bottom: 30px;
67
  }
68
+
69
+ @media (max-width: 768px) {
70
+ .dashboard {
71
+ grid-template-columns: 1fr;
72
+ }
73
  }
74
+
75
+ .card {
76
+ background: rgba(255, 255, 255, 0.08);
77
+ border-radius: 15px;
78
+ padding: 25px;
79
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
80
+ backdrop-filter: blur(10px);
81
+ border: 1px solid rgba(255, 255, 255, 0.1);
82
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
83
+ }
84
+
85
+ .card:hover {
86
+ transform: translateY(-5px);
87
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
88
+ }
89
+
90
+ .card-header {
91
+ display: flex;
92
+ align-items: center;
93
+ margin-bottom: 20px;
94
+ padding-bottom: 15px;
95
+ border-bottom: 2px solid rgba(255, 255, 255, 0.1);
96
  }
97
+
98
+ .card-header i {
99
+ font-size: 1.8rem;
100
+ margin-right: 15px;
101
+ color: var(--primary);
102
+ }
103
+
104
+ .card-header h2 {
105
+ font-size: 1.5rem;
106
+ font-weight: 600;
107
+ }
108
+
109
+ .camera-feed {
110
+ position: relative;
111
+ width: 100%;
112
+ height: 300px;
113
+ background: #000;
114
+ border-radius: 10px;
115
  overflow: hidden;
116
+ display: flex;
117
+ align-items: center;
118
+ justify-content: center;
119
  }
120
+
121
+ .camera-placeholder {
122
+ text-align: center;
123
+ color: var(--gray);
124
+ }
125
+
126
+ .camera-placeholder i {
127
+ font-size: 4rem;
128
+ margin-bottom: 15px;
129
+ opacity: 0.5;
130
+ }
131
+
132
+ .status-grid {
133
+ display: grid;
134
+ grid-template-columns: repeat(2, 1fr);
135
+ gap: 15px;
136
+ }
137
+
138
+ .status-item {
139
+ background: rgba(255, 255, 255, 0.1);
140
+ padding: 15px;
141
+ border-radius: 10px;
142
+ text-align: center;
143
+ }
144
+
145
+ .status-item h3 {
146
+ font-size: 0.9rem;
147
+ color: var(--gray);
148
+ margin-bottom: 8px;
149
+ }
150
+
151
+ .status-value {
152
+ font-size: 1.4rem;
153
+ font-weight: 600;
154
+ }
155
+
156
+ .connected {
157
+ color: var(--success);
158
+ }
159
+
160
+ .disconnected {
161
+ color: var(--danger);
162
+ }
163
+
164
+ .controls {
165
+ display: flex;
166
+ gap: 15px;
167
+ flex-wrap: wrap;
168
+ }
169
+
170
+ .btn {
171
+ padding: 12px 25px;
172
+ border: none;
173
+ border-radius: 8px;
174
+ font-size: 1rem;
175
+ font-weight: 600;
176
+ cursor: pointer;
177
+ transition: all 0.3s ease;
178
+ display: flex;
179
+ align-items: center;
180
+ gap: 8px;
181
+ }
182
+
183
+ .btn-primary {
184
+ background: var(--primary);
185
+ color: white;
186
+ }
187
+
188
+ .btn-success {
189
+ background: var(--success);
190
+ color: white;
191
+ }
192
+
193
+ .btn-warning {
194
+ background: var(--warning);
195
+ color: white;
196
+ }
197
+
198
+ .btn-danger {
199
+ background: var(--danger);
200
+ color: white;
201
+ }
202
+
203
+ .btn:hover {
204
+ transform: translateY(-2px);
205
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
206
+ }
207
+
208
+ .btn:active {
209
+ transform: translateY(0);
210
+ }
211
+
212
+ .image-history {
213
+ display: grid;
214
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
215
+ gap: 15px;
216
+ margin-top: 20px;
217
+ }
218
+
219
+ .image-item {
220
+ aspect-ratio: 4/3;
221
+ background: rgba(255, 255, 255, 0.1);
222
+ border-radius: 8px;
223
+ overflow: hidden;
224
+ position: relative;
225
+ cursor: pointer;
226
+ transition: transform 0.3s ease;
227
+ }
228
+
229
+ .image-item:hover {
230
+ transform: scale(1.05);
231
+ }
232
+
233
+ .image-placeholder {
234
+ width: 100%;
235
  height: 100%;
236
+ display: flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ color: var(--gray);
240
+ }
241
+
242
+ .image-placeholder i {
243
+ font-size: 2rem;
244
+ }
245
+
246
+ .features {
247
+ margin-top: 40px;
248
+ }
249
+
250
+ .features-grid {
251
+ display: grid;
252
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
253
+ gap: 25px;
254
+ margin-top: 25px;
255
+ }
256
+
257
+ .feature-card {
258
+ background: rgba(255, 255, 255, 0.05);
259
+ padding: 25px;
260
+ border-radius: 15px;
261
+ text-align: center;
262
+ transition: all 0.3s ease;
263
+ }
264
+
265
+ .feature-card:hover {
266
+ background: rgba(255, 255, 255, 0.1);
267
+ transform: translateY(-5px);
268
+ }
269
+
270
+ .feature-icon {
271
+ font-size: 3rem;
272
+ margin-bottom: 20px;
273
+ color: var(--primary);
274
+ }
275
+
276
+ .feature-card h3 {
277
+ font-size: 1.4rem;
278
+ margin-bottom: 15px;
279
+ }
280
+
281
+ .feature-card p {
282
+ color: var(--light);
283
+ line-height: 1.6;
284
+ }
285
+
286
+ footer {
287
+ text-align: center;
288
+ padding: 30px 0;
289
+ margin-top: 40px;
290
+ color: var(--gray);
291
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
292
+ }
293
+
294
+ .device-info {
295
+ display: flex;
296
+ align-items: center;
297
+ gap: 10px;
298
+ margin-top: 15px;
299
+ padding: 12px;
300
+ background: rgba(255, 255, 255, 0.05);
301
+ border-radius: 8px;
302
+ }
303
+
304
+ .device-info i {
305
+ color: var(--success);
306
+ }
307
+
308
+ .notification {
309
+ position: fixed;
310
+ top: 20px;
311
+ right: 20px;
312
+ padding: 15px 25px;
313
+ background: var(--success);
314
+ color: white;
315
+ border-radius: 8px;
316
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
317
+ transform: translateX(200%);
318
+ transition: transform 0.3s ease;
319
+ z-index: 1000;
320
+ }
321
+
322
+ .notification.show {
323
+ transform: translateX(0);
324
+ }
325
+
326
+ .loading {
327
+ display: inline-block;
328
+ width: 20px;
329
+ height: 20px;
330
+ border: 3px solid rgba(255,255,255,.3);
331
+ border-radius: 50%;
332
+ border-top-color: white;
333
+ animation: spin 1s ease-in-out infinite;
334
+ }
335
+
336
+ @keyframes spin {
337
+ to { transform: rotate(360deg); }
338
  }
339
  </style>
340
  </head>
341
+ <body>
342
+ <div class="container">
343
+ <header>
344
+ <h1><i class="fas fa-camera"></i> ESP32-CAM Dashboard</h1>
345
+ <p>A user-friendly web application for monitoring and controlling ESP32-CAM devices through a browser interface</p>
346
+ </header>
347
+
348
+ <div class="dashboard">
349
+ <div class="card">
350
+ <div class="card-header">
351
+ <i class="fas fa-video"></i>
352
+ <h2>Live Camera Feed</h2>
353
+ </div>
354
+ <div class="camera-feed">
355
+ <div class="camera-placeholder">
356
+ <i class="fas fa-video-slash"></i>
357
+ <p>Camera feed not available</p>
358
+ <small>Connect your ESP32-CAM device to view live stream</small>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
  </div>
360
+ </div>
361
+ <div class="device-info">
362
+ <i class="fas fa-check-circle"></i>
363
  <div>
364
+ <div>Device Status: <span class="connected">Connected</span></div>
365
+ <small>ESP32-CAM-001 • 192.168.1.105</small>
366
  </div>
367
  </div>
368
  </div>
 
369
 
370
+ <div class="card">
371
+ <div class="card-header">
372
+ <i class="fas fa-sliders-h"></i>
373
+ <h2>Device Controls</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  </div>
375
+ <div class="status-grid">
376
+ <div class="status-item">
377
+ <h3>CONNECTION</h3>
378
+ <div class="status-value connected">Online</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  </div>
380
+ <div class="status-item">
381
+ <h3>QUALITY</h3>
382
+ <div class="status-value">720p</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
  </div>
384
+ <div class="status-item">
385
+ <h3>FPS</h3>
386
+ <div class="status-value">30</div>
 
 
 
 
 
 
 
 
 
 
 
 
387
  </div>
388
+ <div class="status-item">
389
+ <h3>UPTIME</h3>
390
+ <div class="status-value">2h 15m</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  </div>
392
  </div>
393
+ <div class="controls" style="margin-top: 25px;">
394
+ <button class="btn btn-primary" id="captureBtn">
395
+ <i class="fas fa-camera"></i> Capture Image
396
+ </button>
397
+ <button class="btn btn-success">
398
+ <i class="fas fa-sync-alt"></i> Refresh Feed
399
+ </button>
400
+ <button class="btn btn-warning">
401
+ <i class="fas fa-cog"></i> Settings
402
+ </button>
403
+ </div>
404
+ </div>
405
+ </div>
406
 
407
+ <div class="card">
408
+ <div class="card-header">
409
+ <i class="fas fa-images"></i>
410
+ <h2>Image History</h2>
411
+ </div>
412
+ <div class="image-history">
413
+ <div class="image-item">
414
+ <div class="image-placeholder">
415
+ <i class="fas fa-image"></i>
 
 
 
416
  </div>
417
+ </div>
418
+ <div class="image-item">
419
+ <div class="image-placeholder">
420
+ <i class="fas fa-image"></i>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  </div>
422
  </div>
423
+ <div class="image-item">
424
+ <div class="image-placeholder">
425
+ <i class="fas fa-image"></i>
 
 
 
 
 
426
  </div>
427
+ </div>
428
+ <div class="image-item">
429
+ <div class="image-placeholder">
430
+ <i class="fas fa-image"></i>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
431
  </div>
432
  </div>
433
+ <div class="image-item">
434
+ <div class="image-placeholder">
435
+ <i class="fas fa-image"></i>
 
 
436
  </div>
437
+ </div>
438
+ <div class="image-item">
439
+ <div class="image-placeholder">
440
+ <i class="fas fa-image"></i>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
441
  </div>
442
  </div>
443
+ </div>
444
  </div>
 
445
 
446
+ <div class="features">
447
+ <h2 style="text-align: center; margin-bottom: 30px; font-size: 2rem;">Core Features</h2>
448
+ <div class="features-grid">
449
+ <div class="feature-card">
450
+ <div class="feature-icon">
451
+ <i class="fas fa-video"></i>
452
+ </div>
453
+ <h3>Live Camera Feed</h3>
454
+ <p>View real-time video stream directly from your connected ESP32-CAM devices with minimal latency.</p>
 
455
  </div>
456
+ <div class="feature-card">
457
+ <div class="feature-icon">
458
+ <i class="fas fa-heartbeat"></i>
459
+ </div>
460
+ <h3>Device Status Monitoring</h3>
461
+ <p>Get instant insights into the status of your ESP32-CAM, including connection status and device health.</p>
462
  </div>
463
+ <div class="feature-card">
464
+ <div class="feature-icon">
465
+ <i class="fas fa-camera-retro"></i>
 
 
 
 
 
 
466
  </div>
467
+ <h3>Basic Camera Controls</h3>
468
+ <p>Easily capture still images with a simple click and manage your camera settings remotely.</p>
469
  </div>
470
  </div>
 
 
 
 
471
  </div>
472
+
473
+ <footer>
474
+ <p>ESP32-CAM Dashboard &copy; 2023 | Your Own Private Eyes: A Web Dashboard for ESP32-CAM Devices</p>
475
+ <p style="margin-top: 10px; font-size: 0.9rem;">
476
+ <a href="#" style="color: var(--primary); text-decoration: none;">GitHub Repository</a> |
477
+ <a href="#" style="color: var(--primary); text-decoration: none;">Documentation</a> |
478
+ <a href="#" style="color: var(--primary); text-decoration: none;">Support</a>
479
+ </p>
480
+ </footer>
481
  </div>
482
 
483
+ <div class="notification" id="notification">
484
+ Image captured successfully!
 
 
485
  </div>
486
 
487
  <script>
488
+ document.addEventListener('DOMContentLoaded', function() {
489
+ const captureBtn = document.getElementById('captureBtn');
490
+ const notification = document.getElementById('notification');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
 
492
+ captureBtn.addEventListener('click', function() {
493
+ // Show loading state
494
+ const originalHTML = captureBtn.innerHTML;
495
+ captureBtn.innerHTML = '<div class="loading"></div> Capturing...';
496
+ captureBtn.disabled = true;
497
 
498
+ // Simulate capture process
499
+ setTimeout(function() {
500
+ // Reset button
501
+ captureBtn.innerHTML = originalHTML;
502
+ captureBtn.disabled = false;
503
 
504
+ // Show notification
505
+ notification.classList.add('show');
506
+ setTimeout(function() {
507
+ notification.classList.remove('show');
508
+ }, 3000);
509
+ }, 2000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
510
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
511
  });
512
+ </script>
513
+ </body>
 
 
 
 
 
 
 
514
  </html>