o2satz commited on
Commit
91a3034
·
verified ·
1 Parent(s): 1ecbd9c

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +835 -658
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Advanced File Finder</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
@@ -73,6 +73,57 @@
73
  .modal-enter-from, .modal-leave-to {
74
  opacity: 0;
75
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  </style>
77
  </head>
78
  <body class="bg-slate-50">
@@ -84,12 +135,12 @@
84
  <div class="w-9 h-9 rounded-lg bg-indigo-100 flex items-center justify-center">
85
  <i class="fas fa-search text-indigo-500"></i>
86
  </div>
87
- <h1 class="text-xl font-semibold text-slate-800">Advanced Finder</h1>
88
  </div>
89
  <div class="relative">
90
  <input
91
  type="text"
92
- v-model="sidebarSearch"
93
  placeholder="Search locations..."
94
  class="w-full px-4 py-2.5 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent placeholder-slate-400"
95
  >
@@ -97,34 +148,18 @@
97
  </div>
98
  </div>
99
  <div class="flex-1 overflow-y-auto">
100
- <div class="p-2">
101
- <div
102
- v-for="location in filteredLocations"
103
- :key="location.id"
104
- class="sidebar-item px-3 py-2.5 rounded-lg cursor-pointer flex items-center transition-all group"
105
- :class="{'bg-indigo-50': currentLocation.id === location.id}"
106
- @click="selectLocation(location)"
107
- >
108
- <div class="w-8 h-8 rounded-md flex items-center justify-center mr-2"
109
- :class="{'bg-indigo-100': currentLocation.id === location.id, 'bg-slate-100 group-hover:bg-slate-200': currentLocation.id !== location.id}">
110
- <i :class="location.icon" class="text-slate-600 group-hover:text-slate-800"
111
- :class="{'text-indigo-500': currentLocation.id === location.id}"></i>
112
- </div>
113
- <span class="text-sm font-medium truncate"
114
- :class="{'text-indigo-600': currentLocation.id === location.id, 'text-slate-700 group-hover:text-slate-900': currentLocation.id !== location.id}">
115
- {{ location.name }}
116
- </span>
117
- </div>
118
  </div>
119
  </div>
120
  <div class="p-4 border-t border-slate-200 text-xs text-slate-500 bg-slate-50">
121
  <div class="flex items-center mb-1">
122
  <i class="fas fa-database mr-2"></i>
123
- <span>Indexed: {{ indexedCount }} items</span>
124
  </div>
125
  <div class="flex items-center">
126
  <i class="fas fa-sync-alt mr-2"></i>
127
- <span>Last indexed: {{ lastIndexed }}</span>
128
  </div>
129
  </div>
130
  </div>
@@ -135,26 +170,34 @@
135
  <div class="bg-white border-b border-slate-200 p-4 flex items-center justify-between">
136
  <div class="flex items-center space-x-2">
137
  <button
 
 
 
 
 
 
 
 
138
  class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
139
- @click="refreshFiles"
140
  >
141
  <i class="fas fa-sync-alt mr-2"></i> Refresh
142
  </button>
143
  <button
 
144
  class="px-4 py-2 bg-white border border-slate-200 rounded-lg hover:bg-slate-50 flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
145
- @click="toggleIndexing"
146
- :class="{'glow': isIndexing}"
147
  >
148
- <i class="fas fa-database mr-2" :class="{'text-indigo-600': isIndexing}"></i>
149
- <span v-if="isIndexing">Indexing...</span>
150
- <span v-else>Index Now</span>
151
  </button>
152
- <div class="relative" v-if="selectedFiles.length > 0">
153
  <button
 
154
  class="px-4 py-2 bg-red-50 text-red-600 rounded-lg hover:bg-red-100 flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
155
- @click="showDeleteConfirm = true"
156
  >
157
- <i class="fas fa-trash mr-2"></i> Delete ({{ selectedFiles.length }})
158
  </button>
159
  </div>
160
  </div>
@@ -162,31 +205,45 @@
162
  <div class="relative">
163
  <input
164
  type="text"
165
- v-model="searchQuery"
166
  placeholder="Search files..."
167
  class="px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent w-64 placeholder-slate-400"
168
  >
169
  <i class="fas fa-search absolute right-3 top-3 text-slate-400"></i>
170
  </div>
171
  <button
 
172
  class="px-4 py-2 bg-white border border-slate-200 rounded-lg hover:bg-slate-50 flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
173
- @click="showAdvancedSearch = !showAdvancedSearch"
174
  >
175
  <i class="fas fa-sliders-h mr-2"></i> Filters
176
  </button>
 
 
 
 
 
 
 
177
  </div>
178
  </div>
179
 
 
 
 
 
 
180
  <!-- Advanced Search Panel -->
181
  <div
 
182
  class="bg-white border-b border-slate-200 px-5 py-4 transition-all duration-300 ease-in-out overflow-hidden"
183
- :style="showAdvancedSearch ? 'max-height: 240px' : 'max-height: 0'"
184
  >
185
  <div class="grid grid-cols-1 md:grid-cols-3 gap-5">
186
  <div>
187
  <label class="block text-sm font-medium text-slate-700 mb-2">File Type</label>
188
  <select
189
- v-model="filters.fileType"
190
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
191
  >
192
  <option value="all">All Files</option>
@@ -195,13 +252,14 @@
195
  <option value="audio">Audio</option>
196
  <option value="video">Video</option>
197
  <option value="archives">Archives</option>
 
198
  </select>
199
  </div>
200
  <div>
201
  <label class="block text-sm font-medium text-slate-700 mb-2">Author/Creator</label>
202
  <input
203
  type="text"
204
- v-model="filters.author"
205
  placeholder="Search by author..."
206
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent placeholder-slate-400"
207
  >
@@ -211,14 +269,14 @@
211
  <div class="flex items-center space-x-3">
212
  <input
213
  type="number"
214
- v-model="filters.sizeMin"
215
  placeholder="Min (KB)"
216
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent placeholder-slate-400"
217
  >
218
  <span class="text-sm text-slate-400">to</span>
219
  <input
220
  type="number"
221
- v-model="filters.sizeMax"
222
  placeholder="Max (KB)"
223
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent placeholder-slate-400"
224
  >
@@ -227,7 +285,7 @@
227
  <div>
228
  <label class="block text-sm font-medium text-slate-700 mb-2">Date Modified</label>
229
  <select
230
- v-model="filters.dateRange"
231
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
232
  >
233
  <option value="all">Any Time</option>
@@ -238,13 +296,13 @@
238
  <option value="custom">Custom Range</option>
239
  </select>
240
  </div>
241
- <div v-if="filters.dateRange === 'custom'" class="md:col-span-3">
242
  <div class="grid grid-cols-1 md:grid-cols-2 gap-5">
243
  <div>
244
  <label class="block text-sm font-medium text-slate-700 mb-2">From</label>
245
  <input
246
  type="date"
247
- v-model="filters.dateFrom"
248
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
249
  >
250
  </div>
@@ -252,7 +310,7 @@
252
  <label class="block text-sm font-medium text-slate-700 mb-2">To</label>
253
  <input
254
  type="date"
255
- v-model="filters.dateTo"
256
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
257
  >
258
  </div>
@@ -267,159 +325,96 @@
267
  <div class="col-span-5 flex items-center">
268
  <input
269
  type="checkbox"
 
270
  class="mr-3 h-4 w-4 text-indigo-600 rounded border-slate-300 focus:ring-indigo-500"
271
- @change="toggleSelectAll"
272
- :checked="selectedFiles.length === filteredFiles.length && filteredFiles.length > 0"
273
  >
274
  <span
 
275
  class="cursor-pointer flex items-center hover:text-slate-700 transition-colors"
276
- @click="sortBy('name')"
277
  >
278
  Name
279
- <i
280
- class="fas ml-1"
281
- :class="{
282
- 'fa-sort': activeSort !== 'name',
283
- 'fa-sort-up': activeSort === 'name' && sortDirection === 'asc',
284
- 'fa-sort-down': activeSort === 'name' && sortDirection === 'desc'
285
- }"
286
- ></i>
287
  </span>
288
  </div>
289
  <div
 
290
  class="col-span-2 cursor-pointer flex items-center hover:text-slate-700 transition-colors"
291
- @click="sortBy('author')"
292
  >
293
  <span>Author</span>
294
- <i
295
- class="fas ml-1"
296
- :class="{
297
- 'fa-sort': activeSort !== 'author',
298
- 'fa-sort-up': activeSort === 'author' && sortDirection === 'asc',
299
- 'fa-sort-down': activeSort === 'author' && sortDirection === 'desc'
300
- }"
301
- ></i>
302
  </div>
303
  <div
 
304
  class="col-span-2 cursor-pointer flex items-center hover:text-slate-700 transition-colors"
305
- @click="sortBy('type')"
306
  >
307
  <span>Type</span>
308
- <i
309
- class="fas ml-1"
310
- :class="{
311
- 'fa-sort': activeSort !== 'type',
312
- 'fa-sort-up': activeSort === 'type' && sortDirection === 'asc',
313
- 'fa-sort-down': activeSort === 'type' && sortDirection === 'desc'
314
- }"
315
- ></i>
316
  </div>
317
  <div
 
318
  class="col-span-2 cursor-pointer flex items-center justify-end hover:text-slate-700 transition-colors"
319
- @click="sortBy('size')"
320
  >
321
  <span>Size</span>
322
- <i
323
- class="fas ml-1"
324
- :class="{
325
- 'fa-sort': activeSort !== 'size',
326
- 'fa-sort-up': activeSort === 'size' && sortDirection === 'asc',
327
- 'fa-sort-down': activeSort === 'size' && sortDirection === 'desc'
328
- }"
329
- ></i>
330
  </div>
331
  <div
 
332
  class="col-span-1 cursor-pointer flex items-center justify-end hover:text-slate-700 transition-colors"
333
- @click="sortBy('modified')"
334
  >
335
  <span>Modified</span>
336
- <i
337
- class="fas ml-1"
338
- :class="{
339
- 'fa-sort': activeSort !== 'modified',
340
- 'fa-sort-up': activeSort === 'modified' && sortDirection === 'asc',
341
- 'fa-sort-down': activeSort === 'modified' && sortDirection === 'desc'
342
- }"
343
- ></i>
344
  </div>
345
  </div>
346
  </div>
347
 
348
  <!-- File List -->
349
- <div class="flex-1 overflow-y-auto bg-white">
350
- <div v-if="filteredFiles.length === 0" class="flex flex-col items-center justify-center h-64 text-slate-400">
351
  <i class="fas fa-folder-open text-5xl mb-4 opacity-30"></i>
352
- <p class="text-lg font-medium text-slate-500">No files found</p>
353
- <p class="text-sm mt-1 text-slate-400">Try adjusting your search or filters</p>
354
  </div>
