imsubham commited on
Commit
398933b
·
verified ·
1 Parent(s): 45e75df

Initial DeepSite commit

Browse files
Files changed (2) hide show
  1. README.md +9 -6
  2. index.html +846 -19
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Deepsite Project Qdxpm
3
- emoji: 💻
4
- colorFrom: pink
5
- colorTo: purple
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: DeepSite Project
3
+ colorFrom: blue
4
+ colorTo: pink
 
5
  sdk: static
6
+ emoji: 🛠️
7
+ tags:
8
+ - deepsite-v4
9
  ---
10
 
11
+ # DeepSite Project
12
+
13
+ This project has been created with [DeepSite](https://deepsite.hf.co) AI Vibe Coding.
index.html CHANGED
@@ -1,19 +1,846 @@
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, maximum-scale=1.0, user-scalable=no">
6
+ <meta name="theme-color" content="#0f172a">
7
+ <meta name="apple-mobile-web-app-capable" content="yes">
8
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
9
+ <title>SpeedGuard Rewards - Smart Speed Tracking</title>
10
+ <script src="https://cdn.tailwindcss.com"></script>
11
+ <script src="https://unpkg.com/lucide@latest"></script>
12
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
13
+ <style>
14
+ * {
15
+ font-family: 'Inter', sans-serif;
16
+ -webkit-tap-highlight-color: transparent;
17
+ }
18
+
19
+ body {
20
+ background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
21
+ min-height: 100vh;
22
+ }
23
+
24
+ .glass-panel {
25
+ background: rgba(255, 255, 255, 0.05);
26
+ backdrop-filter: blur(10px);
27
+ -webkit-backdrop-filter: blur(10px);
28
+ border: 1px solid rgba(255, 255, 255, 0.1);
29
+ }
30
+
31
+ .speed-gauge {
32
+ background: conic-gradient(from 180deg, #10b981 0deg, #f59e0b 120deg, #ef4444 240deg, #dc2626 360deg);
33
+ border-radius: 50%;
34
+ padding: 8px;
35
+ }
36
+
37
+ .speed-gauge-inner {
38
+ background: #0f172a;
39
+ border-radius: 50%;
40
+ }
41
+
42
+ .pulse-ring {
43
+ animation: pulse-ring 2s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
44
+ }
45
+
46
+ @keyframes pulse-ring {
47
+ 0% { transform: scale(0.8); opacity: 1; }
48
+ 100% { transform: scale(1.4); opacity: 0; }
49
+ }
50
+
51
+ .slide-up {
52
+ animation: slideUp 0.3s ease-out;
53
+ }
54
+
55
+ @keyframes slideUp {
56
+ from { transform: translateY(100%); opacity: 0; }
57
+ to { transform: translateY(0); opacity: 1; }
58
+ }
59
+
60
+ .shake {
61
+ animation: shake 0.5s ease-in-out;
62
+ }
63
+
64
+ @keyframes shake {
65
+ 0%, 100% { transform: translateX(0); }
66
+ 25% { transform: translateX(-10px); }
67
+ 75% { transform: translateX(10px); }
68
+ }
69
+
70
+ .coupon-card {
71
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
72
+ }
73
+
74
+ .fine-alert {
75
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
76
+ }
77
+
78
+ .reward-badge {
79
+ background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
80
+ }
81
+
82
+ /* Hide scrollbar */
83
+ .no-scrollbar::-webkit-scrollbar {
84
+ display: none;
85
+ }
86
+ .no-scrollbar {
87
+ -ms-overflow-style: none;
88
+ scrollbar-width: none;
89
+ }
90
+
91
+ .zone-indicator {
92
+ transition: all 0.3s ease;
93
+ }
94
+
95
+ .tracking-active {
96
+ box-shadow: 0 0 20px rgba(16, 185, 129, 0.5);
97
+ }
98
+ </style>
99
+ </head>
100
+ <body class="text-white overflow-x-hidden">
101
+ <!-- App Container -->
102
+ <div id="app" class="max-w-md mx-auto min-h-screen relative pb-20">
103
+
104
+ <!-- Header -->
105
+ <header class="sticky top-0 z-50 glass-panel px-4 py-3 flex items-center justify-between">
106
+ <div class="flex items-center gap-2">
107
+ <div class="w-10 h-10 bg-gradient-to-br from-emerald-400 to-blue-500 rounded-xl flex items-center justify-center">
108
+ <i data-lucide="gauge" class="w-5 h-5 text-white"></i>
109
+ </div>
110
+ <div>
111
+ <h1 class="font-bold text-lg leading-tight">SpeedGuard</h1>
112
+ <p class="text-xs text-gray-400">Smart Highway Tracker</p>
113
+ </div>
114
+ </div>
115
+ <div class="flex items-center gap-3">
116
+ <div class="text-right">
117
+ <p class="text-xs text-gray-400">Points</p>
118
+ <p class="font-bold text-emerald-400" id="totalPoints">0</p>
119
+ </div>
120
+ <button onclick="showProfile()" class="w-10 h-10 rounded-full bg-gray-700 flex items-center justify-center">
121
+ <i data-lucide="user" class="w-5 h-5"></i>
122
+ </button>
123
+ </div>
124
+ </header>
125
+
126
+ <!-- Main Dashboard -->
127
+ <main class="p-4 space-y-4">
128
+
129
+ <!-- Speedometer Section -->
130
+ <div class="glass-panel rounded-2xl p-6 relative overflow-hidden">
131
+ <div class="absolute top-0 right-0 p-4">
132
+ <span id="zoneBadge" class="px-3 py-1 rounded-full text-xs font-semibold bg-gray-700 text-gray-300 zone-indicator">
133
+ Highway Zone A
134
+ </span>
135
+ </div>
136
+
137
+ <!-- Speed Gauge -->
138
+ <div class="flex flex-col items-center justify-center py-4">
139
+ <div class="relative w-48 h-48">
140
+ <div class="absolute inset-0 speed-gauge"></div>
141
+ <div class="absolute inset-2 speed-gauge-inner flex flex-col items-center justify-center">
142
+ <span id="currentSpeed" class="text-5xl font-bold tabular-nums">0</span>
143
+ <span class="text-gray-400 text-sm mt-1">km/h</span>
144
+ </div>
145
+ <!-- Speed Indicator Needle (visual) -->
146
+ <div id="speedNeedle" class="absolute top-1/2 left-1/2 w-1 h-20 bg-white origin-bottom transform -translate-x-1/2 -translate-y-full rotate-0 transition-transform duration-300" style="transform: translate(-50%, -100%) rotate(-90deg);"></div>
147
+ </div>
148
+ </div>
149
+
150
+ <!-- Speed Limit Display -->
151
+ <div class="flex justify-center items-center gap-4 mt-2">
152
+ <div class="text-center">
153
+ <p class="text-xs text-gray-400 mb-1">Speed Limit</p>
154
+ <div class="flex items-center gap-1 text-2xl font-bold text-white">
155
+ <i data-lucide="alert-circle" class="w-5 h-5 text-amber-400"></i>
156
+ <span id="speedLimit">120</span>
157
+ <span class="text-sm text-gray-400">km/h</span>
158
+ </div>
159
+ </div>
160
+ </div>
161
+
162
+ <!-- Camera Status -->
163
+ <div class="mt-4 flex items-center justify-center gap-2 text-sm">
164
+ <div id="cameraStatus" class="flex items-center gap-2 px-3 py-1 rounded-full bg-emerald-500/20 text-emerald-400">
165
+ <div class="w-2 h-2 bg-emerald-400 rounded-full animate-pulse"></div>
166
+ <span>Camera Connected</span>
167
+ </div>
168
+ </div>
169
+ </div>
170
+
171
+ <!-- Control Buttons -->
172
+ <div class="grid grid-cols-2 gap-3">
173
+ <button id="startTracking" onclick="toggleTracking()" class="glass-panel rounded-xl p-4 flex flex-col items-center gap-2 hover:bg-white/10 transition-all active:scale-95">
174
+ <div id="trackingIcon" class="w-12 h-12 rounded-full bg-emerald-500/20 flex items-center justify-center text-emerald-400">
175
+ <i data-lucide="play" class="w-6 h-6"></i>
176
+ </div>
177
+ <span id="trackingText" class="font-medium">Start Tracking</span>
178
+ </button>
179
+
180
+ <button onclick="showHistory()" class="glass-panel rounded-xl p-4 flex flex-col items-center gap-2 hover:bg-white/10 transition-all active:scale-95">
181
+ <div class="w-12 h-12 rounded-full bg-blue-500/20 flex items-center justify-center text-blue-400">
182
+ <i data-lucide="history" class="w-6 h-6"></i>
183
+ </div>
184
+ <span class="font-medium">History</span>
185
+ </button>
186
+ </div>
187
+
188
+ <!-- Stats Cards -->
189
+ <div class="grid grid-cols-3 gap-3">
190
+ <div class="glass-panel rounded-xl p-3 text-center">
191
+ <i data-lucide="navigation" class="w-5 h-5 mx-auto mb-1 text-blue-400"></i>
192
+ <p class="text-xs text-gray-400">Distance</p>
193
+ <p id="totalDistance" class="font-bold text-sm">0 km</p>
194
+ </div>
195
+ <div class="glass-panel rounded-xl p-3 text-center">
196
+ <i data-lucide="clock" class="w-5 h-6 mx-auto mb-1 text-purple-400"></i>
197
+ <p class="text-xs text-gray-400">Drive Time</p>
198
+ <p id="driveTime" class="font-bold text-sm">00:00</p>
199
+ </div>
200
+ <div class="glass-panel rounded-xl p-3 text-center">
201
+ <i data-lucide="shield-check" class="w-5 h-5 mx-auto mb-1 text-emerald-400"></i>
202
+ <p class="text-xs text-gray-400">Safe Drives</p>
203
+ <p id="safeDrives" class="font-bold text-sm">0</p>
204
+ </div>
205
+ </div>
206
+
207
+ <!-- Rewards Section -->
208
+ <div>
209
+ <div class="flex items-center justify-between mb-3">
210
+ <h2 class="font-semibold text-lg">Your Rewards 🎁</h2>
211
+ <button onclick="showAllCoupons()" class="text-sm text-emerald-400">View All</button>
212
+ </div>
213
+
214
+ <div id="couponsList" class="space-y-3">
215
+ <!-- Coupons will be dynamically inserted here -->
216
+ </div>
217
+ </div>
218
+
219
+ <!-- Recent Alerts -->
220
+ <div>
221
+ <h2 class="font-semibold text-lg mb-3">Recent Alerts</h2>
222
+ <div id="alertsList" class="space-y-2 max-h-40 overflow-y-auto no-scrollbar">
223
+ <div class="glass-panel rounded-lg p-3 text-center text-gray-400 text-sm">
224
+ No alerts yet. Start driving to receive alerts.
225
+ </div>
226
+ </div>
227
+ </div>
228
+ </main>
229
+
230
+ <!-- Bottom Navigation -->
231
+ <nav class="fixed bottom-0 left-0 right-0 glass-panel border-t border-white/10 px-6 py-3 max-w-md mx-auto">
232
+ <div class="flex justify-around items-center">
233
+ <button onclick="showDashboard()" class="flex flex-col items-center gap-1 text-emerald-400">
234
+ <i data-lucide="home" class="w-6 h-6"></i>
235
+ <span class="text-xs">Home</span>
236
+ </button>
237
+ <button onclick="showRewards()" class="flex flex-col items-center gap-1 text-gray-400 hover:text-white transition-colors">
238
+ <i data-lucide="gift" class="w-6 h-6"></i>
239
+ <span class="text-xs">Rewards</span>
240
+ </button>
241
+ <button onclick="showFines()" class="flex flex-col items-center gap-1 text-gray-400 hover:text-white transition-colors">
242
+ <i data-lucide="receipt" class="w-6 h-6"></i>
243
+ <span class="text-xs">Fines</span>
244
+ </button>
245
+ <button onclick="showSettings()" class="flex flex-col items-center gap-1 text-gray-400 hover:text-white transition-colors">
246
+ <i data-lucide="settings" class="w-6 h-6"></i>
247
+ <span class="text-xs">Settings</span>
248
+ </button>
249
+ </div>
250
+ </nav>
251
+
252
+ <!-- Overspeeding Alert Modal -->
253
+ <div id="overspeedModal" class="hidden fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4">
254
+ <div class="glass-panel rounded-2xl p-6 w-full max-w-sm slide-up">
255
+ <div class="flex items-center gap-3 mb-4">
256
+ <div class="w-12 h-12 rounded-full bg-red-500/20 flex items-center justify-center animate-pulse">
257
+ <i data-lucide="alert-triangle" class="w-6 h-6 text-red-500"></i>
258
+ </div>
259
+ <div>
260
+ <h3 class="font-bold text-lg text-red-400">SPEEDING ALERT!</h3>
261
+ <p class="text-sm text-gray-400">Camera detected violation</p>
262
+ </div>
263
+ </div>
264
+
265
+ <div class="bg-red-500/10 rounded-xl p-4 mb-4">
266
+ <div class="flex justify-between items-center mb-2">
267
+ <span class="text-gray-400">Your Speed</span>
268
+ <span id="violationSpeed" class="text-2xl font-bold text-red-400">135 km/h</span>
269
+ </div>
270
+ <div class="flex justify-between items-center mb-2">
271
+ <span class="text-gray-400">Speed Limit</span>
272
+ <span id="violationLimit" class="font-semibold">120 km/h</span>
273
+ </div>
274
+ <div class="flex justify-between items-center pt-2 border-t border-white/10">
275
+ <span class="text-gray-400">Excess</span>
276
+ <span id="excessSpeed" class="font-bold text-red-400">+15 km/h</span>
277
+ </div>
278
+ </div>
279
+
280
+ <div class="fine-alert rounded-xl p-4 mb-4 text-center">
281
+ <p class="text-sm mb-1">Fine Amount</p>
282
+ <p id="fineAmount" class="text-3xl font-bold">$50.00</p>
283
+ </div>
284
+
285
+ <button onclick="acknowledgeFine()" class="w-full bg-red-500 hover:bg-red-600 text-white font-semibold py-3 rounded-xl transition-colors">
286
+ Acknowledge & Pay
287
+ </button>
288
+ </div>
289
+ </div>
290
+
291
+ <!-- Reward Earned Modal -->
292
+ <div id="rewardModal" class="hidden fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4">
293
+ <div class="glass-panel rounded-2xl p-6 w-full max-w-sm slide-up text-center">
294
+ <div class="w-20 h-20 mx-auto mb-4 reward-badge rounded-full flex items-center justify-center animate-bounce">
295
+ <i data-lucide="trophy" class="w-10 h-10 text-white"></i>
296
+ </div>
297
+
298
+ <h3 class="font-bold text-2xl mb-2">Reward Earned! 🎉</h3>
299
+ <p class="text-gray-400 mb-4">Great job maintaining safe speed!</p>
300
+
301
+ <div class="coupon-card rounded-xl p-4 mb-4">
302
+ <div class="flex items-center justify-between mb-2">
303
+ <span class="text-xs bg-white/20 px-2 py-1 rounded">COUPON</span>
304
+ <span id="rewardPoints" class="text-2xl font-bold">+50 pts</span>
305
+ </div>
306
+ <p id="rewardTitle" class="font-semibold text-lg">Fuel Discount</p>
307
+ <p id="rewardDesc" class="text-sm text-white/80">10% off at Shell Gas Stations</p>
308
+ </div>
309
+
310
+ <button onclick="closeReward()" class="w-full bg-gradient-to-r from-emerald-500 to-blue-500 hover:opacity-90 text-white font-semibold py-3 rounded-xl transition-opacity">
311
+ Awesome!
312
+ </button>
313
+ </div>
314
+ </div>
315
+
316
+ <!-- Pages (Hidden by default) -->
317
+
318
+ <!-- History Page -->
319
+ <div id="historyPage" class="hidden fixed inset-0 z-40 bg-gray-900 pt-16 pb-20 overflow-y-auto">
320
+ <div class="p-4">
321
+ <div class="flex items-center gap-3 mb-6">
322
+ <button onclick="showDashboard()" class="w-10 h-10 rounded-full glass-panel flex items-center justify-center">
323
+ <i data-lucide="arrow-left" class="w-5 h-5"></i>
324
+ </button>
325
+ <h2 class="font-bold text-xl">Trip History</h2>
326
+ </div>
327
+ <div id="historyList" class="space-y-3">
328
+ <!-- History items -->
329
+ </div>
330
+ </div>
331
+ </div>
332
+
333
+ <!-- All Coupons Page -->
334
+ <div id="couponsPage" class="hidden fixed inset-0 z-40 bg-gray-900 pt-16 pb-20 overflow-y-auto">
335
+ <div class="p-4">
336
+ <div class="flex items-center gap-3 mb-6">
337
+ <button onclick="showDashboard()" class="w-10 h-10 rounded-full glass-panel flex items-center justify-center">
338
+ <i data-lucide="arrow-left" class="w-5 h-5"></i>
339
+ </button>
340
+ <h2 class="font-bold text-xl">All Rewards</h2>
341
+ </div>
342
+ <div id="allCouponsList" class="grid grid-cols-2 gap-3">
343
+ <!-- All coupons -->
344
+ </div>
345
+ </div>
346
+ </div>
347
+
348
+ </div>
349
+
350
+ <script>
351
+ // Initialize Lucide icons
352
+ lucide.createIcons();
353
+
354
+ // App State
355
+ const state = {
356
+ isTracking: false,
357
+ currentSpeed: 0,
358
+ speedLimit: 120,
359
+ totalPoints: parseInt(localStorage.getItem('totalPoints')) || 0,
360
+ totalDistance: parseFloat(localStorage.getItem('totalDistance')) || 0,
361
+ safeDrives: parseInt(localStorage.getItem('safeDrives')) || 0,
362
+ driveTime: parseInt(localStorage.getItem('driveTime')) || 0,
363
+ fines: JSON.parse(localStorage.getItem('fines')) || [],
364
+ trips: JSON.parse(localStorage.getItem('trips')) || [],
365
+ coupons: JSON.parse(localStorage.getItem('coupons')) || [
366
+ { id: 1, title: 'Fuel Discount', desc: '10% off at Shell', points: 50, claimed: false, icon: 'fuel' },
367
+ { id: 2, title: 'Coffee Free', desc: 'Free coffee at Starbucks', points: 100, claimed: false, icon: 'coffee' },
368
+ { id: 3, title: 'Car Wash', desc: '50% off premium wash', points: 75, claimed: false, icon: 'droplets' },
369
+ { id: 4, title: 'Parking', desc: '2 hours free parking', points: 30, claimed: false, icon: 'parking-circle' }
370
+ ],
371
+ currentZone: 'Highway Zone A',
372
+ watchId: null,
373
+ startTime: null,
374
+ lastPosition: null,
375
+ consecutiveSafeChecks: 0
376
+ };
377
+
378
+ // Speed Zones (Simulated camera zones)
379
+ const speedZones = [
380
+ { name: 'Highway Zone A', limit: 120, lat: 0, lng: 0, radius: 5000 },
381
+ { name: 'Urban Zone B', limit: 80, lat: 0, lng: 0, radius: 3000 },
382
+ { name: 'School Zone C', limit: 40, lat: 0, lng: 0, radius: 1000 },
383
+ { name: 'Highway Zone D', limit: 100, lat: 0, lng: 0, radius: 4000 }
384
+ ];
385
+
386
+ // Initialize
387
+ function init() {
388
+ updateUI();
389
+ renderCoupons();
390
+ renderHistory();
391
+ }
392
+
393
+ // Update UI
394
+ function updateUI() {
395
+ document.getElementById('totalPoints').textContent = state.totalPoints;
396
+ document.getElementById('totalDistance').textContent = state.totalDistance.toFixed(1) + ' km';
397
+ document.getElementById('safeDrives').textContent = state.safeDrives;
398
+
399
+ const minutes = Math.floor(state.driveTime / 60);
400
+ const hours = Math.floor(minutes / 60);
401
+ const mins = minutes % 60;
402
+ document.getElementById('driveTime').textContent =
403
+ hours > 0 ? `${hours}:${mins.toString().padStart(2, '0')}` : `00:${mins.toString().padStart(2, '0')}`;
404
+ }
405
+
406
+ // Toggle Tracking
407
+ function toggleTracking() {
408
+ if (!state.isTracking) {
409
+ startTracking();
410
+ } else {
411
+ stopTracking();
412
+ }
413
+ }
414
+
415
+ function startTracking() {
416
+ if (!navigator.geolocation) {
417
+ alert('Geolocation is not supported by your device');
418
+ return;
419
+ }
420
+
421
+ state.isTracking = true;
422
+ state.startTime = Date.now();
423
+
424
+ // Update UI
425
+ document.getElementById('trackingIcon').className = 'w-12 h-12 rounded-full bg-red-500/20 flex items-center justify-center text-red-400 tracking-active';
426
+ document.getElementById('trackingText').textContent = 'Stop Tracking';
427
+ document.getElementById('trackingIcon').innerHTML = '<i data-lucide="square" class="w-6 h-6"></i>';
428
+ lucide.createIcons();
429
+
430
+ // Start GPS tracking
431
+ state.watchId = navigator.geolocation.watchPosition(
432
+ handlePosition,
433
+ handleError,
434
+ {
435
+ enableHighAccuracy: true,
436
+ maximumAge: 1000,
437
+ timeout: 5000
438
+ }
439
+ );
440
+
441
+ // Simulate zone changes and speed variations for demo
442
+ simulateDriving();
443
+
444
+ addAlert('Tracking started - Camera connected', 'success');
445
+ }
446
+
447
+ function stopTracking() {
448
+ state.isTracking = false;
449
+
450
+ if (state.watchId) {
451
+ navigator.geolocation.clearWatch(state.watchId);
452
+ }
453
+
454
+ // Calculate trip stats
455
+ if (state.startTime) {
456
+ const tripDuration = Math.floor((Date.now() - state.startTime) / 60000);
457
+ state.driveTime += tripDuration;
458
+
459
+ const trip = {
460
+ date: new Date().toISOString(),
461
+ duration: tripDuration,
462
+ distance: (state.currentSpeed * tripDuration / 60).toFixed(1),
463
+ maxSpeed: state.currentSpeed,
464
+ status: 'completed'
465
+ };
466
+ state.trips.push(trip);
467
+ localStorage.setItem('trips', JSON.stringify(state.trips));
468
+ }
469
+
470
+ // Update UI
471
+ document.getElementById('trackingIcon').className = 'w-12 h-12 rounded-full bg-emerald-500/20 flex items-center justify-center text-emerald-400';
472
+ document.getElementById('trackingText').textContent = 'Start Tracking';
473
+ document.getElementById('trackingIcon').innerHTML = '<i data-lucide="play" class="w-6 h-6"></i>';
474
+ document.getElementById('currentSpeed').textContent = '0';
475
+ document.getElementById('speedNeedle').style.transform = 'translate(-50%, -100%) rotate(-90deg)';
476
+ lucide.createIcons();
477
+
478
+ clearInterval(state.simulationInterval);
479
+
480
+ localStorage.setItem('driveTime', state.driveTime);
481
+ updateUI();
482
+ renderHistory();
483
+
484
+ addAlert('Tracking stopped - Trip saved', 'info');
485
+ }
486
+
487
+ function handlePosition(position) {
488
+ const speed = position.coords.speed || 0;
489
+ const speedKmh = Math.round(speed * 3.6);
490
+
491
+ updateSpeed(speedKmh);
492
+
493
+ // Calculate distance
494
+ if (state.lastPosition) {
495
+ const distance = calculateDistance(
496
+ state.lastPosition.coords.latitude,
497
+ state.lastPosition.coords.longitude,
498
+ position.coords.latitude,
499
+ position.coords.longitude
500
+ );
501
+ state.totalDistance += distance;
502
+ localStorage.setItem('totalDistance', state.totalDistance);
503
+ }
504
+
505
+ state.lastPosition = position;
506
+ updateUI();
507
+ }
508
+
509
+ function handleError(error) {
510
+ console.error('GPS Error:', error);
511
+ addAlert('GPS signal weak - Using simulated data', 'warning');
512
+ }
513
+
514
+ // Calculate distance between coordinates
515
+ function calculateDistance(lat1, lon1, lat2, lon2) {
516
+ const R = 6371; // Earth's radius in km
517
+ const dLat = (lat2 - lat1) * Math.PI / 180;
518
+ const dLon = (lon2 - lon1) * Math.PI / 180;
519
+ const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
520
+ Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
521
+ Math.sin(dLon/2) * Math.sin(dLon/2);
522
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
523
+ return R * c;
524
+ }
525
+
526
+ // Simulate driving for demo purposes
527
+ function simulateDriving() {
528
+ let baseSpeed = 90;
529
+ let zoneIndex = 0;
530
+
531
+ state.simulationInterval = setInterval(() => {
532
+ // Vary speed
533
+ const variation = Math.random() * 20 - 10;
534
+ let newSpeed = Math.max(0, baseSpeed + variation);
535
+
536
+ // Occasionally speed up for demo
537
+ if (Math.random() > 0.8) {
538
+ newSpeed += 30;
539
+ }
540
+
541
+ newSpeed = Math.round(newSpeed);
542
+ updateSpeed(newSpeed);
543
+
544
+ // Change zones periodically
545
+ if (Math.random() > 0.95) {
546
+ zoneIndex = (zoneIndex + 1) % speedZones.length;
547
+ changeZone(speedZones[zoneIndex]);
548
+ }
549
+
550
+ // Update distance
551
+ state.totalDistance += (newSpeed / 3600); // km per second
552
+ localStorage.setItem('totalDistance', state.totalDistance);
553
+ updateUI();
554
+
555
+ }, 1000);
556
+ }
557
+
558
+ function updateSpeed(speed) {
559
+ state.currentSpeed = speed;
560
+ document.getElementById('currentSpeed').textContent = speed;
561
+
562
+ // Update needle rotation (-90 to 270 degrees)
563
+ const maxSpeed = 200;
564
+ const rotation = -90 + (speed / maxSpeed) * 360;
565
+ document.getElementById('speedNeedle').style.transform = `translate(-50%, -100%) rotate(${rotation}deg)`;
566
+
567
+ // Check speed limit
568
+ checkSpeedLimit(speed);
569
+ }
570
+
571
+ function changeZone(zone) {
572
+ state.currentZone = zone.name;
573
+ state.speedLimit = zone.limit;
574
+
575
+ document.getElementById('zoneBadge').textContent = zone.name;
576
+ document.getElementById('speedLimit').textContent = zone.limit;
577
+
578
+ // Visual feedback
579
+ document.getElementById('zoneBadge').classList.add('scale-110');
580
+ setTimeout(() => {
581
+ document.getElementById('zoneBadge').classList.remove('scale-110');
582
+ }, 300);
583
+
584
+ addAlert(`Entered ${zone.name} - Limit: ${zone.limit} km/h`, 'info');
585
+ }
586
+
587
+ function checkSpeedLimit(speed) {
588
+ const excess = speed - state.speedLimit;
589
+
590
+ if (excess > 5) {
591
+ // Overspeeding - Issue fine
592
+ issueFine(speed, excess);
593
+ state.consecutiveSafeChecks = 0;
594
+ } else if (speed < state.speedLimit && speed > 20) {
595
+ // Safe driving - Accumulate points
596
+ state.consecutiveSafeChecks++;
597
+
598
+ if (state.consecutiveSafeChecks >= 30) { // 30 seconds of safe driving
599
+ issueReward();
600
+ state.consecutiveSafeChecks = 0;
601
+ state.safeDrives++;
602
+ localStorage.setItem('safeDrives', state.safeDrives);
603
+ }
604
+ }
605
+ }
606
+
607
+ function issueFine(speed, excess) {
608
+ const fineAmount = excess > 30 ? 200 : excess > 20 ? 100 : 50;
609
+
610
+ const fine = {
611
+ id: Date.now(),
612
+ date: new Date().toISOString(),
613
+ speed: speed,
614
+ limit: state.speedLimit,
615
+ excess: excess,
616
+ amount: fineAmount,
617
+ zone: state.currentZone,
618
+ paid: false
619
+ };
620
+
621
+ state.fines.push(fine);
622
+ localStorage.setItem('fines', JSON.stringify(state.fines));
623
+
624
+ // Show modal
625
+ document.getElementById('violationSpeed').textContent = speed + ' km/h';
626
+ document.getElementById('violationLimit').textContent = state.speedLimit + ' km/h';
627
+ document.getElementById('excessSpeed').textContent = '+' + excess + ' km/h';
628
+ document.getElementById('fineAmount').textContent = '$' + fineAmount + '.00';
629
+ document.getElementById('overspeedModal').classList.remove('hidden');
630
+
631
+ // Add alert
632
+ addAlert(`FINE ISSUED: $${fineAmount} for speeding in ${state.currentZone}`, 'error');
633
+
634
+ // Haptic feedback if available
635
+ if (navigator.vibrate) {
636
+ navigator.vibrate([200, 100, 200]);
637
+ }
638
+ }
639
+
640
+ function acknowledgeFine() {
641
+ document.getElementById('overspeedModal').classList.add('hidden');
642
+ addAlert('Fine acknowledged. Drive safely!', 'warning');
643
+ }
644
+
645
+ function issueReward() {
646
+ const points = Math.floor(Math.random() * 30) + 20;
647
+ state.totalPoints += points;
648
+ localStorage.setItem('totalPoints', state.totalPoints);
649
+
650
+ // Pick random reward
651
+ const rewards = [
652
+ { title: 'Fuel Discount', desc: '10% off at Shell Gas Stations', points: points },
653
+ { title: 'Free Coffee', desc: 'Complimentary coffee at Starbucks', points: points },
654
+ { title: 'Car Wash', desc: 'Premium wash 50% off', points: points },
655
+ { title: 'Parking Credit', desc: '2 hours free parking', points: points }
656
+ ];
657
+ const reward = rewards[Math.floor(Math.random() * rewards.length)];
658
+
659
+ // Show modal
660
+ document.getElementById('rewardPoints').textContent = '+' + points + ' pts';
661
+ document.getElementById('rewardTitle').textContent = reward.title;
662
+ document.getElementById('rewardDesc').textContent = reward.desc;
663
+ document.getElementById('rewardModal').classList.remove('hidden');
664
+
665
+ addAlert(`REWARD EARNED: ${points} points for safe driving!`, 'success');
666
+ updateUI();
667
+ renderCoupons();
668
+ }
669
+
670
+ function closeReward() {
671
+ document.getElementById('rewardModal').classList.add('hidden');
672
+ }
673
+
674
+ function addAlert(message, type) {
675
+ const alertsList = document.getElementById('alertsList');
676
+ const alertDiv = document.createElement('div');
677
+
678
+ let bgClass = 'glass-panel';
679
+ let icon = 'info';
680
+
681
+ if (type === 'error') {
682
+ bgClass = 'bg-red-500/20 border border-red-500/30';
683
+ icon = 'alert-triangle';
684
+ } else if (type === 'success') {
685
+ bgClass = 'bg-emerald-500/20 border border-emerald-500/30';
686
+ icon = 'check-circle';
687
+ } else if (type === 'warning') {
688
+ bgClass = 'bg-amber-500/20 border border-amber-500/30';
689
+ icon = 'alert-circle';
690
+ }
691
+
692
+ alertDiv.className = `${bgClass} rounded-lg p-3 flex items-center gap-3 slide-up`;
693
+ alertDiv.innerHTML = `
694
+ <i data-lucide="${icon}" class="w-5 h-5 ${type === 'error' ? 'text-red-400' : type === 'success' ? 'text-emerald-400' : 'text-amber-400'}"></i>
695
+ <p class="text-sm flex-1">${message}</p>
696
+ <span class="text-xs text-gray-400">${new Date().toLocaleTimeString()}</span>
697
+ `;
698
+
699
+ // Remove "no alerts" message
700
+ if (alertsList.children.length === 1 && alertsList.children[0].textContent.includes('No alerts')) {
701
+ alertsList.innerHTML = '';
702
+ }
703
+
704
+ alertsList.insertBefore(alertDiv, alertsList.firstChild);
705
+ lucide.createIcons();
706
+
707
+ // Keep only last 10 alerts
708
+ while (alertsList.children.length > 10) {
709
+ alertsList.removeChild(alertsList.lastChild);
710
+ }
711
+ }
712
+
713
+ function renderCoupons() {
714
+ const container = document.getElementById('couponsList');
715
+ const availableCoupons = state.coupons.filter(c => !c.claimed && c.points <= state.totalPoints);
716
+
717
+ if (availableCoupons.length === 0) {
718
+ container.innerHTML = `
719
+ <div class="glass-panel rounded-xl p-4 text-center">
720
+ <p class="text-gray-400 text-sm">Keep driving safely to earn more rewards!</p>
721
+ <p class="text-emerald-400 text-xs mt-1">Next reward at ${Math.ceil(state.totalPoints / 50) * 50} points</p>
722
+ </div>
723
+ `;
724
+ return;
725
+ }
726
+
727
+ container.innerHTML = availableCoupons.slice(0, 2).map(coupon => `
728
+ <div class="coupon-card rounded-xl p-4 relative overflow-hidden">
729
+ <div class="absolute top-0 right-0 -mt-2 -mr-2 w-16 h-16 bg-white/20 rounded-full blur-xl"></div>
730
+ <div class="flex items-start justify-between relative z-10">
731
+ <div class="flex items-center gap-3">
732
+ <div class="w-10 h-10 rounded-lg bg-white/20 flex items-center justify-center">
733
+ <i data-lucide="${coupon.icon}" class="w-5 h-5"></i>
734
+ </div>
735
+ <div>
736
+ <h4 class="font-semibold">${coupon.title}</h4>
737
+ <p class="text-xs text-white/80">${coupon.desc}</p>
738
+ </div>
739
+ </div>
740
+ <div class="text-right">
741
+ <span class="text-xs bg-white/20 px-2 py-1 rounded">${coupon.points} pts</span>
742
+ </div>
743
+ </div>
744
+ <button onclick="claimCoupon(${coupon.id})" class="mt-3 w-full bg-white text-purple-600 font-semibold py-2 rounded-lg text-sm hover:bg-gray-100 transition-colors">
745
+ Claim Reward
746
+ </button>
747
+ </div>
748
+ `).join('');
749
+
750
+ lucide.createIcons();
751
+ }
752
+
753
+ function claimCoupon(id) {
754
+ const coupon = state.coupons.find(c => c.id === id);
755
+ if (coupon && state.totalPoints >= coupon.points) {
756
+ state.totalPoints -= coupon.points;
757
+ coupon.claimed = true;
758
+ localStorage.setItem('totalPoints', state.totalPoints);
759
+ localStorage.setItem('coupons', JSON.stringify(state.coupons));
760
+ updateUI();
761
+ renderCoupons();
762
+ addAlert(`Coupon claimed: ${coupon.title}!`, 'success');
763
+ }
764
+ }
765
+
766
+ function renderHistory() {
767
+ const container = document.getElementById('historyList');
768
+
769
+ if (state.trips.length === 0) {
770
+ container.innerHTML = '<p class="text-center text-gray-400 py-8">No trips recorded yet</p>';
771
+ return;
772
+ }
773
+
774
+ container.innerHTML = state.trips.slice().reverse().map(trip => `
775
+ <div class="glass-panel rounded-xl p-4">
776
+ <div class="flex items-center justify-between mb-2">
777
+ <span class="text-sm font-medium">${new Date(trip.date).toLocaleDateString()}</span>
778
+ <span class="text-xs px-2 py-1 rounded-full ${trip.status === 'completed' ? 'bg-emerald-500/20 text-emerald-400' : 'bg-amber-500/20 text-amber-400'}">
779
+ ${trip.status}
780
+ </span>
781
+ </div>
782
+ <div class="flex items-center justify-between text-sm text-gray-400">
783
+ <span><i data-lucide="clock" class="w-4 h-4 inline mr-1"></i> ${trip.duration} min</span>
784
+ <span><i data-lucide="navigation" class="w-4 h-4 inline mr-1"></i> ${trip.distance} km</span>
785
+ <span><i data-lucide="gauge" class="w-4 h-4 inline mr-1"></i> ${trip.maxSpeed} km/h</span>
786
+ </div>
787
+ </div>
788
+ `).join('');
789
+
790
+ lucide.createIcons();
791
+ }
792
+
793
+ // Navigation functions
794
+ function showDashboard() {
795
+ document.getElementById('historyPage').classList.add('hidden');
796
+ document.getElementById('couponsPage').classList.add('hidden');
797
+ }
798
+
799
+ function showHistory() {
800
+ document.getElementById('historyPage').classList.remove('hidden');
801
+ }
802
+
803
+ function showAllCoupons() {
804
+ const container = document.getElementById('allCouponsList');
805
+ container.innerHTML = state.coupons.map(coupon => `
806
+ <div class="glass-panel rounded-xl p-3 ${coupon.claimed ? 'opacity-50' : ''}">
807
+ <div class="w-10 h-10 rounded-lg bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center mb-2">
808
+ <i data-lucide="${coupon.icon}" class="w-5 h-5"></i>
809
+ </div>
810
+ <h4 class="font-semibold text-sm">${coupon.title}</h4>
811
+ <p class="text-xs text-gray-400 mb-2">${coupon.desc}</p>
812
+ <div class="flex items-center justify-between">
813
+ <span class="text-xs text-emerald-400">${coupon.points} pts</span>
814
+ ${coupon.claimed ?
815
+ '<span class="text-xs bg-gray-700 px-2 py-1 rounded">Claimed</span>' :
816
+ `<button onclick="claimCoupon(${coupon.id})" class="text-xs bg-emerald-500 px-2 py-1 rounded text-white" ${state.totalPoints < coupon.points ? 'disabled class="opacity-50"' : ''}>Claim</button>`
817
+ }
818
+ </div>
819
+ </div>
820
+ `).join('');
821
+ lucide.createIcons();
822
+ document.getElementById('couponsPage').classList.remove('hidden');
823
+ }
824
+
825
+ function showRewards() {
826
+ showAllCoupons();
827
+ }
828
+
829
+ function showFines() {
830
+ alert(`You have ${state.fines.length} fines totaling $${state.fines.reduce((a, b) => a + b.amount, 0)}. Feature coming soon!`);
831
+ }
832
+
833
+ function showSettings() {
834
+ alert('Settings: GPS Accuracy, Alert Sounds, Notifications - Coming soon!');
835
+ }
836
+
837
+ function showProfile() {
838
+ alert(`Profile Stats:\nTotal Points: ${state.totalPoints}\nSafe Drives: ${state.safeDrives}\nTotal Distance: ${state.totalDistance.toFixed(1)} km\nFines: ${state.fines.length}`);
839
+ }
840
+
841
+ // Initialize app
842
+ init();
843
+ </script>
844
+ <script src="https://deepsite.hf.co/deepsite-badge.js"></script>
845
+ </body>
846
+ </html>