├── LICENSE ├── README.md ├── add-files-concept-illustration ├── 2808347.ai ├── 2808348.eps ├── 2808349.jpg ├── License free.txt └── License premium.txt ├── favicon.ico ├── filemanager.js ├── index.html └── screenshots └── ss1.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 AdDev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # File Manager App 2 | 3 | This is a simple file manager app built using HTML, CSS, and JavaScript. It allows users to perform basic file and folder operations like adding new files/folders, renaming, and deleting. 4 | 5 | ## Features 6 | 7 | - Add new files and folders: Users can create new files and folders by providing a name and selecting the desired location. 8 | - Rename files and folders: Users can rename existing files and folders by selecting the item and entering a new name. 9 | - Delete files and folders: Users can delete files and folders by selecting the item and confirming the deletion. 10 | 11 | ## Usage 12 | 13 | To use the file manager app, follow these steps: 14 | 15 | 1. Clone the repository: `git clone https://github.com/addevin/filemanager.git` 16 | 2. Open the project folder. 17 | 3. Launch the app by opening the `index.html` file in your web browser. 18 | 19 | ## Screenshots 20 | 21 | 22 | ![Screenshot 1](screenshots/ss1.png) 23 | _Example of the file manager interface._ 24 | [Visit now](https://addevin.github.io/filemanager/) 25 | ## Contributing 26 | 27 | Contributions are welcome! If you find any bugs or want to add new features, feel free to submit an issue or a pull request. 28 | 29 | ## License 30 | 31 | This project is licensed under the MIT License. You can find more details in the [LICENSE](LICENSE) file. 32 | 33 | -------------------------------------------------------------------------------- /add-files-concept-illustration/2808347.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addevin/filemanager/abdc1ac40e870efd9540839085dceea5fbcafe55/add-files-concept-illustration/2808347.ai -------------------------------------------------------------------------------- /add-files-concept-illustration/2808348.eps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addevin/filemanager/abdc1ac40e870efd9540839085dceea5fbcafe55/add-files-concept-illustration/2808348.eps -------------------------------------------------------------------------------- /add-files-concept-illustration/2808349.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addevin/filemanager/abdc1ac40e870efd9540839085dceea5fbcafe55/add-files-concept-illustration/2808349.jpg -------------------------------------------------------------------------------- /add-files-concept-illustration/License free.txt: -------------------------------------------------------------------------------- 1 | IMPORTANT NOTICE: This license only applies if you downloaded this content as 2 | an unsubscribed user. If you are a premium user (ie, you pay a subscription) 3 | you are bound to the license terms described in the accompanying file 4 | "License premium.txt". 5 | 6 | --------------------- 7 | 8 | You must attribute the image to its author: 9 | 10 | In order to use a content or a part of it, you must attribute it to slidesgo / Freepik, 11 | so we will be able to continue creating new graphic resources every day. 12 | 13 | 14 | How to attribute it? 15 | 16 | For websites: 17 | 18 | Please, copy this code on your website to accredit the author: 19 | Designed by slidesgo / Freepik 20 | 21 | For printing: 22 | 23 | Paste this text on the final work so the authorship is known. 24 | - For example, in the acknowledgements chapter of a book: 25 | "Designed by slidesgo / Freepik" 26 | 27 | 28 | You are free to use this image: 29 | 30 | - For both personal and commercial projects and to modify it. 31 | - In a website or presentation template or application or as part of your design. 32 | 33 | You are not allowed to: 34 | 35 | - Sub-license, resell or rent it. 36 | - Include it in any online or offline archive or database. 37 | 38 | The full terms of the license are described in section 7 of the Freepik 39 | terms of use, available online in the following link: 40 | 41 | http://www.freepik.com/terms_of_use 42 | 43 | The terms described in the above link have precedence over the terms described 44 | in the present document. In case of disagreement, the Freepik Terms of Use 45 | will prevail. 46 | -------------------------------------------------------------------------------- /add-files-concept-illustration/License premium.txt: -------------------------------------------------------------------------------- 1 | IMPORTANT NOTICE: This license only applies if you downloaded this content as 2 | a subscribed (or "premium") user. If you are an unsubscribed user (or "free" 3 | user) you are bound to the license terms described in the accompanying file 4 | "License free.txt". 5 | 6 | --------------------- 7 | 8 | You can download from your profile in Freepik a personalized license stating 9 | your right to use this content as a "premium" user: 10 | 11 | https://profile.freepik.com/my_downloads 12 | 13 | You are free to use this image: 14 | 15 | - For both personal and commercial projects and to modify it. 16 | - In a website or presentation template or application or as part of your design. 17 | 18 | You are not allowed to: 19 | 20 | - Sub-license, resell or rent it. 21 | - Include it in any online or offline archive or database. 22 | 23 | The full terms of the license are described in sections 7 and 8 of the Freepik 24 | terms of use, available online in the following link: 25 | 26 | http://www.freepik.com/terms_of_use 27 | 28 | The terms described in the above link have precedence over the terms described 29 | in the present document. In case of disagreement, the Freepik Terms of Use 30 | will prevail. 31 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addevin/filemanager/abdc1ac40e870efd9540839085dceea5fbcafe55/favicon.ico -------------------------------------------------------------------------------- /filemanager.js: -------------------------------------------------------------------------------- 1 | let fileSystemTree =[ 2 | { 3 | isDirectory: true, 4 | name: 'Test folder', 5 | child: [ 6 | { 7 | isDirectory: false, 8 | name: 'text.txt', 9 | } 10 | ] 11 | }, 12 | { 13 | isDirectory: false, 14 | name: 'index.html', 15 | }, 16 | { 17 | isDirectory: false, 18 | name: 'index.php', 19 | }, 20 | { 21 | isDirectory: false, 22 | name: 'textfile.txt', 23 | }, 24 | { 25 | isDirectory: false, 26 | name: 'textfile.exe', 27 | }, 28 | // 50 additional files and folders 29 | { 30 | isDirectory: true, 31 | name: 'Folder A', 32 | child: [ 33 | { 34 | isDirectory: false, 35 | name: 'fileA1.txt', 36 | }, 37 | { 38 | isDirectory: false, 39 | name: 'fileA2.js', 40 | }, 41 | { 42 | isDirectory: true, 43 | name: 'Subfolder A', 44 | child: [ 45 | { 46 | isDirectory: false, 47 | name: 'fileA3.css', 48 | }, 49 | // Add more files or folders here as needed 50 | ] 51 | }, 52 | // Add more files or folders here as needed 53 | ] 54 | }, 55 | { 56 | isDirectory: false, 57 | name: 'fileB1.html', 58 | }, 59 | { 60 | isDirectory: true, 61 | name: 'Folder B', 62 | child: [ 63 | { 64 | isDirectory: false, 65 | name: 'fileB2.php', 66 | }, 67 | // Add more files or folders here as needed 68 | ] 69 | }, 70 | // Add more files or folder''s here as needed 71 | ]; 72 | 73 | class HistoryStack{ 74 | #items; 75 | constructor(){ 76 | this.#items = [] 77 | } 78 | push(item){ 79 | this.#items.push(item) 80 | } 81 | pop(){ 82 | return this.#items.pop() 83 | } 84 | peek(){ 85 | return this.#items[this.#items.length - 1] 86 | } 87 | isEmpty(){ 88 | return this.#items.length === 0 89 | } 90 | size(){ 91 | return this.#items.length 92 | } 93 | print(){ 94 | console.log(this.#items.join(', ')) 95 | } 96 | } 97 | let prePaths = new HistoryStack() 98 | let forPaths = new HistoryStack() 99 | let fileSystem = fileSystemTree; 100 | let selected_item = { 101 | item:{}, 102 | index:0 103 | }; 104 | initFileManager('root/'); 105 | function initFileManager(path,config={keepHistory:true,callback:resetContextMenu}){ 106 | document.querySelector('.folder-path-input').value = path; 107 | if(config.keepHistory)prePaths.push(path) 108 | let fileSys = JSON.parse(JSON.stringify(fileSystem)); 109 | let pathArr = path.split('/') 110 | if((pathArr[0]!='root')) return newToast('error','404 | Path doesn\'t exist!',(close)=>setTimeout(()=>close(),5000)) 111 | let flag = 0; 112 | for (let i = 1; i < pathArr.length; i++) { 113 | if(pathArr[i]){ 114 | for (const folder in fileSys) { 115 | if(fileSys[folder].name == pathArr[i]){ 116 | fileSys = fileSys[folder].child; 117 | flag++; 118 | break; 119 | } 120 | } 121 | } 122 | } 123 | if((pathArr.length-(pathArr[pathArr.length-1]?1:2)!=flag)) return newToast('error','404 | Path doesn\'t exist!',(close)=>setTimeout(()=>close(),5000)) 124 | document.querySelector('.folderEmpty').style.display=(fileSys.length?'none':'block') 125 | setupFilemanager(fileSys) 126 | if(config.callback)config.callback(); 127 | } 128 | function newItem(config={isDirectory:true,name:'unknown'}){ 129 | let path= document.querySelector('.folder-path-input').value; 130 | if(!(path && config.name)) return newToast('error','Please fill out the name field!',(close)=>setTimeout(()=>close(),5000)) 131 | let fileSys = fileSystem; 132 | let pathArr = path.split('/') 133 | for (let i = 1; i < pathArr.length; i++) { 134 | if(pathArr[i]){ 135 | for (const folder in fileSys) { 136 | if(fileSys[folder].name == pathArr[i]){ 137 | fileSys = fileSys[folder].child; 138 | break; 139 | } 140 | } 141 | } 142 | } 143 | if(config.isDirectory){ 144 | fileSys.push({ 145 | isDirectory: true, 146 | name: config.name, 147 | child: [] 148 | }) 149 | }else{ 150 | fileSys.push({ 151 | isDirectory: false, 152 | name: config.name, 153 | }) 154 | } 155 | initFileManager(path,{keepHistory:false}) 156 | newToast('success','Saved new '+(config.isDirectory?'folder':'file')+' "'+config.name+'"!',(close)=>setTimeout(()=>close(),5000)) 157 | } 158 | function renameItem(newName){ 159 | if(selected_item.item?.name){ 160 | let path= document.querySelector('.folder-path-input').value; 161 | let pathArr = path.split('/') 162 | let fileSys = fileSystem; 163 | for (let i = 1; i < pathArr.length; i++) { 164 | if(pathArr[i]){ 165 | for (const folder in fileSys) { 166 | if(fileSys[folder].name == pathArr[i]){ 167 | fileSys = fileSys[folder].child; 168 | break; 169 | } 170 | } 171 | } 172 | } 173 | fileSys[selected_item.index].name=newName; 174 | newToast('success','Changed file name into '+selected_item.item.name+'!',(remove)=>{ 175 | setTimeout(() => { 176 | remove() 177 | }, 6000); 178 | }) 179 | initFileManager(path,{keepHistory:false}) 180 | } 181 | } 182 | function deleteItem(){ 183 | if(selected_item.item?.name){ 184 | let path= document.querySelector('.folder-path-input').value; 185 | let pathArr = path.split('/') 186 | let fileSys = fileSystem; 187 | for (let i = 1; i < pathArr.length; i++) { 188 | if(pathArr[i]){ 189 | for (const folder in fileSys) { 190 | if(fileSys[folder].name == pathArr[i]){ 191 | fileSys = fileSys[folder].child; 192 | break; 193 | } 194 | } 195 | } 196 | } 197 | newToast('success',`Deleted ${selected_item.item.isDirectory?'folder':'file'} "${selected_item.item.name}"!`,(remove)=>{ 198 | setTimeout(() => { 199 | remove() 200 | }, 6000); 201 | }) 202 | fileSys.splice(selected_item.index,1); 203 | initFileManager(path,{keepHistory:false}) 204 | } 205 | } 206 | function setupFilemanager(fileSystem){ 207 | filesContainer = document.querySelector('.filemanager-container-row'); 208 | filesContainer.innerHTML = '' 209 | resetHistoryBtn() 210 | for (const fileItem in fileSystem) { 211 | let div = document.createElement("div") 212 | div.setAttribute('title',fileSystem[fileItem].name) 213 | if(fileSystem[fileItem].isDirectory){ 214 | div.classList.add('folder') 215 | div.addEventListener('dblclick',(e)=>{ 216 | let toPath=document.querySelector('.folder-path-input').value+fileSystem[fileItem].name 217 | initFileManager(toPath+'/'); 218 | }) 219 | div.innerHTML += ` 220 |
221 |
222 |
223 |

