Superwolff commited on
Commit
1e92f15
·
verified ·
1 Parent(s): 93cb8b5

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +728 -19
index.html CHANGED
@@ -1,19 +1,728 @@
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>Secure Password Manager</title>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"></script>
8
+ <style>
9
+ :root {
10
+ --primary-color: #6366f1;
11
+ --primary-hover: #4f46e5;
12
+ --bg-color: #0f172a;
13
+ --card-bg: #1e293b;
14
+ --text-main: #f1f5f9;
15
+ --text-muted: #94a3b8;
16
+ --success: #10b981;
17
+ --danger: #ef4444;
18
+ --border-radius: 12px;
19
+ --transition: all 0.3s ease;
20
+ }
21
+
22
+ * {
23
+ box-sizing: border-box;
24
+ margin: 0;
25
+ padding: 0;
26
+ }
27
+
28
+ body {
29
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
30
+ background-color: var(--bg-color);
31
+ color: var(--text-main);
32
+ line-height: 1.6;
33
+ min-height: 100vh;
34
+ display: flex;
35
+ flex-direction: column;
36
+ }
37
+
38
+ /* Header */
39
+ header {
40
+ background-color: var(--card-bg);
41
+ padding: 1rem 2rem;
42
+ border-bottom: 1px solid #334155;
43
+ display: flex;
44
+ justify-content: space-between;
45
+ align-items: center;
46
+ }
47
+
48
+ .brand {
49
+ display: flex;
50
+ align-items: center;
51
+ gap: 10px;
52
+ font-size: 1.5rem;
53
+ font-weight: 700;
54
+ color: var(--text-main);
55
+ }
56
+
57
+ .brand i {
58
+ color: var(--primary-color);
59
+ }
60
+
61
+ .brand span {
62
+ color: var(--primary-color);
63
+ font-weight: 300;
64
+ }
65
+
66
+ .anycoder-link {
67
+ font-size: 0.85rem;
68
+ color: var(--text-muted);
69
+ text-decoration: none;
70
+ border: 1px solid var(--text-muted);
71
+ padding: 5px 10px;
72
+ border-radius: 6px;
73
+ transition: var(--transition);
74
+ }
75
+
76
+ .anycoder-link:hover {
77
+ border-color: var(--primary-color);
78
+ color: var(--primary-color);
79
+ box-shadow: 0 0 10px rgba(99, 102, 241, 0.3);
80
+ }
81
+
82
+ /* Main Layout */
83
+ main {
84
+ flex: 1;
85
+ padding: 2rem;
86
+ max-width: 1200px;
87
+ margin: 0 auto;
88
+ width: 100%;
89
+ }
90
+
91
+ .dashboard-header {
92
+ display: flex;
93
+ justify-content: space-between;
94
+ align-items: center;
95
+ margin-bottom: 2rem;
96
+ }
97
+
98
+ h1 {
99
+ font-size: 2rem;
100
+ font-weight: 600;
101
+ }
102
+
103
+ .btn-primary {
104
+ background-color: var(--primary-color);
105
+ color: white;
106
+ border: none;
107
+ padding: 10px 20px;
108
+ border-radius: var(--border-radius);
109
+ cursor: pointer;
110
+ font-size: 1rem;
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 10px;
114
+ transition: var(--transition);
115
+ }
116
+
117
+ .btn-primary:hover {
118
+ background-color: var(--primary-hover);
119
+ transform: translateY(-1px);
120
+ }
121
+
122
+ /* Stats Grid */
123
+ .stats-grid {
124
+ display: grid;
125
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
126
+ gap: 1.5rem;
127
+ margin-bottom: 2rem;
128
+ }
129
+
130
+ .stat-card {
131
+ background-color: var(--card-bg);
132
+ padding: 1.5rem;
133
+ border-radius: var(--border-radius);
134
+ border: 1px solid #334155;
135
+ }
136
+
137
+ .stat-label {
138
+ color: var(--text-muted);
139
+ font-size: 0.9rem;
140
+ margin-bottom: 0.5rem;
141
+ }
142
+
143
+ .stat-value {
144
+ font-size: 2.5rem;
145
+ font-weight: 700;
146
+ color: var(--text-main);
147
+ }
148
+
149
+ /* Password Grid */
150
+ .password-grid {
151
+ display: grid;
152
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
153
+ gap: 1.5rem;
154
+ }
155
+
156
+ .password-card {
157
+ background-color: var(--card-bg);
158
+ border-radius: var(--border-radius);
159
+ padding: 1.5rem;
160
+ border: 1px solid #334155;
161
+ transition: var(--transition);
162
+ position: relative;
163
+ overflow: hidden;
164
+ }
165
+
166
+ .password-card:hover {
167
+ transform: translateY(-5px);
168
+ box-shadow: 0 10px 20px rgba(0,0,0,0.3);
169
+ border-color: var(--primary-color);
170
+ }
171
+
172
+ .card-header {
173
+ display: flex;
174
+ justify-content: space-between;
175
+ align-items: center;
176
+ margin-bottom: 1rem;
177
+ }
178
+
179
+ .site-name {
180
+ font-size: 1.25rem;
181
+ font-weight: 600;
182
+ display: flex;
183
+ align-items: center;
184
+ gap: 10px;
185
+ }
186
+
187
+ .site-icon {
188
+ width: 32px;
189
+ height: 32px;
190
+ background-color: rgba(99, 102, 241, 0.2);
191
+ color: var(--primary-color);
192
+ display: flex;
193
+ align-items: center;
194
+ justify-content: center;
195
+ border-radius: 8px;
196
+ }
197
+
198
+ .card-actions {
199
+ display: flex;
200
+ gap: 10px;
201
+ }
202
+
203
+ .btn-icon {
204
+ background: none;
205
+ border: none;
206
+ color: var(--text-muted);
207
+ cursor: pointer;
208
+ padding: 5px;
209
+ border-radius: 6px;
210
+ transition: var(--transition);
211
+ font-size: 0.9rem;
212
+ }
213
+
214
+ .btn-icon:hover {
215
+ color: var(--primary-color);
216
+ background-color: rgba(99, 102, 241, 0.1);
217
+ }
218
+
219
+ .btn-delete:hover {
220
+ color: var(--danger);
221
+ background-color: rgba(239, 68, 68, 0.1);
222
+ }
223
+
224
+ .credential-row {
225
+ margin-bottom: 1rem;
226
+ }
227
+
228
+ .label {
229
+ font-size: 0.75rem;
230
+ text-transform: uppercase;
231
+ letter-spacing: 1px;
232
+ color: var(--text-muted);
233
+ margin-bottom: 4px;
234
+ display: block;
235
+ }
236
+
237
+ .input-group {
238
+ display: flex;
239
+ gap: 10px;
240
+ }
241
+
242
+ input[type="text"], input[type="password"] {
243
+ flex: 1;
244
+ background-color: #0f172a;
245
+ border: 1px solid #334155;
246
+ color: var(--text-main);
247
+ padding: 10px;
248
+ border-radius: 6px;
249
+ font-family: inherit;
250
+ }
251
+
252
+ input:focus {
253
+ outline: none;
254
+ border-color: var(--primary-color);
255
+ }
256
+
257
+ .toggle-password {
258
+ background-color: #334155;
259
+ border: none;
260
+ color: var(--text-muted);
261
+ padding: 0 12px;
262
+ border-radius: 6px;
263
+ cursor: pointer;
264
+ transition: var(--transition);
265
+ }
266
+
267
+ .toggle-password:hover {
268
+ color: var(--text-main);
269
+ background-color: #475569;
270
+ }
271
+
272
+ .btn-copy {
273
+ background-color: var(--primary-color);
274
+ color: white;
275
+ border: none;
276
+ padding: 0 15px;
277
+ border-radius: 6px;
278
+ cursor: pointer;
279
+ font-size: 0.85rem;
280
+ transition: var(--transition);
281
+ }
282
+
283
+ .btn-copy:hover {
284
+ background-color: var(--primary-hover);
285
+ }
286
+
287
+ /* Modal */
288
+ .modal {
289
+ display: none;
290
+ position: fixed;
291
+ top: 0;
292
+ left: 0;
293
+ width: 100%;
294
+ height: 100%;
295
+ background-color: rgba(0, 0, 0, 0.7);
296
+ backdrop-filter: blur(4px);
297
+ z-index: 100;
298
+ justify-content: center;
299
+ align-items: center;
300
+ animation: fadeIn 0.3s ease;
301
+ }
302
+
303
+ .modal-content {
304
+ background-color: var(--card-bg);
305
+ padding: 2rem;
306
+ border-radius: var(--border-radius);
307
+ width: 90%;
308
+ max-width: 500px;
309
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.5);
310
+ animation: slideUp 0.3s ease;
311
+ }
312
+
313
+ .modal-header {
314
+ display: flex;
315
+ justify-content: space-between;
316
+ margin-bottom: 2rem;
317
+ }
318
+
319
+ .close-btn {
320
+ background: none;
321
+ border: none;
322
+ font-size: 1.5rem;
323
+ color: var(--text-muted);
324
+ cursor: pointer;
325
+ }
326
+
327
+ .form-group {
328
+ margin-bottom: 1.5rem;
329
+ }
330
+
331
+ .form-group label {
332
+ display: block;
333
+ margin-bottom: 0.5rem;
334
+ color: var(--text-muted);
335
+ }
336
+
337
+ .form-group input {
338
+ width: 100%;
339
+ padding: 10px;
340
+ border-radius: 6px;
341
+ border: 1px solid #334155;
342
+ background-color: #0f172a;
343
+ color: white;
344
+ }
345
+
346
+ .modal-footer {
347
+ display: flex;
348
+ justify-content: flex-end;
349
+ gap: 1rem;
350
+ margin-top: 2rem;
351
+ }
352
+
353
+ .btn-secondary {
354
+ background-color: transparent;
355
+ border: 1px solid #334155;
356
+ color: var(--text-main);
357
+ padding: 10px 20px;
358
+ border-radius: var(--border-radius);
359
+ cursor: pointer;
360
+ }
361
+
362
+ .btn-secondary:hover {
363
+ border-color: var(--text-muted);
364
+ }
365
+
366
+ /* Toast Notification */
367
+ .toast {
368
+ position: fixed;
369
+ bottom: 2rem;
370
+ right: 2rem;
371
+ background-color: var(--success);
372
+ color: white;
373
+ padding: 1rem 2rem;
374
+ border-radius: var(--border-radius);
375
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
376
+ display: flex;
377
+ align-items: center;
378
+ gap: 10px;
379
+ transform: translateY(100px);
380
+ transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
381
+ z-index: 200;
382
+ }
383
+
384
+ .toast.show {
385
+ transform: translateY(0);
386
+ }
387
+
388
+ @keyframes fadeIn {
389
+ from { opacity: 0; }
390
+ to { opacity: 1; }
391
+ }
392
+
393
+ @keyframes slideUp {
394
+ from { transform: translateY(20px); opacity: 0; }
395
+ to { transform: translateY(0); opacity: 1; }
396
+ }
397
+
398
+ /* Responsive */
399
+ @media (max-width: 768px) {
400
+ .password-grid {
401
+ grid-template-columns: 1fr;
402
+ }
403
+
404
+ header {
405
+ flex-direction: column;
406
+ gap: 1rem;
407
+ text-align: center;
408
+ }
409
+ }
410
+ </style>
411
+ </head>
412
+ <body>
413
+
414
+ <header>
415
+ <div class="brand">
416
+ <i class="fa-solid fa-lock"></i>
417
+ Secure<span>Vault</span>
418
+ </div>
419
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
420
+ Built with anycoder
421
+ </a>
422
+ </header>
423
+
424
+ <main>
425
+ <div class="dashboard-header">
426
+ <h1>My Credentials</h1>
427
+ <button class="btn-primary" onclick="openModal()">
428
+ <i class="fa-solid fa-plus"></i> Add Account
429
+ </button>
430
+ </div>
431
+
432
+ <div class="stats-grid">
433
+ <div class="stat-card">
434
+ <div class="stat-label">Total Passwords</div>
435
+ <div class="stat-value" id="total-count">0</div>
436
+ </div>
437
+ <div class="stat-card">
438
+ <div class="stat-label">Weak Passwords</div>
439
+ <div class="stat-value" id="weak-count" style="color: var(--danger)">0</div>
440
+ </div>
441
+ <div class="stat-card">
442
+ <div class="stat-label">Last Updated</div>
443
+ <div class="stat-value" id="last-updated">-</div>
444
+ </div>
445
+ </div>
446
+
447
+ <div class="password-grid" id="password-container">
448
+ <!-- Password cards will be injected here via JS -->
449
+ </div>
450
+
451
+ <div style="text-align: center; margin-top: 4rem; color: var(--text-muted);">
452
+ <p><i class="fa-solid fa-circle-check"></i> All data is stored locally in your browser. No data leaves your device.</p>
453
+ </div>
454
+ </main>
455
+
456
+ <!-- Add Account Modal -->
457
+ <div class="modal" id="addModal">
458
+ <div class="modal-content">
459
+ <div class="modal-header">
460
+ <h2>Add New Credential</h2>
461
+ <button class="close-btn" onclick="closeModal()">&times;</button>
462
+ </div>
463
+ <form id="addForm">
464
+ <div class="form-group">
465
+ <label for="siteName">Website / Service Name</label>
466
+ <input type="text" id="siteName" placeholder="e.g. Gmail, iCloud, Netflix" required>
467
+ </div>
468
+ <div class="form-group">
469
+ <label for="username">Username / Email</label>
470
+ <input type="text" id="username" placeholder="e.g. user@example.com" required>
471
+ </div>
472
+ <div class="form-group">
473
+ <label for="password">Password</label>
474
+ <div class="input-group">
475
+ <input type="password" id="password" placeholder="Enter password" required>
476
+ <button type="button" class="toggle-password" onclick="togglePasswordVisibility('password')">
477
+ <i class="fa-solid fa-eye"></i>
478
+ </button>
479
+ </div>
480
+ </div>
481
+ <div class="form-group">
482
+ <label for="category">Category</label>
483
+ <select id="category" style="width: 100%; padding: 10px; border-radius: 6px; border: 1px solid #334155; background-color: #0f172a; color: white;">
484
+ <option value="email">Email</option>
485
+ <option value="social">Social Media</option>
486
+ <option value="finance">Finance</option>
487
+ <option value="other">Other</option>
488
+ </select>
489
+ </div>
490
+ <div class="modal-footer">
491
+ <button type="button" class="btn-secondary" onclick="closeModal()">Cancel</button>
492
+ <button type="submit" class="btn-primary">Save Credential</button>
493
+ </div>
494
+ </form>
495
+ </div>
496
+ </div>
497
+
498
+ <!-- Toast Notification -->
499
+ <div class="toast" id="toast">
500
+ <i class="fa-solid fa-check-circle"></i>
501
+ <span id="toastMessage">Password copied to clipboard!</span>
502
+ </div>
503
+
504
+ <script>
505
+ // Mock Data - In a real app, this would be encrypted localStorage or IndexedDB
506
+ let passwords = [
507
+ { id: 1, site: 'iCloud', username: 'user@example.com', password: 'icloud_secure_pass_123', category: 'email' },
508
+ { id: 2, site: 'Gmail', username: 'john.doe@gmail.com', password: 'super_secret_email_pass', category: 'email' },
509
+ { id: 3, site: 'Netflix', username: 'john.doe@gmail.com', password: 'netflix_stream_2023', category: 'other' },
510
+ { id: 4, site: 'Bank Portal', username: 'client_88291', password: 'weak', category: 'finance' }
511
+ ];
512
+
513
+ // DOM Elements
514
+ const container = document.getElementById('password-container');
515
+ const totalDisplay = document.getElementById('total-count');
516
+ const weakDisplay = document.getElementById('weak-count');
517
+ const lastUpdatedDisplay = document.getElementById('last-updated');
518
+ const modal = document.getElementById('addModal');
519
+ const form = document.getElementById('addForm');
520
+
521
+ // Initialize
522
+ document.addEventListener('DOMContentLoaded', () => {
523
+ renderPasswords();
524
+ lastUpdatedDisplay.textContent = new Date().toLocaleDateString();
525
+ });
526
+
527
+ // Render Function
528
+ function renderPasswords() {
529
+ container.innerHTML = '';
530
+
531
+ if (passwords.length === 0) {
532
+ container.innerHTML = `
533
+ <div style="grid-column: 1/-1; text-align: center; padding: 3rem; background: #1e293b; border-radius: var(--border-radius); border: 2px dashed #334155;">
534
+ <i class="fa-solid fa-lock-open" style="font-size: 3rem; color: var(--text-muted); margin-bottom: 1rem;"></i>
535
+ <h3>Nosaved credentials</h3>
536
+ <p style="color: var(--text-muted);">Click "Add Account" to securely store your first login.</p>
537
+ </div>`;
538
+ totalDisplay.textContent = 0;
539
+ weakDisplay.textContent = 0;
540
+ return;
541
+ }
542
+
543
+ let weakCount = 0;
544
+
545
+ passwords.forEach(item => {
546
+ // Check for weak passwords (simple logic for demo)
547
+ if (item.password.length < 8 || item.password.toLowerCase() === item.password || item.password === 'weak') {
548
+ weakCount++;
549
+ }
550
+
551
+ const card = document.createElement('div');
552
+ card.className = 'password-card';
553
+
554
+ // Determine icon based on category
555
+ let iconClass = 'fa-globe';
556
+ if (item.category === 'email') iconClass = 'fa-envelope';
557
+ if (item.category === 'finance') iconClass = 'fa-credit-card';
558
+ if (item.category === 'social') iconClass = 'fa-users';
559
+
560
+ card.innerHTML = `
561
+ <div class="card-header">
562
+ <div class="site-name">
563
+ <div class="site-icon">
564
+ <i class="fa-solid ${iconClass}"></i>
565
+ </div>
566
+ ${escapeHtml(item.site)}
567
+ </div>
568
+ <div class="card-actions">
569
+ <button class="btn-icon" onclick="editPassword(${item.id})" title="Edit">
570
+ <i class="fa-solid fa-pen-to-square"></i>
571
+ </button>
572
+ <button class="btn-icon btn-delete" onclick="deletePassword(${item.id})" title="Delete">
573
+ <i class="fa-solid fa-trash"></i>
574
+ </button>
575
+ </div>
576
+ </div>
577
+ <div class="credential-row">
578
+ <span class="label">Username / Email</span>
579
+ <div class="input-group">
580
+ <input type="text" value="${escapeHtml(item.username)}" readonly>
581
+ <button class="btn-copy" onclick="copyToClipboard('${escapeHtml(item.username)}', this)">
582
+ <i class="fa-solid fa-copy"></i> Copy
583
+ </button>
584
+ </div>
585
+ </div>
586
+ <div class="credential-row">
587
+ <span class="label">Password</span>
588
+ <div class="input-group">
589
+ <input type="password" id="pass-${item.id}" value="${item.password}" readonly>
590
+ <button class="toggle-password" onclick="togglePasswordVisibility('pass-${item.id}')">
591
+ <i class="fa-solid fa-eye" id="icon-${item.id}"></i>
592
+ </button>
593
+ <button class="btn-copy" onclick="copyToClipboard('${item.password}', this)">
594
+ <i class="fa-solid fa-copy"></i> Copy
595
+ </button>
596
+ </div>
597
+ ${item.password.length < 8 ? '<span style="color: var(--danger); font-size: 0.75rem; margin-top: 5px; display:block;"><i class="fa-solid fa-triangle-exclamation"></i> Weak Password</span>' : ''}
598
+ </div>
599
+ `;
600
+ container.appendChild(card);
601
+ });
602
+
603
+ totalDisplay.textContent = passwords.length;
604
+ weakDisplay.textContent = weakCount;
605
+ }
606
+
607
+ // Helper: Escape HTML to prevent XSS
608
+ function escapeHtml(unsafe) {
609
+ return unsafe
610
+ .replace(/&/g, "&amp;")
611
+ .replace(/</g, "&lt;")
612
+ .replace(/>/g, "&gt;")
613
+ .replace(/"/g, "&quot;")
614
+ .replace(/'/g, "&#039;");
615
+ }
616
+
617
+ // Toggle Password Visibility
618
+ function togglePasswordVisibility(inputId) {
619
+ const input = document.getElementById(inputId);
620
+ const icon = document.getElementById(inputId.replace('pass-', 'icon-'));
621
+
622
+ if (input.type === 'password') {
623
+ input.type = 'text';
624
+ icon.classList.remove('fa-eye');
625
+ icon.classList.add('fa-eye-slash');
626
+ } else {
627
+ input.type = 'password';
628
+ icon.classList.remove('fa-eye-slash');
629
+ icon.classList.add('fa-eye');
630
+ }
631
+ }
632
+
633
+ // Copy to Clipboard
634
+ function copyToClipboard(text, btnElement) {
635
+ navigator.clipboard.writeText(text).then(() => {
636
+ showToast('Copied to clipboard!');
637
+
638
+ // Visual feedback on button
639
+ const originalHtml = btnElement.innerHTML;
640
+ btnElement.innerHTML = '<i class="fa-solid fa-check"></i> Copied';
641
+ setTimeout(() => {
642
+ btnElement.innerHTML = originalHtml;
643
+ }, 2000);
644
+ }).catch(err => {
645
+ showToast('Failed to copy');
646
+ });
647
+ }
648
+
649
+ // Add New Password
650
+ form.addEventListener('submit', (e) => {
651
+ e.preventDefault();
652
+
653
+ const site = document.getElementById('siteName').value;
654
+ const username = document.getElementById('username').value;
655
+ const password = document.getElementById('password').value;
656
+ const category = document.getElementById('category').value;
657
+
658
+ const newEntry = {
659
+ id: Date.now(),
660
+ site,
661
+ username,
662
+ password,
663
+ category
664
+ };
665
+
666
+ passwords.push(newEntry);
667
+ renderPasswords();
668
+ closeModal();
669
+ showToast('New credential added securely!');
670
+ });
671
+
672
+ // Delete Password
673
+ window.deletePassword = function(id) {
674
+ if (confirm('Are you sure you want to delete this credential?')) {
675
+ passwords = passwords.filter(item => item.id !== id);
676
+ renderPasswords();
677
+ showToast('Credential deleted.');
678
+ }
679
+ };
680
+
681
+ // Edit Password (Simplified)
682
+ window.editPassword = function(id) {
683
+ const item = passwords.find(p => p.id === id);
684
+ if (item) {
685
+ document.getElementById('siteName').value = item.site;
686
+ document.getElementById('username').value = item.username;
687
+ document.getElementById('password').value = item.password;
688
+ document.getElementById('category').value = item.category;
689
+
690
+ // Remove the old item temporarily
691
+ passwords = passwords.filter(p => p.id !== id);
692
+ renderPasswords();
693
+ openModal();
694
+ // Note: In a full app, this would be a better form state management
695
+ }
696
+ };
697
+
698
+ // Modal Logic
699
+ function openModal() {
700
+ modal.style.display = 'flex';
701
+ }
702
+
703
+ function closeModal() {
704
+ modal.style.display = 'none';
705
+ form.reset();
706
+ }
707
+
708
+ // Close modal if clicking outside
709
+ window.onclick = function(event) {
710
+ if (event.target == modal) {
711
+ closeModal();
712
+ }
713
+ }
714
+
715
+ // Toast Logic
716
+ const toast = document.getElementById('toast');
717
+ const toastMessage = document.getElementById('toastMessage');
718
+
719
+ function showToast(message) {
720
+ toastMessage.textContent = message;
721
+ toast.classList.add('show');
722
+ setTimeout(() => {
723
+ toast.classList.remove('show');
724
+ }, 3000);
725
+ }
726
+ </script>
727
+ </body>
728
+ </html>