AmitJ82 commited on
Commit
8f978b6
·
verified ·
1 Parent(s): ef5f509

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +416 -19
index.html CHANGED
@@ -1,19 +1,416 @@
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" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Enigma Vault - Secure Note & Password Pad</title>
7
+
8
+ <!-- Tailwind CSS CDN -->
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+
11
+ <!-- Font Awesome CDN -->
12
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
13
+
14
+ <!-- Google Fonts (Poppins) -->
15
+ <link rel="preconnect" href="https://fonts.googleapis.com">
16
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
17
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
18
+
19
+ <style>
20
+ body {
21
+ font-family: 'Poppins', sans-serif;
22
+ -webkit-font-smoothing: antialiased;
23
+ -moz-osx-font-smoothing: grayscale;
24
+ }
25
+ ::-webkit-scrollbar { width: 8px; }
26
+ ::-webkit-scrollbar-track { background: #1e293b; }
27
+ ::-webkit-scrollbar-thumb { background: #475569; border-radius: 10px; }
28
+ ::-webkit-scrollbar-thumb:hover { background: #64748b; }
29
+
30
+ #note-body {
31
+ height: calc(100vh - 10rem); /* Adjust height dynamically */
32
+ }
33
+
34
+ .strength-bar {
35
+ transition: all 0.3s ease-in-out;
36
+ }
37
+
38
+ /* Fix for password overflow */
39
+ #generated-password {
40
+ overflow-wrap: break-word;
41
+ word-break: break-all;
42
+ }
43
+ </style>
44
+ </head>
45
+ <body class="bg-slate-900 text-slate-300">
46
+
47
+ <div class="flex h-screen">
48
+ <!-- Sidebar -->
49
+ <aside class="w-1/3 md:w-1/4 lg:w-1/5 bg-slate-800/70 p-4 flex flex-col border-r border-slate-700">
50
+ <header class="mb-4">
51
+ <h1 class="text-2xl font-bold text-white text-center">Enigma Vault</h1>
52
+ <p class="text-xs text-slate-400 text-center mb-4">Your Private Notes & Passwords</p>
53
+ <button id="new-note-btn" class="w-full bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded-lg transition duration-300 flex items-center justify-center gap-2">
54
+ <i class="fas fa-plus"></i> New Note
55
+ </button>
56
+ </header>
57
+
58
+ <div id="note-list" class="flex-grow overflow-y-auto space-y-2">
59
+ <!-- Notes will be dynamically inserted here -->
60
+ </div>
61
+
62
+ <footer class="mt-4 pt-4 border-t border-slate-700 space-y-2">
63
+ <button id="open-password-generator-btn" class="w-full bg-slate-700 hover:bg-slate-600 text-white font-bold py-2 px-4 rounded-lg transition duration-300 flex items-center justify-center gap-2">
64
+ <i class="fas fa-key"></i> Password Generator
65
+ </button>
66
+ <button id="download-all-btn" class="w-full bg-slate-700 hover:bg-slate-600 text-white font-bold py-2 px-4 rounded-lg transition duration-300 flex items-center justify-center gap-2">
67
+ <i class="fas fa-file-archive"></i> Download All Notes
68
+ </button>
69
+ <div id="privacy-notice" class="text-center text-xs text-slate-500 mt-2 p-2">
70
+ <i class="fas fa-exclamation-triangle"></i> <strong>Temporary Pad.</strong> All notes are deleted if you refresh or close the page. Nothing is saved permanently.
71
+ </div>
72
+ </footer>
73
+ </aside>
74
+
75
+ <!-- Main Content -->
76
+ <main class="w-2/3 md:w-3/4 lg:w-4/5 p-4 sm:p-6 md:p-8">
77
+ <!-- Welcome Screen -->
78
+ <div id="welcome-screen" class="flex flex-col items-center justify-center h-full text-center">
79
+ <i class="fas fa-book-open text-6xl text-slate-600 mb-4"></i>
80
+ <h2 class="text-3xl font-bold text-white">Welcome to Enigma Vault</h2>
81
+ <p class="text-slate-400 mt-2">Select a note from the list or create a new one to get started.</p>
82
+ </div>
83
+
84
+ <!-- Note Editor -->
85
+ <div id="note-editor" class="hidden h-full flex flex-col">
86
+ <div class="flex justify-between items-center mb-4 gap-4">
87
+ <input type="text" id="note-title" class="w-full bg-transparent text-3xl font-bold text-white focus:outline-none" placeholder="Note Title">
88
+ <div class="flex items-center gap-2 flex-shrink-0">
89
+ <button id="download-note-btn" title="Download this note" class="text-green-500 hover:text-green-400 p-2 rounded-full">
90
+ <i class="fas fa-download fa-lg"></i>
91
+ </button>
92
+ <button id="delete-note-btn" title="Delete this note" class="text-red-500 hover:text-red-400 p-2 rounded-full">
93
+ <i class="fas fa-trash-alt fa-lg"></i>
94
+ </button>
95
+ </div>
96
+ </div>
97
+ <textarea id="note-body" class="w-full flex-grow bg-slate-800/50 rounded-lg p-4 text-slate-200 focus:outline-none focus:ring-2 focus:ring-green-500" placeholder="Start writing your secure thoughts..."></textarea>
98
+ </div>
99
+ </main>
100
+ </div>
101
+
102
+ <!-- Password Generator Modal -->
103
+ <div id="password-generator-modal" class="hidden fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center p-4 z-50">
104
+ <div class="bg-slate-800 rounded-xl shadow-lg p-6 w-full max-w-md border-t-4 border-amber-500">
105
+ <div class="flex justify-between items-center mb-4">
106
+ <h2 class="text-2xl font-bold text-amber-400">Password Generator</h2>
107
+ <button id="close-modal-btn" class="text-slate-400 hover:text-white text-3xl leading-none">×</button>
108
+ </div>
109
+
110
+ <!-- Generated Password Display -->
111
+ <div class="bg-slate-900 p-4 rounded-lg mb-4 flex items-start min-h-[80px]">
112
+ <span id="generated-password" class="text-xl font-mono text-white flex-grow">Click Generate...</span>
113
+ <button id="copy-password-btn" class="ml-4 text-slate-400 hover:text-amber-400 flex-shrink-0"><i class="fas fa-copy"></i></button>
114
+ </div>
115
+
116
+ <!-- Strength Meter -->
117
+ <div class="w-full bg-slate-700 rounded-full h-2.5 mb-2">
118
+ <div id="strength-bar" class="bg-red-600 h-2.5 rounded-full strength-bar" style="width: 10%"></div>
119
+ </div>
120
+ <p id="strength-text" class="text-center text-sm text-slate-400 mb-6">Strength: Very Weak</p>
121
+
122
+ <!-- Options -->
123
+ <div class="space-y-4">
124
+ <div>
125
+ <label for="length" class="flex justify-between font-semibold">Length: <span id="length-val">16</span></label>
126
+ <input id="length" type="range" min="6" max="32" value="16" class="w-full h-2 bg-slate-700 rounded-lg appearance-none cursor-pointer">
127
+ </div>
128
+ <div class="grid grid-cols-2 gap-4">
129
+ <label class="flex items-center"><input type="checkbox" id="uppercase" class="w-4 h-4" checked><span class="ml-2">Uppercase (A-Z)</span></label>
130
+ <label class="flex items-center"><input type="checkbox" id="lowercase" class="w-4 h-4" checked><span class="ml-2">Lowercase (a-z)</span></label>
131
+ <label class="flex items-center"><input type="checkbox" id="numbers" class="w-4 h-4" checked><span class="ml-2">Numbers (0-9)</span></label>
132
+ <label class="flex items-center"><input type="checkbox" id="symbols" class="w-4 h-4" checked><span class="ml-2">Symbols (!@#$)</span></label>
133
+ </div>
134
+ <button id="generate-btn" class="w-full bg-amber-600 hover:bg-amber-700 text-white font-bold py-3 rounded-lg transition">Generate New Password</button>
135
+ </div>
136
+ </div>
137
+ </div>
138
+
139
+
140
+ <script>
141
+ document.addEventListener('DOMContentLoaded', () => {
142
+ // DOM Elements
143
+ const noteListEl = document.getElementById('note-list');
144
+ const newNoteBtn = document.getElementById('new-note-btn');
145
+ const deleteNoteBtn = document.getElementById('delete-note-btn');
146
+ const downloadNoteBtn = document.getElementById('download-note-btn');
147
+ const downloadAllBtn = document.getElementById('download-all-btn');
148
+ const noteEditorEl = document.getElementById('note-editor');
149
+ const welcomeScreenEl = document.getElementById('welcome-screen');
150
+ const noteTitleEl = document.getElementById('note-title');
151
+ const noteBodyEl = document.getElementById('note-body');
152
+
153
+ // State
154
+ let notes = [];
155
+ let activeNoteId = null;
156
+
157
+ // --- Core Note Functions ---
158
+ const saveNotes = () => {
159
+ updateButtonStates();
160
+ };
161
+
162
+ const renderNoteList = () => {
163
+ noteListEl.innerHTML = '';
164
+ if (notes.length === 0) {
165
+ noteListEl.innerHTML = `<p class="text-center text-slate-500 text-sm p-4">No notes yet. Create one!</p>`;
166
+ return;
167
+ }
168
+
169
+ const sortedNotes = [...notes].sort((a,b) => b.id - a.id);
170
+
171
+ sortedNotes.forEach(note => {
172
+ const noteItem = document.createElement('div');
173
+ noteItem.dataset.id = note.id;
174
+ noteItem.className = `p-3 rounded-lg cursor-pointer transition ${note.id === activeNoteId ? 'bg-green-600/30' : 'hover:bg-slate-700'}`;
175
+
176
+ const title = document.createElement('h3');
177
+ title.textContent = note.title || 'Untitled Note';
178
+ title.className = 'font-bold text-white truncate';
179
+ noteItem.appendChild(title);
180
+
181
+ const excerpt = document.createElement('p');
182
+ excerpt.textContent = note.body.substring(0, 40) + (note.body.length > 40 ? '...' : '');
183
+ excerpt.className = 'text-sm text-slate-400 truncate';
184
+ noteItem.appendChild(excerpt);
185
+
186
+ noteItem.addEventListener('click', () => selectNote(note.id));
187
+ noteListEl.appendChild(noteItem);
188
+ });
189
+ };
190
+
191
+ const selectNote = (id) => {
192
+ activeNoteId = id;
193
+ const note = notes.find(n => n.id === id);
194
+ if (note) {
195
+ welcomeScreenEl.classList.add('hidden');
196
+ noteEditorEl.classList.remove('hidden');
197
+ noteTitleEl.value = note.title;
198
+ noteBodyEl.value = note.body;
199
+ }
200
+ renderNoteList();
201
+ };
202
+
203
+ const createNewNote = () => {
204
+ const newNote = {
205
+ id: Date.now(),
206
+ title: 'New Note',
207
+ body: ''
208
+ };
209
+ notes.push(newNote);
210
+ saveNotes();
211
+ selectNote(newNote.id);
212
+ };
213
+
214
+ const deleteActiveNote = () => {
215
+ if (!activeNoteId) return;
216
+ if(confirm('Are you sure you want to delete this note? This action cannot be undone.')){
217
+ notes = notes.filter(note => note.id !== activeNoteId);
218
+ activeNoteId = null;
219
+ saveNotes();
220
+ noteEditorEl.classList.add('hidden');
221
+ welcomeScreenEl.classList.remove('hidden');
222
+ renderNoteList();
223
+ }
224
+ };
225
+
226
+ const downloadActiveNote = () => {
227
+ if (!activeNoteId) return;
228
+ const note = notes.find(n => n.id === activeNoteId);
229
+ if (!note) return;
230
+
231
+ const content = `Title: ${note.title}\n\n---\n\n${note.body}`;
232
+ const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
233
+ const url = URL.createObjectURL(blob);
234
+ const a = document.createElement('a');
235
+ const filename = (note.title || 'Untitled Note').replace(/[^a-z0-9]/gi, '_').toLowerCase();
236
+
237
+ a.href = url;
238
+ a.download = `${filename}.txt`;
239
+ document.body.appendChild(a);
240
+ a.click();
241
+ document.body.removeChild(a);
242
+ URL.revokeObjectURL(url);
243
+ };
244
+
245
+ const downloadAllNotes = () => {
246
+ if (notes.length === 0) {
247
+ alert('There are no notes to download.');
248
+ return;
249
+ }
250
+
251
+ const zip = new JSZip();
252
+
253
+ notes.forEach(note => {
254
+ const content = `Title: ${note.title}\n\n---\n\n${note.body}`;
255
+
256
+ const filename = (note.title || 'Untitled Note').replace(/[^a-z0-9]/gi, '_').toLowerCase();
257
+
258
+ zip.file(`${filename}_${note.id}.txt`, content);
259
+ });
260
+
261
+ zip.generateAsync({ type: "blob" })
262
+ .then(function(blob) {
263
+ const url = URL.createObjectURL(blob);
264
+ const a = document.createElement('a');
265
+ a.href = url;
266
+ a.download = 'enigma-vault-notes.zip';
267
+ document.body.appendChild(a);
268
+ a.click();
269
+ document.body.removeChild(a);
270
+ URL.revokeObjectURL(url);
271
+ });
272
+ };
273
+
274
+ const updateButtonStates = () => {
275
+ if (notes.length === 0) {
276
+ downloadAllBtn.disabled = true;
277
+ downloadAllBtn.classList.add('opacity-50', 'cursor-not-allowed');
278
+ } else {
279
+ downloadAllBtn.disabled = false;
280
+ downloadAllBtn.classList.remove('opacity-50', 'cursor-not-allowed');
281
+ }
282
+ };
283
+
284
+ // Event Listeners for Notes
285
+ newNoteBtn.addEventListener('click', createNewNote);
286
+ deleteNoteBtn.addEventListener('click', deleteActiveNote);
287
+ downloadNoteBtn.addEventListener('click', downloadActiveNote);
288
+ downloadAllBtn.addEventListener('click', downloadAllNotes);
289
+
290
+ noteTitleEl.addEventListener('input', () => {
291
+ const note = notes.find(n => n.id === activeNoteId);
292
+ if(note) {
293
+ note.title = noteTitleEl.value;
294
+ saveNotes();
295
+ const noteInList = noteListEl.querySelector(`[data-id='${activeNoteId}'] h3`);
296
+ if(noteInList) noteInList.textContent = note.title || 'Untitled Note';
297
+ }
298
+ });
299
+
300
+ noteBodyEl.addEventListener('input', () => {
301
+ const note = notes.find(n => n.id === activeNoteId);
302
+ if(note) {
303
+ note.body = noteBodyEl.value;
304
+ saveNotes();
305
+ const noteInList = noteListEl.querySelector(`[data-id='${activeNoteId}'] p`);
306
+ if(noteInList) noteInList.textContent = note.body.substring(0, 40) + (note.body.length > 40 ? '...' : '');
307
+ }
308
+ });
309
+
310
+
311
+ // --- Password Generator Logic ---
312
+ const openModalBtn = document.getElementById('open-password-generator-btn');
313
+ const closeModalBtn = document.getElementById('close-modal-btn');
314
+ const modal = document.getElementById('password-generator-modal');
315
+ const generateBtn = document.getElementById('generate-btn');
316
+ const copyBtn = document.getElementById('copy-password-btn');
317
+
318
+ const lengthSlider = document.getElementById('length');
319
+ const lengthVal = document.getElementById('length-val');
320
+ const uppercaseCheck = document.getElementById('uppercase');
321
+ const lowercaseCheck = document.getElementById('lowercase');
322
+ const numbersCheck = document.getElementById('numbers');
323
+ const symbolsCheck = document.getElementById('symbols');
324
+ const passwordEl = document.getElementById('generated-password');
325
+ const strengthBar = document.getElementById('strength-bar');
326
+ const strengthText = document.getElementById('strength-text');
327
+
328
+
329
+ openModalBtn.addEventListener('click', () => modal.classList.remove('hidden'));
330
+ closeModalBtn.addEventListener('click', () => modal.classList.add('hidden'));
331
+
332
+ lengthSlider.addEventListener('input', (e) => {
333
+ lengthVal.textContent = e.target.value;
334
+ });
335
+
336
+ copyBtn.addEventListener('click', () => {
337
+ if (passwordEl.textContent.length > 0 && passwordEl.textContent !== 'Click Generate...') {
338
+ navigator.clipboard.writeText(passwordEl.textContent);
339
+ copyBtn.innerHTML = '<i class="fas fa-check text-green-500"></i>';
340
+ setTimeout(() => {
341
+ copyBtn.innerHTML = '<i class="fas fa-copy"></i>';
342
+ }, 1500);
343
+ }
344
+ });
345
+
346
+ generateBtn.addEventListener('click', () => {
347
+ const length = +lengthSlider.value;
348
+ const hasUpper = uppercaseCheck.checked;
349
+ const hasLower = lowercaseCheck.checked;
350
+ const hasNumber = numbersCheck.checked;
351
+ const hasSymbol = symbolsCheck.checked;
352
+
353
+ passwordEl.textContent = generatePassword(hasUpper, hasLower, hasNumber, hasSymbol, length);
354
+ updatePasswordStrength();
355
+ });
356
+
357
+ const generatePassword = (upper, lower, number, symbol, length) => {
358
+ let generatedPassword = '';
359
+ const typesCount = upper + lower + number + symbol;
360
+ const typesArr = [{upper}, {lower}, {number}, {symbol}].filter(item => Object.values(item)[0]);
361
+
362
+ if(typesCount === 0) return 'Select at least one option';
363
+
364
+ for(let i=0; i<length; i++) {
365
+ const funcName = Object.keys(typesArr[Math.floor(Math.random() * typesArr.length)])[0];
366
+ generatedPassword += randomFunc[funcName]();
367
+ }
368
+
369
+ return generatedPassword.slice(0, length);
370
+ }
371
+
372
+ const randomFunc = {
373
+ lower: () => String.fromCharCode(Math.floor(Math.random() * 26) + 97),
374
+ upper: () => String.fromCharCode(Math.floor(Math.random() * 26) + 65),
375
+ number: () => String.fromCharCode(Math.floor(Math.random() * 10) + 48),
376
+ symbol: () => '!@#$%^&*(){}[]=<>/,.'.charAt(Math.floor(Math.random() * 20))
377
+ };
378
+
379
+ const updatePasswordStrength = () => {
380
+ const password = passwordEl.textContent;
381
+ let score = 0;
382
+ if(password.length === 0 || password === 'Select at least one option') {
383
+ strengthText.textContent = `Strength: N/A`;
384
+ strengthBar.style.width = '0%';
385
+ return;
386
+ }
387
+ if (password.length > 10) score++;
388
+ if (password.length > 15) score++;
389
+ if (/[a-z]/.test(password) && /[A-Z]/.test(password)) score++;
390
+ if (/\d/.test(password)) score++;
391
+ if (/[^A-Za-z0-9]/.test(password)) score++;
392
+
393
+ let strength = { text: 'Very Weak', color: 'bg-red-600', width: '10%' };
394
+ if (score >= 5) strength = { text: 'Very Strong', color: 'bg-green-500', width: '100%' };
395
+ else if (score === 4) strength = { text: 'Strong', color: 'bg-green-400', width: '80%' };
396
+ else if (score === 3) strength = { text: 'Medium', color: 'bg-yellow-500', width: '60%' };
397
+ else if (score >= 1) strength = { text: 'Weak', color: 'bg-orange-500', width: '35%' };
398
+
399
+ strengthText.textContent = `Strength: ${strength.text}`;
400
+ strengthBar.style.width = strength.width;
401
+ strengthBar.className = `h-2.5 rounded-full strength-bar ${strength.color}`;
402
+ };
403
+
404
+
405
+ // --- Initial Load ---
406
+ const init = () => {
407
+ renderNoteList();
408
+ updateButtonStates();
409
+ lengthVal.textContent = lengthSlider.value; // Set initial slider value display
410
+ };
411
+
412
+ init();
413
+ });
414
+ </script>
415
+ </body>
416
+ </html>