355
-
356
- <template v-else>
357
- <div
358
- v-for="file in filteredFiles"
359
- :key="file.id"
360
- class="file-row px-5 py-3 border-b border-slate-100 grid grid-cols-12 gap-4 text-sm items-center transition-all"
361
- :class="{'highlight': selectedFiles.includes(file)}"
362
- @dblclick="openFile(file)"
363
- >
364
- <div class="col-span-5 flex items-center truncate">
365
- <input
366
- type="checkbox"
367
- class="mr-3 h-4 w-4 text-indigo-600 rounded border-slate-300 focus:ring-indigo-500"
368
- :checked="selectedFiles.includes(file)"
369
- @change="toggleFileSelection(file, $event)"
370
- >
371
- <div class="w-8 h-8 rounded-md flex items-center justify-center mr-2"
372
- :class="{'bg-indigo-50': selectedFiles.includes(file), 'bg-slate-100': !selectedFiles.includes(file)}">
373
- <i :class="getFileIcon(file)" class="text-slate-600"></i>
374
- </div>
375
- <div class="truncate">
376
- <div class="font-medium text-slate-800 truncate">{{ file.name }}</div>
377
- <div class="text-xs text-slate-500 truncate">{{ file.path || currentLocation.name }}</div>
378
- </div>
379
- <i v-if="file.isFavorite" class="fas fa-star text-yellow-400 ml-2 text-xs"></i>
380
- </div>
381
- <div class="col-span-2 text-slate-600 truncate">
382
- <span class="inline-flex items-center">
383
- <i class="fas fa-user-circle mr-2 text-slate-400"></i>
384
- {{ file.author || 'Unknown' }}
385
- </span>
386
- </div>
387
- <div class="col-span-2 text-slate-600 truncate text-sm">{{ file.type }}</div>
388
- <div class="col-span-2 text-slate-600 text-right text-sm">{{ formatFileSize(file.size) }}</div>
389
- <div class="col-span-1 text-slate-600 text-right text-sm">{{ formatDate(file.modified) }}</div>
390
- </div>
391
- </template>
392
  </div>
393
 
394
  <!-- Status Bar -->
395
  <div class="bg-slate-50 border-t border-slate-200 px-5 py-2.5 text-xs text-slate-500 flex justify-between">
396
  <div>
397
- <span v-if="selectedFiles.length > 0" class="font-medium">{{ selectedFiles.length }} selected</span>
398
- <span v-else>{{ filteredFiles.length }} items</span>
399
  </div>
400
  <div class="flex items-center space-x-5">
401
  <div class="flex items-center">
402
  <span class="mr-2">Index status:</span>
403
- <span v-if="isIndexing" class="text-indigo-600 font-medium flex items-center">
404
- <span class="w-2 h-2 rounded-full bg-indigo-500 mr-1.5 animate-pulse"></span>
405
- Running
406
- </span>
407
- <span v-else class="text-slate-400">Idle</span>
408
  </div>
409
  <div class="flex items-center">
410
- <i class="fas fa-circle text-xs mr-1.5" :class="{
411
- 'text-emerald-500': performanceRating === 'fast',
412
- 'text-amber-500': performanceRating === 'normal',
413
- 'text-rose-500': performanceRating === 'slow'
414
- }"></i>
415
- <span>{{ performanceRating }} performance</span>
416
  </div>
417
  </div>
418
  </div>
419
  </div>
420
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  <!-- Delete Confirmation Modal -->
422
- <div v-if="showDeleteConfirm" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 backdrop-blur-sm">
423
  <div class="bg-white rounded-xl modal-shadow p-6 w-96">
424
  <div class="flex items-start mb-5">
425
  <div class="flex-shrink-0 mt-1">
@@ -430,605 +425,787 @@
430
  <div class="ml-4">
431
  <h3 class="text-lg font-medium text-slate-800">Delete Files</h3>
432
  <p class="mt-1 text-sm text-slate-500">
433
- Are you sure you want to delete {{ selectedFiles.length }} file(s)? This action cannot be undone.
434
  </p>
435
  </div>
436
  </div>
437
  <div class="mt-6 flex justify-end space-x-3">
438
  <button
 
439
  type="button"
440
  class="px-4 py-2 bg-white border border-slate-200 rounded-lg text-slate-700 hover:bg-slate-50 transition-colors focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
441
- @click="showDeleteConfirm = false"
442
  >
443
  Cancel
444
  </button>
445
  <button
 
446
  type="button"
447
  class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
448
- @click="deleteSelectedFiles"
449
  >
450
  Delete
451
  </button>
452
  </div>
453
  </div>
454
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
  </div>
456
 
457
  <script>
