AScythe commited on
Commit
fbcc320
·
verified ·
1 Parent(s): cc9aaeb

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +662 -19
  3. prompts.txt +0 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Geolocator Deepsite
3
- emoji: 🚀
4
- colorFrom: red
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: geolocator-deepsite
3
+ emoji: 🐳
4
+ colorFrom: green
5
+ colorTo: green
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,662 @@
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>GeoLocator - Real-Time Device Tracking</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
9
+ <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
10
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
11
+ <style>
12
+ #map { height: 400px; }
13
+ .notification {
14
+ animation: slideIn 0.5s forwards;
15
+ }
16
+ @keyframes slideIn {
17
+ from { transform: translateY(100%); }
18
+ to { transform: translateY(0); }
19
+ }
20
+ .camera-preview {
21
+ background-color: #000;
22
+ border-radius: 8px;
23
+ overflow: hidden;
24
+ }
25
+ .pulse {
26
+ animation: pulse 2s infinite;
27
+ }
28
+ @keyframes pulse {
29
+ 0% { transform: scale(1); }
30
+ 50% { transform: scale(1.05); }
31
+ 100% { transform: scale(1); }
32
+ }
33
+ .media-metadata {
34
+ background-color: rgba(0, 0, 0, 0.7);
35
+ color: white;
36
+ padding: 8px;
37
+ border-radius: 4px;
38
+ font-size: 12px;
39
+ }
40
+ </style>
41
+ </head>
42
+ <body class="bg-gray-100">
43
+ <div class="container mx-auto px-4 py-6 max-w-4xl">
44
+ <header class="mb-8">
45
+ <div class="flex items-center justify-between">
46
+ <div>
47
+ <h1 class="text-3xl font-bold text-blue-600 flex items-center">
48
+ <i class="fas fa-map-marker-alt mr-2"></i> GeoLocator
49
+ </h1>
50
+ <p class="text-gray-600">Real-time device tracking with GPS</p>
51
+ </div>
52
+ <div class="flex items-center space-x-4">
53
+ <div id="connectionStatus" class="flex items-center">
54
+ <div class="w-3 h-3 rounded-full bg-green-500 mr-2"></div>
55
+ <span class="text-sm">Connected</span>
56
+ </div>
57
+ <div class="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center">
58
+ <i class="fas fa-user text-blue-500 text-xl"></i>
59
+ </div>
60
+ </div>
61
+ </div>
62
+ </header>
63
+
64
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
65
+ <!-- Left Column -->
66
+ <div class="space-y-6">
67
+ <div class="bg-white rounded-xl shadow-md p-4">
68
+ <div class="flex justify-between items-center mb-4">
69
+ <h2 class="text-lg font-semibold flex items-center">
70
+ <i class="fas fa-satellite-dish mr-2 text-blue-500"></i> Tracked Devices
71
+ </h2>
72
+ <div class="flex space-x-2">
73
+ <button id="refreshDevices" class="text-blue-500 hover:text-blue-700">
74
+ <i class="fas fa-sync-alt"></i>
75
+ </button>
76
+ <button id="addDevice" class="text-green-500 hover:text-green-700">
77
+ <i class="fas fa-plus"></i>
78
+ </button>
79
+ </div>
80
+ </div>
81
+
82
+ <div class="space-y-3">
83
+ <div class="device-card bg-blue-50 p-3 rounded-lg flex items-center justify-between pulse" data-device="A">
84
+ <div class="flex items-center">
85
+ <div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3">
86
+ <i class="fas fa-mobile-alt text-blue-500"></i>
87
+ </div>
88
+ <div>
89
+ <h3 class="font-medium">Device A</h3>
90
+ <p class="text-xs text-gray-500">Last update: <span class="time-ago">just now</span></p>
91
+ </div>
92
+ </div>
93
+ <div class="text-right">
94
+ <p class="text-sm font-medium"><span class="distance">1.2</span> km away</p>
95
+ <p class="text-xs text-green-500">Active</p>
96
+ </div>
97
+ </div>
98
+
99
+ <div class="device-card bg-gray-50 p-3 rounded-lg flex items-center justify-between" data-device="B">
100
+ <div class="flex items-center">
101
+ <div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center mr-3">
102
+ <i class="fas fa-car text-gray-500"></i>
103
+ </div>
104
+ <div>
105
+ <h3 class="font-medium">Device B</h3>
106
+ <p class="text-xs text-gray-500">Last update: <span class="time-ago">5 min ago</span></p>
107
+ </div>
108
+ </div>
109
+ <div class="text-right">
110
+ <p class="text-sm font-medium"><span class="distance">3.7</span> km away</p>
111
+ <p class="text-xs text-gray-500">Idle</p>
112
+ </div>
113
+ </div>
114
+
115
+ <div class="device-card bg-gray-50 p-3 rounded-lg flex items-center justify-between" data-device="C">
116
+ <div class="flex items-center">
117
+ <div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center mr-3">
118
+ <i class="fas fa-laptop text-gray-500"></i>
119
+ </div>
120
+ <div>
121
+ <h3 class="font-medium">Device C</h3>
122
+ <p class="text-xs text-gray-500">Last update: <span class="time-ago">1 hour ago</span></p>
123
+ </div>
124
+ </div>
125
+ <div class="text-right">
126
+ <p class="text-sm font-medium"><span class="distance">8.2</span> km away</p>
127
+ <p class="text-xs text-red-500">Offline</p>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ </div>
132
+
133
+ <div class="bg-white rounded-xl shadow-md p-4">
134
+ <h2 class="text-lg font-semibold mb-4 flex items-center">
135
+ <i class="fas fa-camera mr-2 text-blue-500"></i> Location Capture
136
+ </h2>
137
+ <div class="camera-preview mb-4 relative" id="cameraPreview">
138
+ <video id="video" class="w-full" autoplay></video>
139
+ <canvas id="canvas" class="hidden"></canvas>
140
+ <div class="absolute bottom-0 left-0 right-0 bg-black bg-opacity-50 text-white p-2 flex justify-center">
141
+ <button id="captureBtn" class="mx-2 bg-white text-black rounded-full w-12 h-12 flex items-center justify-center hover:bg-gray-100">
142
+ <i class="fas fa-camera"></i>
143
+ </button>
144
+ <button id="switchCameraBtn" class="mx-2 bg-gray-700 text-white rounded-full w-10 h-10 flex items-center justify-center hover:bg-gray-600">
145
+ <i class="fas fa-sync-alt"></i>
146
+ </button>
147
+ </div>
148
+ </div>
149
+
150
+ <div id="capturedMedia" class="hidden">
151
+ <div class="flex justify-between items-center mb-3">
152
+ <h3 class="font-medium">Captured Location</h3>
153
+ <div>
154
+ <button id="retakeBtn" class="text-blue-500 hover:text-blue-700 mr-3">
155
+ <i class="fas fa-redo mr-1"></i> Retake
156
+ </button>
157
+ <button id="deleteBtn" class="text-red-500 hover:text-red-700">
158
+ <i class="fas fa-trash mr-1"></i> Delete
159
+ </button>
160
+ </div>
161
+ </div>
162
+ <div class="relative">
163
+ <img id="capturedImage" class="w-full rounded-lg mb-3" src="" alt="Captured image">
164
+ <div id="mediaMetadata" class="media-metadata absolute bottom-3 left-3">
165
+ <div>Lat: <span id="capturedLat">0.0000</span></div>
166
+ <div>Lng: <span id="capturedLng">0.0000</span></div>
167
+ <div>Time: <span id="capturedTime">00:00:00</span></div>
168
+ </div>
169
+ </div>
170
+ <div class="grid grid-cols-2 gap-2">
171
+ <button id="saveBtn" class="bg-blue-500 hover:bg-blue-600 text-white py-2 rounded-lg flex items-center justify-center">
172
+ <i class="fas fa-save mr-2"></i> Save
173
+ </button>
174
+ <button id="shareBtn" class="bg-green-500 hover:bg-green-600 text-white py-2 rounded-lg flex items-center justify-center">
175
+ <i class="fas fa-share mr-2"></i> Share
176
+ </button>
177
+ <button id="locationBtn" class="bg-purple-500 hover:bg-purple-600 text-white py-2 rounded-lg flex items-center justify-center col-span-2">
178
+ <i class="fas fa-map-marker-alt mr-2"></i> Show on Map
179
+ </button>
180
+ </div>
181
+ </div>
182
+ </div>
183
+ </div>
184
+
185
+ <!-- Right Column -->
186
+ <div class="space-y-6">
187
+ <div class="bg-white rounded-xl shadow-md p-4 h-full">
188
+ <div class="flex justify-between items-center mb-4">
189
+ <h2 class="text-lg font-semibold flex items-center">
190
+ <i class="fas fa-map mr-2 text-blue-500"></i> Live Tracking Map
191
+ </h2>
192
+ <div class="flex space-x-2">
193
+ <button id="zoomInBtn" class="text-blue-500 hover:text-blue-700">
194
+ <i class="fas fa-search-plus"></i>
195
+ </button>
196
+ <button id="zoomOutBtn" class="text-blue-500 hover:text-blue-700">
197
+ <i class="fas fa-search-minus"></i>
198
+ </button>
199
+ <button id="centerMapBtn" class="text-blue-500 hover:text-blue-700">
200
+ <i class="fas fa-crosshairs"></i>
201
+ </button>
202
+ </div>
203
+ </div>
204
+ <div id="map" class="rounded-lg"></div>
205
+ <div class="mt-3 text-sm text-gray-600 flex justify-between">
206
+ <div>
207
+ <span class="font-medium">Your location:</span>
208
+ <span id="userCoords">0.0000, 0.0000</span>
209
+ </div>
210
+ <div>
211
+ <span class="font-medium">Accuracy:</span>
212
+ <span id="accuracy">0</span> meters
213
+ </div>
214
+ </div>
215
+ </div>
216
+
217
+ <div class="bg-white rounded-xl shadow-md p-4">
218
+ <h2 class="text-lg font-semibold mb-4 flex items-center">
219
+ <i class="fas fa-bell mr-2 text-blue-500"></i> Proximity Alerts
220
+ </h2>
221
+ <div class="space-y-2">
222
+ <div class="p-3 bg-yellow-50 rounded-lg">
223
+ <div class="flex items-center">
224
+ <div class="w-8 h-8 rounded-full bg-yellow-100 flex items-center justify-center mr-3">
225
+ <i class="fas fa-exclamation text-yellow-500"></i>
226
+ </div>
227
+ <div>
228
+ <p class="font-medium">Device A is within 50m</p>
229
+ <p class="text-xs text-gray-500">Alert triggered 2 minutes ago</p>
230
+ </div>
231
+ </div>
232
+ </div>
233
+ <div class="p-3 bg-gray-50 rounded-lg">
234
+ <div class="flex items-center">
235
+ <div class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center mr-3">
236
+ <i class="fas fa-check text-gray-500"></i>
237
+ </div>
238
+ <div>
239
+ <p>No alerts for Device B</p>
240
+ <p class="text-xs text-gray-500">Last check: just now</p>
241
+ </div>
242
+ </div>
243
+ </div>
244
+ </div>
245
+ </div>
246
+ </div>
247
+ </div>
248
+
249
+ <div id="notification" class="hidden fixed bottom-4 left-4 right-4 bg-green-500 text-white p-4 rounded-lg shadow-lg notification max-w-md mx-auto">
250
+ <div class="flex items-center">
251
+ <i class="fas fa-bell mr-3 text-xl"></i>
252
+ <div>
253
+ <p class="font-medium" id="notificationMessage">Device A is in vicinity!</p>
254
+ <p class="text-sm">You're within 50m radius</p>
255
+ </div>
256
+ <button id="closeNotification" class="ml-auto">
257
+ <i class="fas fa-times"></i>
258
+ </button>
259
+ </div>
260
+ </div>
261
+ </div>
262
+
263
+ <script>
264
+ // Initialize map
265
+ const map = L.map('map').setView([0, 0], 15);
266
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
267
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
268
+ }).addTo(map);
269
+
270
+ // Real-time location tracking
271
+ let userLocation = null;
272
+ let userMarker = null;
273
+ let userCircle = null;
274
+ let watchId = null;
275
+ const deviceMarkers = {};
276
+ const deviceLocations = {
277
+ 'A': { lat: 0, lng: 0, lastUpdate: new Date(), online: true },
278
+ 'B': { lat: 0, lng: 0, lastUpdate: new Date(), online: true },
279
+ 'C': { lat: 0, lng: 0, lastUpdate: new Date(), online: false }
280
+ };
281
+ let capturedLocation = null;
282
+
283
+ // Start watching user's location
284
+ function startTracking() {
285
+ if (navigator.geolocation) {
286
+ watchId = navigator.geolocation.watchPosition(
287
+ position => {
288
+ const lat = position.coords.latitude;
289
+ const lng = position.coords.longitude;
290
+ userLocation = [lat, lng];
291
+
292
+ // Update coordinates display
293
+ document.getElementById('userCoords').textContent = `${lat.toFixed(4)}, ${lng.toFixed(4)}`;
294
+ document.getElementById('accuracy').textContent = Math.round(position.coords.accuracy);
295
+
296
+ // Update or create marker
297
+ if (!userMarker) {
298
+ userMarker = L.marker(userLocation, {
299
+ icon: L.divIcon({
300
+ html: '<div class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center text-white"><i class="fas fa-user"></i></div>',
301
+ className: 'border-none',
302
+ iconSize: [32, 32]
303
+ })
304
+ }).addTo(map).bindPopup("Your location");
305
+
306
+ userCircle = L.circle(userLocation, {
307
+ color: 'blue',
308
+ fillColor: '#3b82f6',
309
+ fillOpacity: 0.2,
310
+ radius: position.coords.accuracy
311
+ }).addTo(map);
312
+ } else {
313
+ userMarker.setLatLng(userLocation);
314
+ userCircle.setLatLng(userLocation).setRadius(position.coords.accuracy);
315
+ }
316
+
317
+ // Update device distances
318
+ updateDeviceDistances();
319
+
320
+ // Check proximity
321
+ checkProximity();
322
+ },
323
+ error => {
324
+ console.error("Geolocation error:", error);
325
+ document.getElementById('connectionStatus').innerHTML = `
326
+ <div class="flex items-center">
327
+ <div class="w-3 h-3 rounded-full bg-red-500 mr-2"></div>
328
+ <span class="text-sm">Location Error</span>
329
+ </div>
330
+ `;
331
+ },
332
+ {
333
+ enableHighAccuracy: true,
334
+ maximumAge: 10000,
335
+ timeout: 5000
336
+ }
337
+ );
338
+ } else {
339
+ alert("Geolocation is not supported by this browser.");
340
+ }
341
+ }
342
+
343
+ // Simulate device movements (for demo purposes)
344
+ function simulateDeviceMovements() {
345
+ // Device A - moves randomly but stays relatively close
346
+ deviceLocations['A'].lat = userLocation ? userLocation[0] + (Math.random() - 0.5) * 0.01 : 51.505;
347
+ deviceLocations['A'].lng = userLocation ? userLocation[1] + (Math.random() - 0.5) * 0.01 : -0.09;
348
+ deviceLocations['A'].lastUpdate = new Date();
349
+
350
+ // Device B - moves in a larger area
351
+ deviceLocations['B'].lat = userLocation ? userLocation[0] + (Math.random() - 0.5) * 0.03 : 51.51;
352
+ deviceLocations['B'].lng = userLocation ? userLocation[1] + (Math.random() - 0.5) * 0.03 : -0.1;
353
+ deviceLocations['B'].lastUpdate = new Date();
354
+
355
+ // Device C - stays offline (no movement)
356
+
357
+ updateDeviceMarkers();
358
+ updateDeviceCards();
359
+ }
360
+
361
+ // Update device markers on map
362
+ function updateDeviceMarkers() {
363
+ Object.keys(deviceLocations).forEach(device => {
364
+ const deviceData = deviceLocations[device];
365
+ const deviceCoords = [deviceData.lat, deviceData.lng];
366
+
367
+ if (!deviceMarkers[device]) {
368
+ deviceMarkers[device] = L.marker(deviceCoords, {
369
+ icon: L.divIcon({
370
+ html: `<div class="w-8 h-8 rounded-full ${deviceData.online ? 'bg-red-500' : 'bg-gray-500'} flex items-center justify-center text-white">${device}</div>`,
371
+ className: 'border-none',
372
+ iconSize: [32, 32]
373
+ })
374
+ }).addTo(map).bindPopup(`Device ${device}`);
375
+ } else {
376
+ deviceMarkers[device].setLatLng(deviceCoords);
377
+ }
378
+ });
379
+ }
380
+
381
+ // Update device cards with distance and status
382
+ function updateDeviceCards() {
383
+ document.querySelectorAll('.device-card').forEach(card => {
384
+ const device = card.getAttribute('data-device');
385
+ const deviceData = deviceLocations[device];
386
+
387
+ // Update distance
388
+ const distanceElement = card.querySelector('.distance');
389
+ if (userLocation && deviceData.online) {
390
+ const distance = map.distance(userLocation, [deviceData.lat, deviceData.lng]);
391
+ distanceElement.textContent = (distance / 1000).toFixed(1);
392
+ }
393
+
394
+ // Update time ago
395
+ const timeAgoElement = card.querySelector('.time-ago');
396
+ timeAgoElement.textContent = getTimeAgo(deviceData.lastUpdate);
397
+
398
+ // Update status
399
+ const statusElement = card.querySelector('.text-xs');
400
+ if (deviceData.online) {
401
+ statusElement.textContent = distance < 50000 ? 'Active' : 'Idle';
402
+ statusElement.className = 'text-xs ' + (distance < 50000 ? 'text-green-500' : 'text-yellow-500');
403
+ } else {
404
+ statusElement.textContent = 'Offline';
405
+ statusElement.className = 'text-xs text-red-500';
406
+ }
407
+ });
408
+ }
409
+
410
+ // Calculate time ago string
411
+ function getTimeAgo(date) {
412
+ const seconds = Math.floor((new Date() - date) / 1000);
413
+
414
+ if (seconds < 60) return 'just now';
415
+ if (seconds < 120) return '1 min ago';
416
+ if (seconds < 3600) return Math.floor(seconds / 60) + ' min ago';
417
+ if (seconds < 7200) return '1 hour ago';
418
+ if (seconds < 86400) return Math.floor(seconds / 3600) + ' hours ago';
419
+
420
+ const days = Math.floor(seconds / 86400);
421
+ return days === 1 ? '1 day ago' : days + ' days ago';
422
+ }
423
+
424
+ // Update distances for all devices
425
+ function updateDeviceDistances() {
426
+ Object.keys(deviceLocations).forEach(device => {
427
+ const deviceData = deviceLocations[device];
428
+ if (userLocation && deviceData.online) {
429
+ deviceData.distance = map.distance(userLocation, [deviceData.lat, deviceData.lng]);
430
+ }
431
+ });
432
+ updateDeviceCards();
433
+ }
434
+
435
+ // Check if user is within 50m of any device
436
+ function checkProximity() {
437
+ Object.keys(deviceLocations).forEach(device => {
438
+ const deviceData = deviceLocations[device];
439
+ if (userLocation && deviceData.online && deviceData.distance <= 50) {
440
+ showNotification(device);
441
+ playBeep();
442
+ }
443
+ });
444
+ }
445
+
446
+ // Show notification
447
+ function showNotification(device) {
448
+ const notification = document.getElementById('notification');
449
+ document.getElementById('notificationMessage').textContent = `Device ${device} is in vicinity!`;
450
+ notification.classList.remove('hidden');
451
+
452
+ // Auto-hide after 5 seconds
453
+ setTimeout(() => {
454
+ notification.classList.add('hidden');
455
+ }, 5000);
456
+ }
457
+
458
+ // Play beep sound
459
+ function playBeep() {
460
+ const beep = new Audio('data:audio/wav;base64,UklGRl9vT19XQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YU...');
461
+ beep.play().catch(e => console.log('Audio play failed:', e));
462
+ }
463
+
464
+ // Camera functionality
465
+ const video = document.getElementById('video');
466
+ const canvas = document.getElementById('canvas');
467
+ const capturedImage = document.getElementById('capturedImage');
468
+ const cameraPreview = document.getElementById('cameraPreview');
469
+ const capturedMedia = document.getElementById('capturedMedia');
470
+ let currentStream = null;
471
+
472
+ function stopMediaTracks(stream) {
473
+ stream.getTracks().forEach(track => {
474
+ track.stop();
475
+ });
476
+ }
477
+
478
+ function startCamera(facingMode = 'user') {
479
+ if (currentStream) {
480
+ stopMediaTracks(currentStream);
481
+ }
482
+
483
+ const constraints = {
484
+ video: {
485
+ facingMode,
486
+ width: { ideal: 1280 },
487
+ height: { ideal: 720 }
488
+ },
489
+ audio: false
490
+ };
491
+
492
+ navigator.mediaDevices.getUserMedia(constraints)
493
+ .then(stream => {
494
+ currentStream = stream;
495
+ video.srcObject = stream;
496
+ cameraPreview.classList.remove('hidden');
497
+ capturedMedia.classList.add('hidden');
498
+ })
499
+ .catch(err => {
500
+ console.error("Camera error: ", err);
501
+ cameraPreview.innerHTML = '<p class="text-center py-10 text-gray-500">Could not access camera</p>';
502
+ });
503
+ }
504
+
505
+ // Capture photo
506
+ document.getElementById('captureBtn').addEventListener('click', () => {
507
+ if (!userLocation) {
508
+ alert("Please wait for your location to be determined.");
509
+ return;
510
+ }
511
+
512
+ canvas.width = video.videoWidth;
513
+ canvas.height = video.videoHeight;
514
+ canvas.getContext('2d').drawImage(video, 0, 0);
515
+ const imageDataUrl = canvas.toDataURL('image/jpeg');
516
+ capturedImage.src = imageDataUrl;
517
+
518
+ // Store captured location
519
+ capturedLocation = userLocation;
520
+ document.getElementById('capturedLat').textContent = capturedLocation[0].toFixed(4);
521
+ document.getElementById('capturedLng').textContent = capturedLocation[1].toFixed(4);
522
+
523
+ // Set current time
524
+ const now = new Date();
525
+ document.getElementById('capturedTime').textContent =
526
+ `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
527
+
528
+ cameraPreview.classList.add('hidden');
529
+ capturedMedia.classList.remove('hidden');
530
+
531
+ if (currentStream) {
532
+ stopMediaTracks(currentStream);
533
+ }
534
+ });
535
+
536
+ // Retake photo
537
+ document.getElementById('retakeBtn').addEventListener('click', () => {
538
+ startCamera();
539
+ });
540
+
541
+ // Delete photo
542
+ document.getElementById('deleteBtn').addEventListener('click', () => {
543
+ capturedImage.src = '';
544
+ capturedLocation = null;
545
+ startCamera();
546
+ });
547
+
548
+ // Switch camera
549
+ document.getElementById('switchCameraBtn').addEventListener('click', () => {
550
+ if (currentStream) {
551
+ const track = currentStream.getVideoTracks()[0];
552
+ const facingMode = track.getSettings().facingMode === 'user' ? 'environment' : 'user';
553
+ startCamera(facingMode);
554
+ }
555
+ });
556
+
557
+ // Save photo
558
+ document.getElementById('saveBtn').addEventListener('click', () => {
559
+ if (capturedImage.src) {
560
+ const link = document.createElement('a');
561
+ link.href = capturedImage.src;
562
+ link.download = `geolocator_${new Date().toISOString().slice(0, 10)}.jpg`;
563
+ link.click();
564
+ alert('Photo saved with location data!');
565
+ }
566
+ });
567
+
568
+ // Share photo
569
+ document.getElementById('shareBtn').addEventListener('click', () => {
570
+ if (navigator.share) {
571
+ navigator.share({
572
+ title: 'GeoLocator Capture',
573
+ text: `Location: ${capturedLocation[0].toFixed(4)}, ${capturedLocation[1].toFixed(4)}`,
574
+ url: capturedImage.src
575
+ }).catch(err => {
576
+ console.log('Error sharing:', err);
577
+ alert('Sharing failed: ' + err.message);
578
+ });
579
+ } else {
580
+ alert('Web Share API not supported in this browser. You can manually save and share the image.');
581
+ }
582
+ });
583
+
584
+ // Show location on map
585
+ document.getElementById('locationBtn').addEventListener('click', () => {
586
+ if (capturedLocation) {
587
+ map.setView(capturedLocation, 18);
588
+ L.popup()
589
+ .setLatLng(capturedLocation)
590
+ .setContent("Photo capture location")
591
+ .openOn(map);
592
+ }
593
+ });
594
+
595
+ // Device card click handler
596
+ document.querySelectorAll('.device-card').forEach(card => {
597
+ card.addEventListener('click', function() {
598
+ const device = this.getAttribute('data-device');
599
+ const deviceData = deviceLocations[device];
600
+ if (deviceData.online) {
601
+ map.setView([deviceData.lat, deviceData.lng], 15);
602
+ } else {
603
+ alert(`Device ${device} is currently offline`);
604
+ }
605
+ });
606
+ });
607
+
608
+ // Map controls
609
+ document.getElementById('zoomInBtn').addEventListener('click', () => {
610
+ map.zoomIn();
611
+ });
612
+
613
+ document.getElementById('zoomOutBtn').addEventListener('click', () => {
614
+ map.zoomOut();
615
+ });
616
+
617
+ document.getElementById('centerMapBtn').addEventListener('click', () => {
618
+ if (userLocation) {
619
+ map.setView(userLocation, 15);
620
+ }
621
+ });
622
+
623
+ // Refresh devices
624
+ document.getElementById('refreshDevices').addEventListener('click', function() {
625
+ this.classList.add('animate-spin');
626
+ setTimeout(() => {
627
+ this.classList.remove('animate-spin');
628
+ simulateDeviceMovements();
629
+ }, 1000);
630
+ });
631
+
632
+ // Close notification
633
+ document.getElementById('closeNotification').addEventListener('click', () => {
634
+ document.getElementById('notification').classList.add('hidden');
635
+ });
636
+
637
+ // Initialize app
638
+ function initApp() {
639
+ // Start tracking user location
640
+ startTracking();
641
+
642
+ // Initialize camera if supported
643
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
644
+ startCamera();
645
+ } else {
646
+ document.getElementById('cameraPreview').innerHTML = '<p class="text-center py-10 text-gray-500">Camera not supported on this device</p>';
647
+ }
648
+
649
+ // Simulate initial device locations
650
+ setTimeout(() => {
651
+ simulateDeviceMovements();
652
+ }, 1000);
653
+
654
+ // Simulate periodic device updates
655
+ setInterval(simulateDeviceMovements, 5000);
656
+ }
657
+
658
+ // Start the app when page loads
659
+ window.addEventListener('load', initApp);
660
+ </script>
661
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=AScythe/geolocator-deepsite" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
662
+ </html>
prompts.txt ADDED
File without changes