Spaces:
Running
Running
Add 1 files
Browse files- index.html +280 -1
index.html
CHANGED
@@ -67,6 +67,12 @@
|
|
67 |
::-webkit-scrollbar-thumb:hover {
|
68 |
background: #94a3b8;
|
69 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
</style>
|
71 |
</head>
|
72 |
<body class="bg-slate-50">
|
@@ -751,5 +757,278 @@
|
|
751 |
const newFile = {
|
752 |
id: Math.max(...newFiles.map(f => f.id)) + 1,
|
753 |
name: ['New Document.docx', 'Report.pdf', 'Image.jpg', 'Archive.zip', 'Data.xlsx'][Math.floor(Math.random() * 5)],
|
754 |
-
path: ['Documents', 'Downloads', 'Pictures', 'Music', 'Videos'][Math.floor(Math
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
755 |
</html>
|
|
|
67 |
::-webkit-scrollbar-thumb:hover {
|
68 |
background: #94a3b8;
|
69 |
}
|
70 |
+
.modal-enter-active, .modal-leave-active {
|
71 |
+
transition: opacity 0.3s ease;
|
72 |
+
}
|
73 |
+
.modal-enter-from, .modal-leave-to {
|
74 |
+
opacity: 0;
|
75 |
+
}
|
76 |
</style>
|
77 |
</head>
|
78 |
<body class="bg-slate-50">
|
|
|
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>
|