458
- class Reactive {
459
- constructor(data) {
460
- this.data = data;
461
- this.subscribers = [];
462
- }
 
463
 
464
- get(prop) {
465
- return this.data[prop];
466
- }
467
 
468
- set(prop, value) {
469
- this.data[prop] = value;
470
- this.notify();
471
- }
472
 
473
- subscribe(callback) {
474
- this.subscribers.push(callback);
475
- }
476
 
477
- notify() {
478
- this.subscribers.forEach(callback => callback(this.data));
479
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
  }
481
 
482
- function bindInput(input, state, property) {
483
- input.value = state.get(property);
484
 
485
- input.addEventListener('input', (e) => {
486
- state.set(property, e.target.value);
487
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
 
489
- state.subscribe((data) => {
490
- input.value = data[property];
491
- });
492
  }
493
 
494
- function renderList(container, template, data) {
495
- container.innerHTML = '';
496
- data.forEach((item, index) => {
497
- const element = document.createElement('div');
498
- element.innerHTML = template(item, index);
499
- container.appendChild(element.firstChild);
500
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
501
  }
502
 
503
- document.addEventListener('DOMContentLoaded', () => {
504
- const state = new Reactive({
505
- sidebarSearch: '',
506
- currentLocation: { id: 1, name: 'Home', icon: 'fas fa-home' },
507
- indexedCount: 2847,
508
- lastIndexed: '5 minutes ago',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
509
 
510
- searchQuery: '',
511
- showAdvancedSearch: false,
512
- isIndexing: false,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
 
514
- activeSort: 'name',
515
- sortDirection: 'asc',
 
 
 
 
516
 
517
- selectedFiles: [],
518
- showDeleteConfirm: false,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
519
 
520
- filters: {
521
- fileType: 'all',
522
- author: '',
523
- sizeMin: '',
524
- sizeMax: '',
525
- dateRange: 'all',
526
- dateFrom: '',
527
- dateTo: ''
528
- },
529
 
530
- performanceRating: 'fast',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
531
 
532
- locations: [
533
- { id: 1, name: 'Home', icon: 'fas fa-home' },
534
- { id: 2, name: 'Documents', icon: 'fas fa-folder' },
535
- { id: 3, name: 'Downloads', icon: 'fas fa-download' },
536
- { id: 4, name: 'Pictures', icon: 'fas fa-image' },
537
- { id: 5, name: 'Music', icon: 'fas fa-music' },
538
- { id: 6, name: 'Videos', icon: 'fas fa-video' },
539
- { id: 7, name: 'Desktop', icon: 'fas fa-desktop' }
540
- ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
541
 
542
- files: [
543
- { id: 1, name: 'Project Proposal.pdf', path: 'Documents/Projects', author: 'John Doe', type: 'PDF Document', size: 2456, modified: '2023-06-15T14:30:00', isFavorite: false },
544
- { id: 2, name: 'Budget 2023.xlsx', path: 'Documents/Finance', author: 'Jane Smith', type: 'Excel Spreadsheet', size: 4532, modified: '2023-05-22T09:45:00', isFavorite: true },
545
- { id: 3, name: 'Team Photo.jpg', path: 'Pictures/Work', author: 'Mike Johnson', type: 'JPEG Image', size: 3245, modified: '2023-06-10T11:20:00', isFavorite: false },
546
- { id: 4, name: 'Meeting Notes.docx', path: 'Documents/Meetings', author: 'Sarah Wilson', type: 'Word Document', size: 876, modified: '2023-06-14T16:10:00', isFavorite: false },
547
- { id: 5, name: 'Presentation.pptx', path: 'Documents/Presentations', author: 'David Brown', type: 'PowerPoint', size: 6543, modified: '2023-06-12T13:30:00', isFavorite: false },
548
- { id: 6, name: 'Project Backup.zip', path: 'Downloads', author: 'Emma Davis', type: 'ZIP Archive', size: 24567, modified: '2023-06-09T18:05:00', isFavorite: false },
549
- { id: 7, name: 'Interview.mp3', path: 'Music/Recordings', author: 'James Miller', type: 'MP3 Audio', size: 12345, modified: '2023-05-30T10:15:00', isFavorite: false },
550
- { id: 8, name: 'Tutorial.mp4', path: 'Videos/Learning', author: 'Olivia Wilson', type: 'MP4 Video', size: 45678, modified: '2023-05-28T14:20:00', isFavorite: false },
551
- { id: 9, name: 'Configuration.ini', path: 'System', author: 'System', type: 'Configuration File', size: 23, modified: '2023-06-13T12:40:00', isFavorite: false },
552
- { id: 10, name: 'Code Repository', path: 'Documents/Projects', author: 'John Doe', type: 'Folder', size: 10245, modified: '2023-06-05T08:30:00', isFavorite: true }
553
- ]
554
  });
 
555
 
556
- function computedFilteredLocations() {
557
- const search = state.get('sidebarSearch').toLowerCase();
558
- return state.get('locations').filter(loc =>
559
- loc.name.toLowerCase().includes(search)
560
- );
561
- }
562
 
563
- function computedFilteredFiles() {
564
- let files = [...state.get('files')];
565
- const filters = state.get('filters');
566
- const search = state.get('searchQuery').toLowerCase();
567
- const activeSort = state.get('activeSort');
568
- const sortDirection = state.get('sortDirection');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
 
570
- if (search) {
571
- files = files.filter(file =>
572
- file.name.toLowerCase().includes(search) ||
573
- file.type.toLowerCase().includes(search) ||
574
- (file.author && file.author.toLowerCase().includes(search))
 
 
 
575
  );
576
- }
577
-
578
- if (filters.fileType !== 'all') {
579
- const typeMap = {
580
- 'documents': ['PDF Document', 'Word Document', 'Excel Spreadsheet', 'PowerPoint'],
581
- 'images': ['JPEG Image', 'PNG Image', 'GIF Image'],
582
- 'audio': ['MP3 Audio', 'WAV Audio'],
583
- 'video': ['MP4 Video', 'MOV Video'],
584
- 'archives': ['ZIP Archive', 'RAR Archive']
585
- };
586
 
587
- const types = typeMap[filters.fileType] || [];
588
- files = files.filter(file =>
589
- types.includes(file.type) ||
590
- (filters.fileType === 'documents' && file.type.includes('Document'))
591
- );
592
- }
 
 
 
 
 
 
 
593
 
594
- if (filters.author) {
595
- const authorSearch = filters.author.toLowerCase();
596
- files = files.filter(file =>
597
- file.author && file.author.toLowerCase().includes(authorSearch)
598
- );
599
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
 
601
- if (filters.sizeMin || filters.sizeMax) {
602
- const min = filters.sizeMin ? parseInt(filters.sizeMin) : 0;
603
- const max = filters.sizeMax ? parseInt(filters.sizeMax) : Infinity;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
604
 
605
- files = files.filter(file => file.size >= min && file.size <= max);
606
- }
607
-
608
- if (filters.dateRange && filters.dateRange !== 'all') {
609
- const now = new Date();
610
- let fromDate = new Date();
611
 
612
- switch (filters.dateRange) {
613
- case 'today':
614
- fromDate.setHours(0, 0, 0, 0);
615
- break;
616
- case 'week':
617
- fromDate.setDate(fromDate.getDate() - 7);
618
- break;
619
- case 'month':
620
- fromDate.setMonth(fromDate.getMonth() - 1);
621
- break;
622
- case 'year':
623
- fromDate.setFullYear(fromDate.getFullYear() - 1);
624
- break;
625
- case 'custom':
626
- if (filters.dateFrom) {
627
- fromDate = new Date(filters.dateFrom);
628
- }
629
- break;
630
- }
631
 
632
- files = files.filter(file => {
633
- const fileDate = new Date(file.modified);
634
- return fileDate >= fromDate;
 
635
  });
636
 
637
- if (filters.dateRange === 'custom' && filters.dateTo) {
638
- const toDate = new Date(filters.dateTo);
639
- toDate.setHours(23, 59, 59, 999);
640
-
641
- files = files.filter(file => {
642
- const fileDate = new Date(file.modified);
643
- return fileDate <= toDate;
644
- });
645
- }
646
- }
647
-
648
- files.sort((a, b) => {
649
- let aVal, bVal;
650
-
651
- switch (activeSort) {
652
- case 'name':
653
- aVal = a.name.toLowerCase();
654
- bVal = b.name.toLowerCase();
655
- break;
656
- case 'author':
657
- aVal = a.author ? a.author.toLowerCase() : '';
658
- bVal = b.author ? b.author.toLowerCase() : '';
659
- break;
660
- case 'type':
661
- aVal = a.type.toLowerCase();
662
- bVal = b.type.toLowerCase();
663
- break;
664
- case 'size':
665
- aVal = a.size;
666
- bVal = b.size;
667
- break;
668
- case 'modified':
669
- aVal = new Date(a.modified);
670
- bVal = new Date(b.modified);
671
- break;
672
- default:
673
- aVal = a.name.toLowerCase();
674
- bVal = b.name.toLowerCase();
675
- }
676
-
677
- if (aVal < bVal) return sortDirection === 'asc' ? -1 : 1;
678
- if (aVal > bVal) return sortDirection === 'asc' ? 1 : -1;
679
- return 0;
680
  });
681
-
682
- return files;
683
  }
 
 
 
 
 
 
 
684
 
685
- function formatFileSize(bytes) {
686
- if (bytes === 0) return '0 Bytes';
687
- if (typeof bytes === 'string') bytes = parseInt(bytes);
688
-
689
- const k = 1024;
690
- const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
691
- const i = Math.floor(Math.log(bytes) / Math.log(k));
692
-
693
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
 
694
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
695
 
696
- function formatDate(dateString) {
697
- const date = new Date(dateString);
698
- return date.toLocaleDateString('en-US', {month: 'short', day: 'numeric'});
 
 
 
 
 
 
 
 
 
699
  }
 
700
 
701
- function getFileIcon(file) {
702
- if (file.type === 'Folder') return 'fas fa-folder folder-icon';
703
-
704
- const extension = file.name.split('.').pop().toLowerCase();
705
- const iconMap = {
706
- 'pdf': 'fas fa-file-pdf file-icon',
707
- 'docx': 'fas fa-file-word file-icon',
708
- 'xlsx': 'fas fa-file-excel file-icon',
709
- 'pptx': 'fas fa-file-powerpoint file-icon',
710
- 'jpg': 'fas fa-file-image file-icon',
711
- 'jpeg': 'fas fa-file-image file-icon',
712
- 'png': 'fas fa-file-image file-icon',
713
- 'gif': 'fas fa-file-image file-icon',
714
- 'mp3': 'fas fa-file-audio file-icon',
715
- 'wav': 'fas fa-file-audio file-icon',
716
- 'mp4': 'fas fa-file-video file-icon',
717
- 'mov': 'fas fa-file-video file-icon',
718
- 'zip': 'fas fa-file-archive file-icon',
719
- 'rar': 'fas fa-file-archive file-icon',
720
- 'ini': 'fas fa-file-code file-icon'
721
- };
722
-
723
- return iconMap[extension] || 'fas fa-file file-icon';
724
  }
 
725
 
726
- function toggleIndexing() {
727
- state.set('isIndexing', !state.get('isIndexing'));
728
- if (state.get('isIndexing')) {
729
- let count = state.get('indexedCount');
730
- const interval = setInterval(() => {
731
- count += Math.floor(Math.random() * 10);
732
- state.set('indexedCount', count);
733
- state.set('lastIndexed', 'Just now');
734
-
735
- if (!state.get('isIndexing')) {
736
- clearInterval(interval);
737
- }
738
- }, 3000);
739
-
740
- setTimeout(() => {
741
- if (Math.random() > 0.7) {
742
- state.set('isIndexing', false);
743
- }
744
- }, 15000);
745
- }
746
- }
747
 
748
- function refreshFiles() {
749
- state.set('performanceRating', ['fast', 'normal', 'slow'][Math.floor(Math.random() * 3)]);
 
 
 
750
 
751
- if (Math.random() > 0.7) {
752
- const newFiles = [...state.get('files')];
753
- if (newFiles.length > 5 && Math.random() > 0.5) {
754
- newFiles.splice(Math.floor(Math.random() * newFiles.length), 1);
755
- } else {
756
- const authors = ['John Doe', 'Jane Smith', 'Mike Johnson', 'Sarah Wilson', 'Emma Davis'];
757
- const newFile = {
758
- id: Math.max(...newFiles.map(f => f.id)) + 1,
759
- name: ['New Document.docx', 'Report.pdf', 'Image.jpg', 'Archive.zip', 'Data.xlsx'][Math.floor(Math.random() * 5)],
760
- path: ['Documents', 'Downloads', 'Pictures', 'Music', 'Videos'][Math.floor(Math.random() * 5)],
761
- author: authors[Math.floor(Math.random() * authors.length)],
762
- type: ['PDF Document', 'Word Document', 'Excel Spreadsheet', 'JPEG Image', 'ZIP Archive'][Math.floor(Math.random() * 5)],
763
- size: Math.floor(Math.random() * 10000),
764
- modified: new Date().toISOString(),
765
- isFavorite: Math.random() > 0.8
766
- };
767
- newFiles.push(newFile);
768
- }
769
- state.set('files', newFiles);
770
  }
 
 
 
771
  }
 
 
 
 
 
 
 
 
 
 
 
 
772
 
773
- function selectLocation(location) {
774
- state.set('currentLocation', location);
775
- state.set('searchQuery', '');
776
- state.set('selectedFiles', []);
 
 
 
 
 
777
  }
 
778
 
779
- function sortBy(column) {
780
- if (state.get('activeSort') === column) {
781
- state.set('sortDirection', state.get('sortDirection') === 'asc' ? 'desc' : 'asc');
782
- } else {
783
- state.set('activeSort', column);
784
- state.set('sortDirection', 'asc');
785
- }
 
 
786
  }
 
787
 
788
- function toggleSelectAll(e) {
789
- const allFiles = computedFilteredFiles();
790
- if (e.target.checked) {
791
- state.set('selectedFiles', [...allFiles]);
792
- } else {
793
- state.set('selectedFiles', []);
794
- }
 
 
 
795
  }
 
 
 
 
 
 
 
 
 
796
 
797
- function toggleFileSelection(file, e) {
798
- const selected = [...state.get('selectedFiles')];
799
- if (e.target.checked) {
800
- selected.push(file);
801
- } else {
802
- const index = selected.findIndex(f => f.id === file.id);
803
- if (index !== -1) {
804
- selected.splice(index, 1);
 
 
 
 
 
 
 
 
 
 
 
 
805
  }
806
- }
807
- state.set('selectedFiles', selected);
 
 
 
 
 
 
 
 
 
 
 
 
 
808
  }
 
809
 
810
- function openFile(file) {
811
- if (file.type === 'Folder') {
812
- // Navigate to folder
813
- const newLocation = {
814
- id: Date.now(),
815
- name: file.name,
816
- icon: 'fas fa-folder'
817
- };
818
- state.set('currentLocation', newLocation);
819
- state.set('selectedFiles', []);
 
 
 
 
 
 
 
 
 
 
820
  } else {
821
- // Open file (simulated)
822
- alert(`Opening file: ${file.name}`);
 
 
 
 
 
 
 
 
 
 
823
  }
 
 
 
 
 
824
  }
 
825
 
826
- function deleteSelectedFiles() {
827
- const filesToDelete = [...state.get('selectedFiles')];
828
- const currentFiles = [...state.get('files')];
829
-
830
- const updatedFiles = currentFiles.filter(file =>
831
- !filesToDelete.some(f => f.id === file.id)
832
- );
833
-
834
- state.set('files', updatedFiles);
835
- state.set('selectedFiles', []);
836
- state.set('showDeleteConfirm', false);
837
-
838
- // Show success notification
839
- alert(`Successfully deleted ${filesToDelete.length} file(s)`);
840
  }
841
-
842
- // Bind UI elements to state
843
- const app = document.getElementById('app');
844
 
845
- function render() {
846
- const data = state.data;
847
- const filteredLocations = computedFilteredLocations();
848
- const filteredFiles = computedFilteredFiles();
849
-
850
- // Sidebar search
851
- app.querySelector('input[placeholder="Search locations..."]').value = data.sidebarSearch;
852
-
853
- // Main search
854
- app.querySelector('input[placeholder="Search files..."]').value = data.searchQuery;
855
-
856
- // Sidebar locations
857
- const sidebarLocations = app.querySelector('.flex-1.overflow-y-auto .p-2');
858
- sidebarLocations.innerHTML = '';
859
- filteredLocations.forEach(location => {
860
- const locationEl = document.createElement('div');
861
- locationEl.className = `sidebar-item px-3 py-2.5 rounded-lg cursor-pointer flex items-center transition-all group ${
862
- data.currentLocation.id === location.id ? 'bg-indigo-50' : ''
863
- }`;
864
- locationEl.innerHTML = `
865
- <div class="w-8 h-8 rounded-md flex items-center justify-center mr-2 ${
866
- data.currentLocation.id === location.id ? 'bg-indigo-100' : 'bg-slate-100 group-hover:bg-slate-200'
867
- }">
868
- <i class="${location.icon} text-slate-600 group-hover:text-slate-800 ${
869
- data.currentLocation.id === location.id ? 'text-indigo-500' : ''
870
- }"></i>
871
- </div>
872
- <span class="text-sm font-medium truncate ${
873
- data.currentLocation.id === location.id ? 'text-indigo-600' : 'text-slate-700 group-hover:text-slate-900'
874
- }">
875
- ${location.name}
876
- </span>
877
- `;
878
- locationEl.addEventListener('click', () => selectLocation(location));
879
- sidebarLocations.appendChild(locationEl);
880
- });
881
-
882
- // File list
883
- const fileList = app.querySelector('.flex-1.overflow-y-auto.bg-white');
884
- if (filteredFiles.length === 0) {
885
- fileList.innerHTML = `
886
- <div class="flex flex-col items-center justify-center h-64 text-slate-400">
887
- <i class="fas fa-folder-open text-5xl mb-4 opacity-30"></i>
888
- <p class="text-lg font-medium text-slate-500">No files found</p>
889
- <p class="text-sm mt-1 text-slate-400">Try adjusting your search or filters</p>
890
- </div>
891
- `;
892
- } else {
893
- fileList.innerHTML = '';
894
- filteredFiles.forEach(file => {
895
- const fileEl = document.createElement('div');
896
- fileEl.className = `file-row px-5 py-3 border-b border-slate-100 grid grid-cols-12 gap-4 text-sm items-center transition-all ${
897
- data.selectedFiles.includes(file) ? 'highlight' : ''
898
- }`;
899
- fileEl.innerHTML = `
900
- <div class="col-span-5 flex items-center truncate">
901
- <input
902
- type="checkbox"
903
- class="mr-3 h-4 w-4 text-indigo-600 rounded border-slate-300 focus:ring-indigo-500"
904
- ${data.selectedFiles.includes(file) ? 'checked' : ''}
905
- >
906
- <div class="w-8 h-8 rounded-md flex items-center justify-center mr-2 ${
907
- data.selectedFiles.includes(file) ? 'bg-indigo-50' : 'bg-slate-100'
908
- }">
909
- <i class="${getFileIcon(file)} text-slate-600"></i>
910
- </div>
911
- <div class="truncate">
912
- <div class="font-medium text-slate-800 truncate">${file.name}</div>
913
- <div class="text-xs text-slate-500 truncate">${file.path || data.currentLocation.name}</div>
914
- </div>
915
- ${file.isFavorite ? '<i class="fas fa-star text-yellow-400 ml-2 text-xs"></i>' : ''}
916
- </div>
917
- <div class="col-span-2 text-slate-600 truncate">
918
- <span class="inline-flex items-center">
919
- <i class="fas fa-user-circle mr-2 text-slate-400"></i>
920
- ${file.author || 'Unknown'}
921
- </span>
922
- </div>
923
- <div class="col-span-2 text-slate-600 truncate text-sm">${file.type}</div>
924
- <div class="col-span-2 text-slate-600 text-right text-sm">${formatFileSize(file.size)}</div>
925
- <div class="col-span-1 text-slate-600 text-right text-sm">${formatDate(file.modified)}</div>
926
- `;
927
-
928
- // Add event listeners
929
- const checkbox = fileEl.querySelector('input[type="checkbox"]');
930
- checkbox.addEventListener('change', (e) => toggleFileSelection(file, e));
931
-
932
- fileEl.addEventListener('dblclick', () => openFile(file));
933
-
934
- fileList.appendChild(fileEl);
935
- });
936
- }
937
-
938
- // Status bar
939
- const statusBar = app.querySelector('.bg-slate-50.border-t.border-slate-200');
940
- statusBar.innerHTML = `
941
- <div>
942
- <span class="${data.selectedFiles.length > 0 ? 'font-medium' : ''}">
943
- ${data.selectedFiles.length > 0 ? `${data.selectedFiles.length} selected` : `${filteredFiles.length} items`}
944
- </span>
945
- </div>
946
- <div class="flex items-center space-x-5">
947
- <div class="flex items-center">
948
- <span class="mr-2">Index status:</span>
949
- ${data.isIndexing ? `
950
- <span class="text-indigo-600 font-medium flex items-center">
951
- <span class="w-2 h-2 rounded-full bg-indigo-500 mr-1.5 animate-pulse"></span>
952
- Running
953
- </span>
954
- ` : '<span class="text-slate-400">Idle</span>'}
955
- </div>
956
- <div class="flex items-center">
957
- <i class="fas fa-circle text-xs mr-1.5 ${
958
- data.performanceRating === 'fast' ? 'text-emerald-500' :
959
- data.performanceRating === 'normal' ? 'text-amber-500' : 'text-rose-500'
960
- }"></i>
961
- <span>${data.performanceRating} performance</span>
962
- </div>
963
- </div>
964
- `;
965
-
966
- // Select all checkbox
967
- const selectAllCheckbox = app.querySelector('input[type="checkbox"][class*="mr-3 h-4 w-4"]');
968
- selectAllCheckbox.checked = data.selectedFiles.length === filteredFiles.length && filteredFiles.length > 0;
969
- selectAllCheckbox.addEventListener('change', toggleSelectAll);
970
-
971
- // Advanced search panel
972
- const advancedSearchPanel = app.querySelector('.bg-white.border-b.border-slate-200');
973
- advancedSearchPanel.style.maxHeight = data.showAdvancedSearch ? '240px' : '0';
974
-
975
- // Modal
976
- const modal = app.querySelector('.fixed.inset-0');
977
- if (data.showDeleteConfirm) {
978
- modal.style.display = 'flex';
979
- } else {
980
- modal.style.display = 'none';
981
- }
982
  }
 
 
 
 
983
 
984
- // Initialize event listeners
985
- function initEventListeners() {
986
- // Sidebar search
987
- const sidebarSearch = app.querySelector('input[placeholder="Search locations..."]');
988
- sidebarSearch.addEventListener('input', (e) => {
989
- state.set('sidebarSearch', e.target.value);
990
- });
991
-
992
- // Main search
993
- const mainSearch = app.querySelector('input[placeholder="Search files..."]');
994
- mainSearch.addEventListener('input', (e) => {
995
- state.set('searchQuery', e.target.value);
996
- });
997
-
998
- // Refresh button
999
- const refreshBtn = app.querySelector('button:has(.fa-sync-alt)');
1000
- refreshBtn.addEventListener('click', refreshFiles);
1001
-
1002
- // Index button
1003
- const indexBtn = app.querySelector('button:has(.fa-database)');
1004
- indexBtn.addEventListener('click', toggleIndexing);
1005
-
1006
- // Filters button
1007
- const filtersBtn = app.querySelector('button:has(.fa-sliders-h)');
1008
- filtersBtn.addEventListener('click', () => {
1009
- state.set('showAdvancedSearch', !state.get('showAdvancedSearch'));
1010
- });
1011
-
1012
- // Delete confirmation modal buttons
1013
- const modalCancelBtn = app.querySelector('.fixed.inset-0 button:first-of-type');
1014
- const modalDeleteBtn = app.querySelector('.fixed.inset-0 button:last-of-type');
1015
-
1016
- if (modalCancelBtn && modalDeleteBtn) {
1017
- modalCancelBtn.addEventListener('click', () => {
1018
- state.set('showDeleteConfirm', false);
1019
- });
1020
-
1021
- modalDeleteBtn.addEventListener('click', deleteSelectedFiles);
1022
  }
1023
  }
1024
-
1025
- // Subscribe to state changes
1026
- state.subscribe(render);
1027
 
1028
- // Initial render
1029
- render();
1030
- initEventListeners();
1031
- });
1032
- </script>
1033
- </body>
 
 
 
 
1034
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Advanced File Finder Pro</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
 
73
  .modal-enter-from, .modal-leave-to {
74
  opacity: 0;
75
  }
76
+ .toast {
77
+ position: fixed;
78
+ bottom: 20px;
79
+ right: 20px;
80
+ background: #4f46e5;
81
+ color: white;
82
+ padding: 12px 24px;
83
+ border-radius: 8px;
84
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
85
+ transform: translateY(100px);
86
+ opacity: 0;
87
+ transition: all 0.3s ease;
88
+ z-index: 1000;
89
+ }
90
+ .toast.show {
91
+ transform: translateY(0);
92
+ opacity: 1;
93
+ }
94
+ .context-menu {
95
+ position: absolute;
96
+ background: white;
97
+ border-radius: 8px;
98
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
99
+ z-index: 100;
100
+ min-width: 200px;
101
+ overflow: hidden;
102
+ display: none;
103
+ }
104
+ .context-menu-item {
105
+ padding: 8px 16px;
106
+ cursor: pointer;
107
+ display: flex;
108
+ align-items: center;
109
+ gap: 8px;
110
+ }
111
+ .context-menu-item:hover {
112
+ background: #f1f5f9;
113
+ }
114
+ .breadcrumb-item {
115
+ display: flex;
116
+ align-items: center;
117
+ gap: 4px;
118
+ cursor: pointer;
119
+ }
120
+ .breadcrumb-item:hover {
121
+ color: #4f46e5;
122
+ }
123
+ .breadcrumb-separator {
124
+ margin: 0 4px;
125
+ color: #94a3b8;
126
+ }
127
  </style>
128
  </head>
129
  <body class="bg-slate-50">
 
135
  <div class="w-9 h-9 rounded-lg bg-indigo-100 flex items-center justify-center">
136
  <i class="fas fa-search text-indigo-500"></i>
137
  </div>
138
+ <h1 class="text-xl font-semibold text-slate-800">Advanced Finder Pro</h1>
139
  </div>
140
  <div class="relative">
141
  <input
142
  type="text"
143
+ id="sidebarSearch"
144
  placeholder="Search locations..."
145
  class="w-full px-4 py-2.5 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent placeholder-slate-400"
146
  >
 
148
  </div>
149
  </div>
150
  <div class="flex-1 overflow-y-auto">
151
+ <div id="sidebarLocations" class="p-2">
152
+ <!-- Locations will be populated here -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  </div>
154
  </div>
155
  <div class="p-4 border-t border-slate-200 text-xs text-slate-500 bg-slate-50">
156
  <div class="flex items-center mb-1">
157
  <i class="fas fa-database mr-2"></i>
158
+ <span>Indexed: <span id="indexedCount">2847</span> items</span>
159
  </div>
160
  <div class="flex items-center">
161
  <i class="fas fa-sync-alt mr-2"></i>
162
+ <span>Last indexed: <span id="lastIndexed">5 minutes ago</span></span>
163
  </div>
164
  </div>
165
  </div>
 
170
  <div class="bg-white border-b border-slate-200 p-4 flex items-center justify-between">
171
  <div class="flex items-center space-x-2">
172
  <button
173
+ id="backBtn"
174
+ class="px-3 py-2 bg-white border border-slate-200 rounded-lg hover:bg-slate-50 flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
175
+ title="Go back"
176
+ >
177
+ <i class="fas fa-arrow-left mr-2"></i>
178
+ </button>
179
+ <button
180
+ id="refreshBtn"
181
  class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
182
+ title="Refresh"
183
  >
184
  <i class="fas fa-sync-alt mr-2"></i> Refresh
185
  </button>
186
  <button
187
+ id="indexBtn"
188
  class="px-4 py-2 bg-white border border-slate-200 rounded-lg hover:bg-slate-50 flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
189
+ title="Reindex files"
 
190
  >
191
+ <i class="fas fa-database mr-2"></i>
192
+ <span id="indexBtnText">Index Now</span>
 
193
  </button>
194
+ <div class="relative" id="deleteBtnContainer" style="display: none;">
195
  <button
196
+ id="deleteBtn"
197
  class="px-4 py-2 bg-red-50 text-red-600 rounded-lg hover:bg-red-100 flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
198
+ title="Delete selected files"
199
  >
200
+ <i class="fas fa-trash mr-2"></i> Delete (<span id="selectedCount">0</span>)
201
  </button>
202
  </div>
203
  </div>
 
205
  <div class="relative">
206
  <input
207
  type="text"
208
+ id="searchQuery"
209
  placeholder="Search files..."
210
  class="px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent w-64 placeholder-slate-400"
211
  >
212
  <i class="fas fa-search absolute right-3 top-3 text-slate-400"></i>
213
  </div>
214
  <button
215
+ id="filtersBtn"
216
  class="px-4 py-2 bg-white border border-slate-200 rounded-lg hover:bg-slate-50 flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
217
+ title="Show filters"
218
  >
219
  <i class="fas fa-sliders-h mr-2"></i> Filters
220
  </button>
221
+ <button
222
+ id="newBtn"
223
+ class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
224
+ title="Create new"
225
+ >
226
+ <i class="fas fa-plus mr-2"></i> New
227
+ </button>
228
  </div>
229
  </div>
230
 
231
+ <!-- Breadcrumbs -->
232
+ <div id="breadcrumbs" class="bg-white border-b border-slate-200 px-5 py-2 flex items-center text-sm">
233
+ <!-- Breadcrumbs will be populated here -->
234
+ </div>
235
+
236
  <!-- Advanced Search Panel -->
237
  <div
238
+ id="advancedSearchPanel"
239
  class="bg-white border-b border-slate-200 px-5 py-4 transition-all duration-300 ease-in-out overflow-hidden"
240
+ style="max-height: 0;"
241
  >
242
  <div class="grid grid-cols-1 md:grid-cols-3 gap-5">
243
  <div>
244
  <label class="block text-sm font-medium text-slate-700 mb-2">File Type</label>
245
  <select
246
+ id="fileTypeFilter"
247
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
248
  >
249
  <option value="all">All Files</option>
 
252
  <option value="audio">Audio</option>
253
  <option value="video">Video</option>
254
  <option value="archives">Archives</option>
255
+ <option value="folders">Folders</option>
256
  </select>
257
  </div>
258
  <div>
259
  <label class="block text-sm font-medium text-slate-700 mb-2">Author/Creator</label>
260
  <input
261
  type="text"
262
+ id="authorFilter"
263
  placeholder="Search by author..."
264
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent placeholder-slate-400"
265
  >
 
269
  <div class="flex items-center space-x-3">
270
  <input
271
  type="number"
272
+ id="sizeMinFilter"
273
  placeholder="Min (KB)"
274
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent placeholder-slate-400"
275
  >
276
  <span class="text-sm text-slate-400">to</span>
277
  <input
278
  type="number"
279
+ id="sizeMaxFilter"
280
  placeholder="Max (KB)"
281
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent placeholder-slate-400"
282
  >
 
285
  <div>
286
  <label class="block text-sm font-medium text-slate-700 mb-2">Date Modified</label>
287
  <select
288
+ id="dateRangeFilter"
289
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
290
  >
291
  <option value="all">Any Time</option>
 
296
  <option value="custom">Custom Range</option>
297
  </select>
298
  </div>
299
+ <div id="customDateRangeContainer" style="display: none;" class="md:col-span-3">
300
  <div class="grid grid-cols-1 md:grid-cols-2 gap-5">
301
  <div>
302
  <label class="block text-sm font-medium text-slate-700 mb-2">From</label>
303
  <input
304
  type="date"
305
+ id="dateFromFilter"
306
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
307
  >
308
  </div>
 
310
  <label class="block text-sm font-medium text-slate-700 mb-2">To</label>
311
  <input
312
  type="date"
313
+ id="dateToFilter"
314
  class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
315
  >
316
  </div>
 
325
  <div class="col-span-5 flex items-center">
326
  <input
327
  type="checkbox"
328
+ id="selectAllCheckbox"
329
  class="mr-3 h-4 w-4 text-indigo-600 rounded border-slate-300 focus:ring-indigo-500"
 
 
330
  >
331
  <span
332
+ id="sortByName"
333
  class="cursor-pointer flex items-center hover:text-slate-700 transition-colors"
 
334
  >
335
  Name
336
+ <i id="nameSortIcon" class="fas ml-1 fa-sort"></i>
 
 
 
 
 
 
 
337
  </span>
338
  </div>
339
  <div
340
+ id="sortByAuthor"
341
  class="col-span-2 cursor-pointer flex items-center hover:text-slate-700 transition-colors"
 
342
  >
343
  <span>Author</span>
344
+ <i id="authorSortIcon" class="fas ml-1 fa-sort"></i>
 
 
 
 
 
 
 
345
  </div>
346
  <div
347
+ id="sortByType"
348
  class="col-span-2 cursor-pointer flex items-center hover:text-slate-700 transition-colors"
 
349
  >
350
  <span>Type</span>
351
+ <i id="typeSortIcon" class="fas ml-1 fa-sort"></i>
 
 
 
 
 
 
 
352
  </div>
353
  <div
354
+ id="sortBySize"
355
  class="col-span-2 cursor-pointer flex items-center justify-end hover:text-slate-700 transition-colors"
 
356
  >
357
  <span>Size</span>
358
+ <i id="sizeSortIcon" class="fas ml-1 fa-sort"></i>
 
 
 
 
 
 
 
359
  </div>
360
  <div
361
+ id="sortByModified"
362
  class="col-span-1 cursor-pointer flex items-center justify-end hover:text-slate-700 transition-colors"
 
363
  >
364
  <span>Modified</span>
365
+ <i id="modifiedSortIcon" class="fas ml-1 fa-sort"></i>
 
 
 
 
 
 
 
366
  </div>
367
  </div>
368
  </div>
369
 
370
  <!-- File List -->
371
+ <div id="fileList" class="flex-1 overflow-y-auto bg-white">
372
+ <div class="flex flex-col items-center justify-center h-64 text-slate-400">
373
  <i class="fas fa-folder-open text-5xl mb-4 opacity-30"></i>
374
+ <p class="text-lg font-medium text-slate-500">Loading files...</p>
 
375
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  </div>
377
 
378
  <!-- Status Bar -->
379
  <div class="bg-slate-50 border-t border-slate-200 px-5 py-2.5 text-xs text-slate-500 flex justify-between">
380
  <div>
381
+ <span id="statusCount">0 items</span>
 
382
  </div>
383
  <div class="flex items-center space-x-5">
384
  <div class="flex items-center">
385
  <span class="mr-2">Index status:</span>
386
+ <span id="indexStatus" class="text-slate-400">Idle</span>
 
 
 
 
387
  </div>
388
  <div class="flex items-center">
389
+ <i id="performanceIcon" class="fas fa-circle text-xs mr-1.5 text-emerald-500"></i>
390
+ <span id="performanceText">fast performance</span>
 
 
 
 
391
  </div>
392
  </div>
393
  </div>
394
  </div>
395
 
396
+ <!-- Context Menu -->
397
+ <div id="contextMenu" class="context-menu">
398
+ <div class="context-menu-item" id="contextOpen">
399
+ <i class="fas fa-folder-open"></i> Open
400
+ </div>
401
+ <div class="context-menu-item" id="contextDownload">
402
+ <i class="fas fa-download"></i> Download
403
+ </div>
404
+ <div class="context-menu-item" id="contextRename">
405
+ <i class="fas fa-pen"></i> Rename
406
+ </div>
407
+ <div class="context-menu-item" id="contextFavorite">
408
+ <i class="fas fa-star"></i> Add to Favorites
409
+ </div>
410
+ <div class="border-t border-slate-200"></div>
411
+ <div class="context-menu-item" id="contextDelete">
412
+ <i class="fas fa-trash text-red-500"></i> <span class="text-red-500">Delete</span>
413
+ </div>
414
+ </div>
415
+
416
  <!-- Delete Confirmation Modal -->
417
+ <div id="deleteModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50 backdrop-blur-sm">
418
  <div class="bg-white rounded-xl modal-shadow p-6 w-96">
419
  <div class="flex items-start mb-5">
420
  <div class="flex-shrink-0 mt-1">
 
425
  <div class="ml-4">
426
  <h3 class="text-lg font-medium text-slate-800">Delete Files</h3>
427
  <p class="mt-1 text-sm text-slate-500">
428
+ Are you sure you want to delete <span id="deleteCount">0</span> file(s)? This action cannot be undone.
429
  </p>
430
  </div>
431
  </div>
432
  <div class="mt-6 flex justify-end space-x-3">
433
  <button
434
+ id="cancelDeleteBtn"
435
  type="button"
436
  class="px-4 py-2 bg-white border border-slate-200 rounded-lg text-slate-700 hover:bg-slate-50 transition-colors focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
 
437
  >
438
  Cancel
439
  </button>
440
  <button
441
+ id="confirmDeleteBtn"
442
  type="button"
443
  class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
 
444
  >
445
  Delete
446
  </button>
447
  </div>
448
  </div>
449
  </div>
450
+
451
+ <!-- New File/Folder Modal -->
452
+ <div id="newModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50 backdrop-blur-sm">
453
+ <div class="bg-white rounded-xl modal-shadow p-6 w-96">
454
+ <div class="flex items-start mb-5">
455
+ <div class="flex-shrink-0 mt-1">
456
+ <div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center">
457
+ <i class="fas fa-plus text-indigo-500"></i>
458
+ </div>
459
+ </div>
460
+ <div class="ml-4">
461
+ <h3 class="text-lg font-medium text-slate-800">Create New</h3>
462
+ <p class="mt-1 text-sm text-slate-500">
463
+ Create a new file or folder in the current location.
464
+ </p>
465
+ </div>
466
+ </div>
467
+ <div class="mt-4">
468
+ <div class="flex items-center space-x-2 mb-4">
469
+ <button id="newFileBtn" class="flex-1 px-4 py-3 border border-slate-200 rounded-lg hover:bg-slate-50 flex flex-col items-center">
470
+ <i class="fas fa-file text-indigo-500 text-xl mb-2"></i>
471
+ <span>File</span>
472
+ </button>
473
+ <button id="newFolderBtn" class="flex-1 px-4 py-3 border border-slate-200 rounded-lg hover:bg-slate-50 flex flex-col items-center">
474
+ <i class="fas fa-folder text-amber-500 text-xl mb-2"></i>
475
+ <span>Folder</span>
476
+ </button>
477
+ </div>
478
+ <div id="newFormContainer" style="display: none;">
479
+ <div class="mb-4">
480
+ <label class="block text-sm font-medium text-slate-700 mb-1">Name</label>
481
+ <input
482
+ type="text"
483
+ id="newNameInput"
484
+ placeholder="Enter name..."
485
+ class="w-full px-4 py-2 text-sm border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent placeholder-slate-400"
486
+ >
487
+ </div>
488
+ <div class="flex justify-end space-x-3">
489
+ <button
490
+ id="cancelNewBtn"
491
+ type="button"
492
+ class="px-4 py-2 bg-white border border-slate-200 rounded-lg text-slate-700 hover:bg-slate-50 transition-colors focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
493
+ >
494
+ Cancel
495
+ </button>
496
+ <button
497
+ id="confirmNewBtn"
498
+ type="button"
499
+ class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
500
+ >
501
+ Create
502
+ </button>
503
+ </div>
504
+ </div>
505
+ </div>
506
+ </div>
507
+ </div>
508
+
509
+ <!-- Toast Notification -->
510
+ <div id="toast" class="toast">
511
+ <div class="flex items-center">
512
+ <i id="toastIcon" class="fas fa-check-circle mr-2"></i>
513
+ <span id="toastMessage">Operation completed successfully</span>
514
+ </div>
515
+ </div>
516
  </div>
517
 
518
  <script>
519
+ // Enhanced application state
520
+ const state = {
521
+ sidebarSearch: '',
522
+ currentLocation: { id: 1, name: 'Home', icon: 'fas fa-home', path: [] },
523
+ indexedCount: 2847,
524
+ lastIndexed: '5 minutes ago',
525
 
526
+ searchQuery: '',
527
+ showAdvancedSearch: false,
528
+ isIndexing: false,
529
 
530
+ activeSort: 'name',
531
+ sortDirection: 'asc',
 
 
532
 
533
+ selectedFiles: [],
534
+ showDeleteConfirm: false,
535
+ contextMenuFile: null,
536
 
537
+ filters: {
538
+ fileType: 'all',
539
+ author: '',
540
+ sizeMin: '',
541
+ sizeMax: '',
542
+ dateRange: 'all',
543
+ dateFrom: '',
544
+ dateTo: ''
545
+ },
546
+
547
+ performanceRating: 'fast',
548
+ newItemType: 'file',
549
+
550
+ locations: [
551
+ { id: 1, name: 'Home', icon: 'fas fa-home', path: [] },
552
+ { id: 2, name: 'Documents', icon: 'fas fa-folder', path: ['Home'] },
553
+ { id: 3, name: 'Downloads', icon: 'fas fa-download', path: ['Home'] },
554
+ { id: 4, name: 'Pictures', icon: 'fas fa-image', path: ['Home'] },
555
+ { id: 5, name: 'Music', icon: 'fas fa-music', path: ['Home'] },
556
+ { id: 6, name: 'Videos', icon: 'fas fa-video', path: ['Home'] },
557
+ { id: 7, name: 'Desktop', icon: 'fas fa-desktop', path: ['Home'] }
558
+ ],
559
+
560
+ files: [
561
+ { id: 1, name: 'Project Proposal.pdf', path: ['Home', 'Documents', 'Projects'], author: 'John Doe', type: 'PDF Document', size: 2456, modified: '2023-06-15T14:30:00', isFavorite: false },
562
+ { id: 2, name: 'Budget 2023.xlsx', path: ['Home', 'Documents', 'Finance'], author: 'Jane Smith', type: 'Excel Spreadsheet', size: 4532, modified: '2023-05-22T09:45:00', isFavorite: true },
563
+ { id: 3, name: 'Team Photo.jpg', path: ['Home', 'Pictures', 'Work'], author: 'Mike Johnson', type: 'JPEG Image', size: 3245, modified: '2023-06-10T11:20:00', isFavorite: false },
564
+ { id: 4, name: 'Meeting Notes.docx', path: ['Home', 'Documents', 'Meetings'], author: 'Sarah Wilson', type: 'Word Document', size: 876, modified: '2023-06-14T16:10:00', isFavorite: false },
565
+ { id: 5, name: 'Presentation.pptx', path: ['Home', 'Documents', 'Presentations'], author: 'David Brown', type: 'PowerPoint', size: 6543, modified: '2023-06-12T13:30:00', isFavorite: false },
566
+ { id: 6, name: 'Project Backup.zip', path: ['Home', 'Downloads'], author: 'Emma Davis', type: 'ZIP Archive', size: 24567, modified: '2023-06-09T18:05:00', isFavorite: false },
567
+ { id: 7, name: 'Interview.mp3', path: ['Home', 'Music', 'Recordings'], author: 'James Miller', type: 'MP3 Audio', size: 12345, modified: '2023-05-30T10:15:00', isFavorite: false },
568
+ { id: 8, name: 'Tutorial.mp4', path: ['Home', 'Videos', 'Learning'], author: 'Olivia Wilson', type: 'MP4 Video', size: 45678, modified: '2023-05-28T14:20:00', isFavorite: false },
569
+ { id: 9, name: 'Configuration.ini', path: ['Home', 'System'], author: 'System', type: 'Configuration File', size: 23, modified: '2023-06-13T12:40:00', isFavorite: false },
570
+ { id: 10, name: 'Code Repository', path: ['Home', 'Documents', 'Projects'], author: 'John Doe', type: 'Folder', size: 10245, modified: '2023-06-05T08:30:00', isFavorite: true }
571
+ ],
572
+
573
+ locationHistory: [],
574
+ historyIndex: -1
575
+ };
576
+
577
+ // Helper functions
578
+ function formatFileSize(bytes) {
579
+ if (bytes === 0) return '0 Bytes';
580
+ if (typeof bytes === 'string') bytes = parseInt(bytes);
581
+
582
+ const k = 1024;
583
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
584
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
585
+
586
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
587
+ }
588
+
589
+ function formatDate(dateString) {
590
+ const date = new Date(dateString);
591
+ return date.toLocaleDateString('en-US', {month: 'short', day: 'numeric'});
592
+ }
593
+
594
+ function formatTime(dateString) {
595
+ const date = new Date(dateString);
596
+ return date.toLocaleTimeString('en-US', {hour: '2-digit', minute: '2-digit'});
597
  }
598
 
599
+ function getFileIcon(file) {
600
+ if (file.type === 'Folder') return 'fas fa-folder folder-icon';
601
 
602
+ const extension = file.name.split('.').pop().toLowerCase();
603
+ const iconMap = {
604
+ 'pdf': 'fas fa-file-pdf file-icon',
605
+ 'docx': 'fas fa-file-word file-icon',
606
+ 'xlsx': 'fas fa-file-excel file-icon',
607
+ 'pptx': 'fas fa-file-powerpoint file-icon',
608
+ 'jpg': 'fas fa-file-image file-icon',
609
+ 'jpeg': 'fas fa-file-image file-icon',
610
+ 'png': 'fas fa-file-image file-icon',
611
+ 'gif': 'fas fa-file-image file-icon',
612
+ 'mp3': 'fas fa-file-audio file-icon',
613
+ 'wav': 'fas fa-file-audio file-icon',
614
+ 'mp4': 'fas fa-file-video file-icon',
615
+ 'mov': 'fas fa-file-video file-icon',
616
+ 'zip': 'fas fa-file-archive file-icon',
617
+ 'rar': 'fas fa-file-archive file-icon',
618
+ 'ini': 'fas fa-file-code file-icon'
619
+ };
620
 
621
+ return iconMap[extension] || 'fas fa-file file-icon';
 
 
622
  }
623
 
624
+ function showToast(message, type = 'success') {
625
+ const toast = document.getElementById('toast');
626
+ const toastIcon = document.getElementById('toastIcon');
627
+ const toastMessage = document.getElementById('toastMessage');
628
+
629
+ // Set icon and color based on type
630
+ if (type === 'success') {
631
+ toastIcon.className = 'fas fa-check-circle mr-2';
632
+ toast.style.backgroundColor = '#4f46e5';
633
+ } else if (type === 'error') {
634
+ toastIcon.className = 'fas fa-exclamation-circle mr-2';
635
+ toast.style.backgroundColor = '#ef4444';
636
+ } else if (type === 'warning') {
637
+ toastIcon.className = 'fas fa-exclamation-triangle mr-2';
638
+ toast.style.backgroundColor = '#f59e0b';
639
+ } else if (type === 'info') {
640
+ toastIcon.className = 'fas fa-info-circle mr-2';
641
+ toast.style.backgroundColor = '#3b82f6';
642
+ }
643
+
644
+ toastMessage.textContent = message;
645
+ toast.classList.add('show');
646
+
647
+ // Hide after 3 seconds
648
+ setTimeout(() => {
649
+ toast.classList.remove('show');
650
+ }, 3000);
651
  }
652
 
653
+ function filterFiles() {
654
+ let files = [...state.files];
655
+ const filters = state.filters;
656
+ const search = state.searchQuery.toLowerCase();
657
+
658
+ // Filter by current location
659
+ files = files.filter(file =>
660
+ JSON.stringify(file.path) === JSON.stringify(state.currentLocation.path)
661
+ );
662
+
663
+ if (search) {
664
+ files = files.filter(file =>
665
+ file.name.toLowerCase().includes(search) ||
666
+ file.type.toLowerCase().includes(search) ||
667
+ (file.author && file.author.toLowerCase().includes(search))
668
+ );
669
+ }
670
+
671
+ if (filters.fileType !== 'all') {
672
+ const typeMap = {
673
+ 'documents': ['PDF Document', 'Word Document', 'Excel Spreadsheet', 'PowerPoint'],
674
+ 'images': ['JPEG Image', 'PNG Image', 'GIF Image'],
675
+ 'audio': ['MP3 Audio', 'WAV Audio'],
676
+ 'video': ['MP4 Video', 'MOV Video'],
677
+ 'archives': ['ZIP Archive', 'RAR Archive'],
678
+ 'folders': ['Folder']
679
+ };
680
 
681
+ const types = typeMap[filters.fileType] || [];
682
+ files = files.filter(file =>
683
+ types.includes(file.type) ||
684
+ (filters.fileType === 'documents' && file.type.includes('Document'))
685
+ );
686
+ }
687
+
688
+ if (filters.author) {
689
+ const authorSearch = filters.author.toLowerCase();
690
+ files = files.filter(file =>
691
+ file.author && file.author.toLowerCase().includes(authorSearch)
692
+ );
693
+ }
694
+
695
+ if (filters.sizeMin || filters.sizeMax) {
696
+ const min = filters.sizeMin ? parseInt(filters.sizeMin) : 0;
697
+ const max = filters.sizeMax ? parseInt(filters.sizeMax) : Infinity;
698
 
699
+ files = files.filter(file => file.size >= min && file.size <= max);
700
+ }
701
+
702
+ if (filters.dateRange && filters.dateRange !== 'all') {
703
+ const now = new Date();
704
+ let fromDate = new Date();
705
 
706
+ switch (filters.dateRange) {
707
+ case 'today':
708
+ fromDate.setHours(0, 0, 0, 0);
709
+ break;
710
+ case 'week':
711
+ fromDate.setDate(fromDate.getDate() - 7);
712
+ break;
713
+ case 'month':
714
+ fromDate.setMonth(fromDate.getMonth() - 1);
715
+ break;
716
+ case 'year':
717
+ fromDate.setFullYear(fromDate.getFullYear() - 1);
718
+ break;
719
+ case 'custom':
720
+ if (filters.dateFrom) {
721
+ fromDate = new Date(filters.dateFrom);
722
+ }
723
+ break;
724
+ }
725
 
726
+ files = files.filter(file => {
727
+ const fileDate = new Date(file.modified);
728
+ return fileDate >= fromDate;
729
+ });
 
 
 
 
 
730
 
731
+ if (filters.dateRange === 'custom' && filters.dateTo) {
732
+ const toDate = new Date(filters.dateTo);
733
+ toDate.setHours(23, 59, 59, 999);
734
+
735
+ files = files.filter(file => {
736
+ const fileDate = new Date(file.modified);
737
+ return fileDate <= toDate;
738
+ });
739
+ }
740
+ }
741
+
742
+ return sortFiles(files);
743
+ }
744
+
745
+ function sortFiles(files) {
746
+ const activeSort = state.activeSort;
747
+ const sortDirection = state.sortDirection;
748
+
749
+ return files.sort((a, b) => {
750
+ let aVal, bVal;
751
 
752
+ switch (activeSort) {
753
+ case 'name':
754
+ aVal = a.name.toLowerCase();
755
+ bVal = b.name.toLowerCase();
756
+ break;
757
+ case 'author':
758
+ aVal = a.author ? a.author.toLowerCase() : '';
759
+ bVal = b.author ? b.author.toLowerCase() : '';
760
+ break;
761
+ case 'type':
762
+ aVal = a.type.toLowerCase();
763
+ bVal = b.type.toLowerCase();
764
+ break;
765
+ case 'size':
766
+ aVal = a.size;
767
+ bVal = b.size;
768
+ break;
769
+ case 'modified':
770
+ aVal = new Date(a.modified);
771
+ bVal = new Date(b.modified);
772
+ break;
773
+ default:
774
+ aVal = a.name.toLowerCase();
775
+ bVal = b.name.toLowerCase();
776
+ }
777
 
778
+ if (aVal < bVal) return sortDirection === 'asc' ? -1 : 1;
779
+ if (aVal > bVal) return sortDirection === 'asc' ? 1 : -1;
780
+ return 0;
 
 
 
 
 
 
 
 
 
781
  });
782
+ }
783
 
784
+ function filterLocations() {
785
+ const search = state.sidebarSearch.toLowerCase();
786
+ return state.locations.filter(loc =>
787
+ loc.name.toLowerCase().includes(search)
788
+ );
789
+ }
790
 
791
+ function updateBreadcrumbs() {
792
+ const breadcrumbs = document.getElementById('breadcrumbs');
793
+ breadcrumbs.innerHTML = '';
794
+
795
+ // Add home breadcrumb
796
+ const homeCrumb = document.createElement('div');
797
+ homeCrumb.className = 'breadcrumb-item';
798
+ homeCrumb.innerHTML = `
799
+ <i class="fas fa-home"></i>
800
+ <span>Home</span>
801
+ `;
802
+ homeCrumb.addEventListener('click', () => {
803
+ const homeLocation = state.locations.find(loc => loc.id === 1);
804
+ selectLocation(homeLocation);
805
+ });
806
+ breadcrumbs.appendChild(homeCrumb);
807
+
808
+ // Add path breadcrumbs
809
+ state.currentLocation.path.forEach((pathItem, index) => {
810
+ const separator = document.createElement('div');
811
+ separator.className = 'breadcrumb-separator';
812
+ separator.innerHTML = '<i class="fas fa-chevron-right"></i>';
813
+ breadcrumbs.appendChild(separator);
814
 
815
+ const crumb = document.createElement('div');
816
+ crumb.className = 'breadcrumb-item';
817
+ crumb.textContent = pathItem;
818
+ crumb.addEventListener('click', () => {
819
+ // Find the location that matches this path
820
+ const targetPath = state.currentLocation.path.slice(0, index + 1);
821
+ const targetLocation = state.locations.find(loc =>
822
+ loc.name === pathItem && JSON.stringify(loc.path) === JSON.stringify(targetPath.slice(0, -1))
823
  );
 
 
 
 
 
 
 
 
 
 
824
 
825
+ if (targetLocation) {
826
+ selectLocation(targetLocation);
827
+ }
828
+ });
829
+ breadcrumbs.appendChild(crumb);
830
+ });
831
+
832
+ // Add current location if it's not home
833
+ if (state.currentLocation.id !== 1) {
834
+ const separator = document.createElement('div');
835
+ separator.className = 'breadcrumb-separator';
836
+ separator.innerHTML = '<i class="fas fa-chevron-right"></i>';
837
+ breadcrumbs.appendChild(separator);
838
 
839
+ const currentCrumb = document.createElement('div');
840
+ currentCrumb.className = 'breadcrumb-item font-medium text-indigo-600';
841
+ currentCrumb.textContent = state.currentLocation.name;
842
+ breadcrumbs.appendChild(currentCrumb);
843
+ }
844
+ }
845
+
846
+ // UI update functions
847
+ function updateSidebar() {
848
+ const sidebarLocations = document.getElementById('sidebarLocations');
849
+ const filteredLocations = filterLocations();
850
+
851
+ sidebarLocations.innerHTML = '';
852
+
853
+ filteredLocations.forEach(location => {
854
+ const locationEl = document.createElement('div');
855
+ locationEl.className = `sidebar-item px-3 py-2.5 rounded-lg cursor-pointer flex items-center transition-all group ${
856
+ state.currentLocation.id === location.id ? 'bg-indigo-50' : ''
857
+ }`;
858
+ locationEl.innerHTML = `
859
+ <div class="w-8 h-8 rounded-md flex items-center justify-center mr-2 ${
860
+ state.currentLocation.id === location.id ? 'bg-indigo-100' : 'bg-slate-100 group-hover:bg-slate-200'
861
+ }">
862
+ <i class="${location.icon} text-slate-600 group-hover:text-slate-800 ${
863
+ state.currentLocation.id === location.id ? 'text-indigo-500' : ''
864
+ }"></i>
865
+ </div>
866
+ <span class="text-sm font-medium truncate ${
867
+ state.currentLocation.id === location.id ? 'text-indigo-600' : 'text-slate-700 group-hover:text-slate-900'
868
+ }">
869
+ ${location.name}
870
+ </span>
871
+ `;
872
+ locationEl.addEventListener('click', () => selectLocation(location));
873
+ sidebarLocations.appendChild(locationEl);
874
+ });
875
+ }
876
+
877
+ function updateFileList() {
878
+ const fileList = document.getElementById('fileList');
879
+ const filteredFiles = filterFiles();
880
+
881
+ if (filteredFiles.length === 0) {
882
+ fileList.innerHTML = `
883
+ <div class="flex flex-col items-center justify-center h-64 text-slate-400">
884
+ <i class="fas fa-folder-open text-5xl mb-4 opacity-30"></i>
885
+ <p class="text-lg font-medium text-slate-500">No files found</p>
886
+ <p class="text-sm mt-1 text-slate-400">Try adjusting your search or filters</p>
887
+ </div>
888
+ `;
889
+ } else {
890
+ fileList.innerHTML = '';
891
 
892
+ filteredFiles.forEach(file => {
893
+ const fileEl = document.createElement('div');
894
+ fileEl.className = `file-row px-5 py-3 border-b border-slate-100 grid grid-cols-12 gap-4 text-sm items-center transition-all ${
895
+ state.selectedFiles.includes(file) ? 'highlight' : ''
896
+ }`;
897
+ fileEl.innerHTML = `
898
+ <div class="col-span-5 flex items-center truncate">
899
+ <input
900
+ type="checkbox"
901
+ class="mr-3 h-4 w-4 text-indigo-600 rounded border-slate-300 focus:ring-indigo-500"
902
+ ${state.selectedFiles.includes(file) ? 'checked' : ''}
903
+ data-file-id="${file.id}"
904
+ >
905
+ <div class="w-8 h-8 rounded-md flex items-center justify-center mr-2 ${
906
+ state.selectedFiles.includes(file) ? 'bg-indigo-50' : 'bg-slate-100'
907
+ }">
908
+ <i class="${getFileIcon(file)} text-slate-600"></i>
909
+ </div>
910
+ <div class="truncate">
911
+ <div class="font-medium text-slate-800 truncate">${file.name}</div>
912
+ <div class="text-xs text-slate-500 truncate">${formatTime(file.modified)}</div>
913
+ </div>
914
+ ${file.isFavorite ? '<i class="fas fa-star text-yellow-400 ml-2 text-xs"></i>' : ''}
915
+ </div>
916
+ <div class="col-span-2 text-slate-600 truncate">
917
+ <span class="inline-flex items-center">
918
+ <i class="fas fa-user-circle mr-2 text-slate-400"></i>
919
+ ${file.author || 'Unknown'}
920
+ </span>
921
+ </div>
922
+ <div class="col-span-2 text-slate-600 truncate text-sm">${file.type}</div>
923
+ <div class="col-span-2 text-slate-600 text-right text-sm">${formatFileSize(file.size)}</div>
924
+ <div class="col-span-1 text-slate-600 text-right text-sm">${formatDate(file.modified)}</div>
925
+ `;
926
 
927
+ // Add event listeners
928
+ const checkbox = fileEl.querySelector('input[type="checkbox"]');
929
+ checkbox.addEventListener('change', (e) => toggleFileSelection(file, e));
 
 
 
930
 
931
+ fileEl.addEventListener('dblclick', () => openFile(file));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
932
 
933
+ // Add context menu
934
+ fileEl.addEventListener('contextmenu', (e) => {
935
+ e.preventDefault();
936
+ showContextMenu(file, e.clientX, e.clientY);
937
  });
938
 
939
+ fileList.appendChild(fileEl);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
940
  });
 
 
941
  }
942
+
943
+ // Update status bar
944
+ document.getElementById('statusCount').textContent =
945
+ state.selectedFiles.length > 0 ?
946
+ `${state.selectedFiles.length} selected of ${filteredFiles.length} items` :
947
+ `${filteredFiles.length} items`;
948
+ }
949
 
950
+ function showContextMenu(file, x, y) {
951
+ const contextMenu = document.getElementById('contextMenu');
952
+ state.contextMenuFile = file;
953
+
954
+ // Update context menu items based on file type
955
+ const favoriteItem = document.getElementById('contextFavorite');
956
+ if (file.isFavorite) {
957
+ favoriteItem.innerHTML = '<i class="fas fa-star"></i> Remove from Favorites';
958
+ } else {
959
+ favoriteItem.innerHTML = '<i class="fas fa-star"></i> Add to Favorites';
960
  }
961
+
962
+ // Position the menu
963
+ contextMenu.style.left = `${x}px`;
964
+ contextMenu.style.top = `${y}px`;
965
+ contextMenu.style.display = 'block';
966
+
967
+ // Close menu when clicking elsewhere
968
+ const closeMenu = () => {
969
+ contextMenu.style.display = 'none';
970
+ document.removeEventListener('click', closeMenu);
971
+ };
972
+
973
+ setTimeout(() => {
974
+ document.addEventListener('click', closeMenu);
975
+ }, 100);
976
+ }
977
 
978
+ function updateSortIcons() {
979
+ // Reset all icons
980
+ document.getElementById('nameSortIcon').className = 'fas ml-1 fa-sort';
981
+ document.getElementById('authorSortIcon').className = 'fas ml-1 fa-sort';
982
+ document.getElementById('typeSortIcon').className = 'fas ml-1 fa-sort';
983
+ document.getElementById('sizeSortIcon').className = 'fas ml-1 fa-sort';
984
+ document.getElementById('modifiedSortIcon').className = 'fas ml-1 fa-sort';
985
+
986
+ // Set active sort icon
987
+ const activeIcon = document.getElementById(`${state.activeSort}SortIcon`);
988
+ if (activeIcon) {
989
+ activeIcon.className = `fas ml-1 fa-sort-${state.sortDirection === 'asc' ? 'up' : 'down'}`;
990
  }
991
+ }
992
 
993
+ function updateDeleteButton() {
994
+ const deleteBtnContainer = document.getElementById('deleteBtnContainer');
995
+ const selectedCount = document.getElementById('selectedCount');
996
+
997
+ if (state.selectedFiles.length > 0) {
998
+ deleteBtnContainer.style.display = 'block';
999
+ selectedCount.textContent = state.selectedFiles.length;
1000
+ } else {
1001
+ deleteBtnContainer.style.display = 'none';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1002
  }
1003
+ }
1004
 
1005
+ function updateSelectAllCheckbox() {
1006
+ const selectAllCheckbox = document.getElementById('selectAllCheckbox');
1007
+ const filteredFiles = filterFiles();
1008
+
1009
+ selectAllCheckbox.checked =
1010
+ state.selectedFiles.length === filteredFiles.length &&
1011
+ filteredFiles.length > 0;
1012
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
1013
 
1014
+ // Core functions
1015
+ function selectLocation(location) {
1016
+ // Add to history
1017
+ if (state.historyIndex === -1 ||
1018
+ JSON.stringify(state.locationHistory[state.historyIndex]) !== JSON.stringify(location)) {
1019
 
1020
+ // If we're not at the end of history, truncate the future
1021
+ if (state.historyIndex < state.locationHistory.length - 1) {
1022
+ state.locationHistory = state.locationHistory.slice(0, state.historyIndex + 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1023
  }
1024
+
1025
+ state.locationHistory.push({...location});
1026
+ state.historyIndex = state.locationHistory.length - 1;
1027
  }
1028
+
1029
+ state.currentLocation = location;
1030
+ state.searchQuery = '';
1031
+ state.selectedFiles = [];
1032
+ updateFileList();
1033
+ updateDeleteButton();
1034
+ updateSelectAllCheckbox();
1035
+ updateBreadcrumbs();
1036
+
1037
+ // Update back button state
1038
+ updateBackForwardButtons();
1039
+ }
1040
 
1041
+ function navigateBack() {
1042
+ if (state.historyIndex > 0) {
1043
+ state.historyIndex--;
1044
+ state.currentLocation = {...state.locationHistory[state.historyIndex]};
1045
+ updateFileList();
1046
+ updateDeleteButton();
1047
+ updateSelectAllCheckbox();
1048
+ updateBreadcrumbs();
1049
+ updateBackForwardButtons();
1050
  }
1051
+ }
1052
 
1053
+ function navigateForward() {
1054
+ if (state.historyIndex < state.locationHistory.length - 1) {
1055
+ state.historyIndex++;
1056
+ state.currentLocation = {...state.locationHistory[state.historyIndex]};
1057
+ updateFileList();
1058
+ updateDeleteButton();
1059
+ updateSelectAllCheckbox();
1060
+ updateBreadcrumbs();
1061
+ updateBackForwardButtons();
1062
  }
1063
+ }
1064
 
1065
+ function updateBackForwardButtons() {
1066
+ const backBtn = document.getElementById('backBtn');
1067
+ const forwardBtn = document.getElementById('forwardBtn');
1068
+
1069
+ if (state.historyIndex > 0) {
1070
+ backBtn.disabled = false;
1071
+ backBtn.classList.remove('opacity-50', 'cursor-not-allowed');
1072
+ } else {
1073
+ backBtn.disabled = true;
1074
+ backBtn.classList.add('opacity-50', 'cursor-not-allowed');
1075
  }
1076
+
1077
+ if (state.historyIndex < state.locationHistory.length - 1) {
1078
+ forwardBtn.disabled = false;
1079
+ forwardBtn.classList.remove('opacity-50', 'cursor-not-allowed');
1080
+ } else {
1081
+ forwardBtn.disabled = true;
1082
+ forwardBtn.classList.add('opacity-50', 'cursor-not-allowed');
1083
+ }
1084
+ }
1085
 
1086
+ function toggleIndexing() {
1087
+ state.isIndexing = !state.isIndexing;
1088
+
1089
+ const indexBtn = document.getElementById('indexBtn');
1090
+ const indexBtnText = document.getElementById('indexBtnText');
1091
+ const indexStatus = document.getElementById('indexStatus');
1092
+
1093
+ if (state.isIndexing) {
1094
+ indexBtn.classList.add('glow');
1095
+ indexBtnText.textContent = 'Indexing...';
1096
+ indexStatus.innerHTML = '<span class="text-indigo-600 font-medium flex items-center"><span class="w-2 h-2 rounded-full bg-indigo-500 mr-1.5 animate-pulse"></span>Running</span>';
1097
+
1098
+ let count = state.indexedCount;
1099
+ const interval = setInterval(() => {
1100
+ count += Math.floor(Math.random() * 10);
1101
+ document.getElementById('indexedCount').textContent = count;
1102
+ document.getElementById('lastIndexed').textContent = 'Just now';
1103
+
1104
+ if (!state.isIndexing) {
1105
+ clearInterval(interval);
1106
  }
1107
+ }, 3000);
1108
+
1109
+ setTimeout(() => {
1110
+ if (Math.random() > 0.7) {
1111
+ state.isIndexing = false;
1112
+ indexBtn.classList.remove('glow');
1113
+ indexBtnText.textContent = 'Index Now';
1114
+ indexStatus.textContent = 'Idle';
1115
+ showToast('Indexing completed successfully', 'success');
1116
+ }
1117
+ }, 15000);
1118
+ } else {
1119
+ indexBtn.classList.remove('glow');
1120
+ indexBtnText.textContent = 'Index Now';
1121
+ indexStatus.textContent = 'Idle';
1122
  }
1123
+ }
1124
 
1125
+ function refreshFiles() {
1126
+ state.performanceRating = ['fast', 'normal', 'slow'][Math.floor(Math.random() * 3)];
1127
+
1128
+ const performanceIcon = document.getElementById('performanceIcon');
1129
+ const performanceText = document.getElementById('performanceText');
1130
+
1131
+ performanceText.textContent = `${state.performanceRating} performance`;
1132
+
1133
+ if (state.performanceRating === 'fast') {
1134
+ performanceIcon.className = 'fas fa-circle text-xs mr-1.5 text-emerald-500';
1135
+ } else if (state.performanceRating === 'normal') {
1136
+ performanceIcon.className = 'fas fa-circle text-xs mr-1.5 text-amber-500';
1137
+ } else {
1138
+ performanceIcon.className = 'fas fa-circle text-xs mr-1.5 text-rose-500';
1139
+ }
1140
+
1141
+ if (Math.random() > 0.7) {
1142
+ const newFiles = [...state.files];
1143
+ if (newFiles.length > 5 && Math.random() > 0.5) {
1144
+ newFiles.splice(Math.floor(Math.random() * newFiles.length), 1);
1145
  } else {
1146
+ const authors = ['John Doe', 'Jane Smith', 'Mike Johnson', 'Sarah Wilson', 'Emma Davis'];
1147
+ const newFile = {
1148
+ id: Math.max(...newFiles.map(f => f.id)) + 1,
1149
+ name: ['New Document.docx', 'Report.pdf', 'Image.jpg', 'Archive.zip', 'Data.xlsx'][Math.floor(Math.random() * 5)],
1150
+ path: [...state.currentLocation.path],
1151
+ author: authors[Math.floor(Math.random() * authors.length)],
1152
+ type: ['PDF Document', 'Word Document', 'Excel Spreadsheet', 'JPEG Image', 'ZIP Archive'][Math.floor(Math.random() * 5)],
1153
+ size: Math.floor(Math.random() * 10000),
1154
+ modified: new Date().toISOString(),
1155
+ isFavorite: Math.random() > 0.8
1156
+ };
1157
+ newFiles.push(newFile);
1158
  }
1159
+ state.files = newFiles;
1160
+ updateFileList();
1161
+ showToast('Files refreshed', 'success');
1162
+ } else {
1163
+ showToast('Files are up to date', 'info');
1164
  }
1165
+ }
1166
 
1167
+ function sortBy(column) {
1168
+ if (state.activeSort === column) {
1169
+ state.sortDirection = state.sortDirection === 'asc' ? 'desc' : 'asc';
1170
+ } else {
1171
+ state.activeSort = column;
1172
+ state.sortDirection = 'asc';
 
 
 
 
 
 
 
 
1173
  }
 
 
 
1174
 
1175
+ updateSortIcons();
1176
+ updateFileList();
1177
+ }
1178
+
1179
+ function toggleSelectAll(e) {
1180
+ const allFiles = filterFiles();
1181
+ if (e.target.checked) {
1182
+ state.selectedFiles = [...allFiles];
1183
+ } else {
1184
+ state.selectedFiles = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1185
  }
1186
+
1187
+ updateFileList();
1188
+ updateDeleteButton();
1189
+ }
1190
 
1191
+ function toggleFileSelection(file, e) {
1192
+ if (e.target.checked) {
1193
+ state.selectedFiles.push(file);
1194
+ } else {
1195
+ const index = state.selectedFiles.findIndex(f => f.id === file.id);
1196
+ if (index !== -1) {
1197
+ state.selectedFiles.splice(index, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1198
  }
1199
  }
 
 
 
1200
 
1201
+ updateDeleteButton();
1202
+ updateSelectAllCheckbox();
1203
+ }
1204
+
1205
+ function openFile(file) {
1206
+ if (file.type === 'Folder') {
1207
+ // Navigate to folder
1208
+ const newLocation = {
1209
+ id: Date.now(),
1210
+ name
1211
  </html>