${fileSystem[fileItem].name}

224 | ` 225 | }else{ 226 | // div.addEventListener('dblclick',(e)=>{}) 227 | div.classList.add('file') 228 | let fileIcon = getFileIconMeta(fileSystem[fileItem]) 229 | div.innerHTML += ` 230 |
231 |

${fileIcon.ext}

232 |
233 |

${fileSystem[fileItem].name}

234 | ` 235 | } 236 | filesContainer.appendChild(div) 237 | div.addEventListener('click',(e)=>{ 238 | // selected_item=document.querySelector('.folder-path-input').value+fileSystem[fileItem].name 239 | selected_item.index=fileItem; 240 | selected_item.item=fileSystem[fileItem]; 241 | document.querySelector('.item-selected')?.classList.remove('item-selected') 242 | div.classList.add('item-selected') 243 | }) 244 | } 245 | } 246 | function getFileIconMeta(file){ 247 | let ext = file.name.split('.')[file.name.split('.').length-1]; 248 | let color = '116, 116, 116' 249 | switch (ext) { 250 | case 'txt': 251 | color = '36, 230, 149' 252 | break; 253 | 254 | case 'html': 255 | color = '36, 230, 149' 256 | break; 257 | 258 | case 'php': 259 | color = '108, 74, 201' 260 | break; 261 | 262 | case 'zip': 263 | color = '190, 173, 16' 264 | break; 265 | 266 | case 'svg': 267 | color = '36, 230, 149' 268 | break; 269 | 270 | default: 271 | ext = '.?' 272 | break; 273 | } 274 | return {ext:ext.toUpperCase(),color} 275 | } 276 | 277 | function backward(){ 278 | if(!prePaths.isEmpty()){ 279 | let currPath = prePaths.pop() 280 | forPaths.push(currPath) 281 | initFileManager(prePaths.peek(),{keepHistory:false}) 282 | } 283 | } 284 | function forward(){ 285 | if(!forPaths.isEmpty()){ 286 | let currPath = forPaths.pop() 287 | prePaths.push(currPath) 288 | initFileManager(currPath,{keepHistory:false}) 289 | } 290 | } 291 | function resetHistoryBtn(){ 292 | if((prePaths.size()-1)==0){ 293 | document.getElementById('backwardBtn').setAttribute('disabled',true) 294 | }else{ 295 | document.getElementById('backwardBtn').removeAttribute('disabled') 296 | } 297 | if(forPaths.isEmpty()){ 298 | document.getElementById('forwardBtn').setAttribute('disabled',true) 299 | }else{ 300 | document.getElementById('forwardBtn').removeAttribute('disabled') 301 | } 302 | } 303 | 304 | function openModel(modelFor){ //'newFile' 305 | document.querySelector('.popup').style.display='flex' 306 | document.querySelector('.popup >.popup-bg').addEventListener('click',()=>document.querySelector('.popup').style.display='none') 307 | if(modelFor=='newFile'){ 308 | document.querySelector('.popup h1').innerHTML = 'New file' 309 | let input = document.createElement('input') 310 | input.setAttribute('type','text') 311 | input.setAttribute('placeholder','Filename') 312 | let saveButton = document.createElement('button') 313 | saveButton.style = 'background-color: rgb(1, 158, 111);'; 314 | saveButton.innerHTML = 'Save'; 315 | document.querySelector('.popup form').innerHTML = '' 316 | document.querySelector('.popup form').appendChild(input); 317 | document.querySelector('.popup form').appendChild(saveButton); 318 | saveButton.addEventListener('click',()=>{ 319 | newItem(config={isDirectory:false,name:input.value}); 320 | document.querySelector('.popup').style.display='none' 321 | }) 322 | } 323 | if(modelFor=='newFolder'){ 324 | document.querySelector('.popup h1').innerHTML = 'New Folder' 325 | let input = document.createElement('input') 326 | input.setAttribute('type','text') 327 | input.setAttribute('placeholder','Foldername') 328 | let saveButton = document.createElement('button') 329 | saveButton.style = 'background-color: rgb(1, 158, 111);'; 330 | saveButton.innerHTML = 'Save'; 331 | document.querySelector('.popup form').innerHTML = '' 332 | document.querySelector('.popup form').appendChild(input); 333 | document.querySelector('.popup form').appendChild(saveButton); 334 | saveButton.addEventListener('click',()=>{ 335 | newItem(config={isDirectory:true,name:input.value}); 336 | document.querySelector('.popup').style.display='none' 337 | }) 338 | } 339 | if(modelFor=='rename'){ 340 | if(selected_item.item?.name){ 341 | 342 | document.querySelector('.popup h1').innerHTML = 'Rename' 343 | let input = document.createElement('input') 344 | input.setAttribute('type','text') 345 | input.setAttribute('placeholder',(selected_item.item.isDirectory?'Folder':'File')+' name ('+selected_item.item.name+')') 346 | input.value = selected_item.item.name; 347 | let saveButton = document.createElement('button') 348 | saveButton.style = 'background-color: rgb(1, 158, 111);'; 349 | saveButton.innerHTML = 'Save'; 350 | document.querySelector('.popup form').innerHTML = '' 351 | document.querySelector('.popup form').appendChild(input); 352 | document.querySelector('.popup form').appendChild(saveButton); 353 | saveButton.addEventListener('click',()=>{ 354 | renameItem(input.value); 355 | document.querySelector('.popup').style.display='none' 356 | }) 357 | }else{ 358 | document.querySelector('.popup').style.display='none' 359 | newToast('error','Please select a File or Folder which you want to rename!',(remove)=>{ 360 | setTimeout(() => { 361 | remove() 362 | }, 6000); 363 | }) 364 | } 365 | } 366 | if(modelFor=='delete'){ 367 | if(selected_item.item?.name){ 368 | 369 | document.querySelector('.popup h1').innerHTML = 'Sure to delete?' 370 | let saveButton = document.createElement('button') 371 | let cancelButton = document.createElement('button') 372 | saveButton.style = 'background-color: rgb(1, 158, 111);'; 373 | saveButton.innerHTML = 'Yes'; 374 | cancelButton.innerHTML = 'Cancel'; 375 | document.querySelector('.popup form').innerHTML = '' 376 | // document.querySelector('.popup form').appendChild(input); 377 | document.querySelector('.popup form').appendChild(saveButton); 378 | document.querySelector('.popup form').appendChild(cancelButton); 379 | saveButton.focus() 380 | saveButton.addEventListener('click',()=>{ 381 | deleteItem(); 382 | document.querySelector('.popup').style.display='none' 383 | }) 384 | cancelButton.addEventListener('click',()=>{ 385 | document.querySelector('.popup').style.display='none' 386 | }) 387 | }else{ 388 | document.querySelector('.popup').style.display='none' 389 | newToast('error','Please select a File or Folder which you want to delete!',(remove)=>{ 390 | setTimeout(() => { 391 | remove() 392 | }, 6000); 393 | }) 394 | } 395 | } 396 | } 397 | 398 | function newToast(sts,message,cb){ 399 | sts = (sts=='success'?'toast-sccess':(sts=='error'?'toast-dnger':'toast-inf')); 400 | let tContainer = document.querySelector('.toast-messages') 401 | let c = document.createElement('div') 402 | let bc = document.createElement('div') 403 | let p = document.createElement('p') 404 | let b = document.createElement('button') 405 | c.classList.add('toast-container',sts) 406 | // c.setAttribute('id','sjdfnksjdfn'); 407 | p.innerText = message; 408 | b.innerHTML = ''; 409 | b.addEventListener('click',removeToast); 410 | c.appendChild(p) 411 | bc.appendChild(b) 412 | c.appendChild(bc) 413 | tContainer.prepend(c) 414 | setTimeout(() => { 415 | c.style.opacity = '1' 416 | }, 300); 417 | function removeToast(){ 418 | c.style = ` 419 | opacity:0; 420 | ` 421 | setTimeout(() => { 422 | c.remove() 423 | }, 500); 424 | } 425 | if(cb)cb(removeToast); 426 | } 427 | 428 | newToast('info','Welcome: in testing mode...',(remove)=>{ 429 | setTimeout(() => { 430 | remove() 431 | }, 10000); 432 | }) 433 | window.addEventListener('focus',()=>{ 434 | 435 | newToast('info','Welcome back!',(remove)=>{ 436 | setTimeout(() => { 437 | remove() 438 | }, 3000); 439 | }) 440 | }) 441 | window.addEventListener('blur',(e)=>{ 442 | newToast('info','Seems you gone!',(remove)=>{ 443 | e.target.addEventListener('focus',()=>{ 444 | setTimeout(() => { 445 | remove() 446 | }, 1200); 447 | }) 448 | }) 449 | }) 450 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Filemanager | AdDev 9 | 10 | 293 | 294 | 295 |
296 |
297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 |
305 |
306 |
307 | 308 | 309 | 310 |
311 |
312 | 313 | 316 | 317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |

A folder ikjsnf ijsd kjndk jn

325 |
326 |
327 |
328 |
329 |
330 |

A folder ikjsnf ijsd kjndk jn

331 |
332 |
333 |
334 |
335 |
336 |

A folder ikjsnf ijsd kjndk jn

337 |
338 |
339 |
340 |
341 |
342 |

test folder

343 |
344 |
345 |
346 |
347 |
348 |

A folder ikjsnf ijsd kjndk jn

349 |
350 | 351 |
352 |
353 |
354 |
355 |

folder 1

356 |
357 |
358 |
359 |
360 |
361 |

folder 2

362 |
363 |
364 |
365 |
366 |
367 |

folder 3

368 |
369 |
370 |
371 |
372 |
373 |

folder 4

374 |
375 |
376 |
377 |
378 |
379 |

folder 10

380 |
381 |
382 |
383 |
384 |
385 |

folder 11

386 |
387 |
388 |
389 |
390 |
391 |

folder 12

392 |
393 |
394 |
395 |
396 |
397 |

folder 13

398 |
399 |
400 |
401 |
402 |
403 |

folder 14

404 |
405 |
406 |
407 |
408 |
409 |

folder 15

410 |
411 |
412 |
413 | 417 |
418 |

image.jpg

419 |
420 |
421 |
422 |

PDF

423 |
424 |

documt.pdf

425 |
426 |
427 |
428 |

TXT

429 |
430 |

text.txt

431 |
432 |
433 |
434 |

.?

435 |
436 |

file.unknown

437 |
438 |
439 |
440 |

ZIP

441 |
442 |

file.zip

443 |
444 |
445 |
446 |

SVG

447 |
448 |

image.svg

449 |
450 |
451 |
452 |

.?

453 |
454 |

file.unknown

455 |
456 |
457 |
458 |

ZIP

459 |
460 |

file.zip

461 |
462 |
463 |
464 |

SVG

465 |
466 |

image.svg

467 |
468 |
469 |
470 |
471 | 472 |
Folder is empty!
473 |
474 | 475 | 486 | 497 |
498 | 499 |
500 | 647 | 690 | 691 | 692 | 693 | -------------------------------------------------------------------------------- /screenshots/ss1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addevin/filemanager/abdc1ac40e870efd9540839085dceea5fbcafe55/screenshots/ss1.png --------------------------------------------------------------------------------