Skip to content

Commit 8f7cb21

Browse files
committed
feat: Implement drag and drop functionality for folder selection and enhance UI with drag-drop zone
1 parent 84516e9 commit 8f7cb21

File tree

4 files changed

+166
-5
lines changed

4 files changed

+166
-5
lines changed

index.html

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,20 @@ <h3>EXPLORER</h3>
8383
<small class="search-meta" id="searchMeta">Search file and folder names (case-insensitive)</small>
8484
</div>
8585

86-
<div class="sidebar-select">
87-
<button class="btn-select-dir" id="selectDirBtn">
88-
<img src="public/folder.svg" alt="Select Directory" class="sidebar-btn-icon" />
89-
Select Directory
90-
</button>
86+
<div class="drag-drop-zone" id="dragDropZone">
87+
<div class="drag-drop-content">
88+
<span class="material-symbols-outlined drag-drop-icon">folder_open</span>
89+
<h4>Drag & Drop Folder Here</h4>
90+
<p>or</p>
91+
<button class="btn-select-dir" id="selectDirBtn">
92+
<img src="public/folder.svg" alt="Select Directory" class="sidebar-btn-icon" />
93+
Browse Folder
94+
</button>
95+
</div>
96+
<div class="drag-drop-overlay" id="dragDropOverlay">
97+
<span class="material-symbols-outlined drag-drop-icon-large">cloud_upload</span>
98+
<h3>Drop folder to load</h3>
99+
</div>
91100
</div>
92101

93102
<div class="sidebar-select">

index.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,6 +1998,59 @@
19981998
toast(`Template: ${S.model.toUpperCase()}`, 'info');
19991999
});
20002000
}
2001+
2002+
// Drag and Drop functionality
2003+
const dragDropZone = $('dragDropZone');
2004+
const dragDropOverlay = $('dragDropOverlay');
2005+
2006+
if (dragDropZone) {
2007+
// Prevent default drag behaviors on the entire zone
2008+
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
2009+
dragDropZone.addEventListener(eventName, e => {
2010+
e.preventDefault();
2011+
e.stopPropagation();
2012+
}, false);
2013+
});
2014+
2015+
// Highlight drop zone when dragging over it
2016+
['dragenter', 'dragover'].forEach(eventName => {
2017+
dragDropZone.addEventListener(eventName, () => {
2018+
dragDropZone.classList.add('drag-over');
2019+
}, false);
2020+
});
2021+
2022+
['dragleave', 'drop'].forEach(eventName => {
2023+
dragDropZone.addEventListener(eventName, () => {
2024+
dragDropZone.classList.remove('drag-over');
2025+
}, false);
2026+
});
2027+
2028+
// Handle dropped files
2029+
dragDropZone.addEventListener('drop', e => {
2030+
const items = e.dataTransfer.items;
2031+
if (!items || items.length === 0) return;
2032+
2033+
// Check if folder was dropped (check webkitdirectory support)
2034+
const files = e.dataTransfer.files;
2035+
if (files.length > 0) {
2036+
// Show loader IMMEDIATELY
2037+
load(true, 'Loading dropped files...');
2038+
// Process files in next tick to let loader render
2039+
setTimeout(() => loadFiles(files), 0);
2040+
} else {
2041+
toast('Please drop a folder, not individual files', 'warning');
2042+
}
2043+
}, false);
2044+
2045+
// Click on zone to trigger folder selection
2046+
dragDropZone.addEventListener('click', e => {
2047+
// Don't trigger if clicking the button itself
2048+
if (!e.target.closest('.btn-select-dir')) {
2049+
if (D.sel) D.sel.click();
2050+
}
2051+
});
2052+
}
2053+
20012054
// Optimize file input change handler
20022055
inp.onchange = e => {
20032056
if (!e.target.files.length) return;

ss.png

2.8 KB
Loading

style.css

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,105 @@ html, body {
480480
line-height: 1.2;
481481
}
482482

483+
/* Drag and Drop Zone */
484+
.drag-drop-zone {
485+
position: relative;
486+
margin: 12px 12px 8px 12px;
487+
border: 2px dashed var(--border-color);
488+
border-radius: 8px;
489+
padding: 24px 16px;
490+
background: rgba(255, 255, 255, 0.02);
491+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
492+
cursor: pointer;
493+
flex-shrink: 0;
494+
}
495+
496+
.drag-drop-zone:hover {
497+
border-color: var(--color-accent);
498+
background: rgba(251, 191, 36, 0.05);
499+
}
500+
501+
.drag-drop-zone.drag-over {
502+
border-color: var(--color-accent);
503+
background: rgba(251, 191, 36, 0.1);
504+
border-style: solid;
505+
transform: scale(1.02);
506+
}
507+
508+
.drag-drop-content {
509+
display: flex;
510+
flex-direction: column;
511+
align-items: center;
512+
gap: 8px;
513+
z-index: 1;
514+
position: relative;
515+
}
516+
517+
.drag-drop-icon {
518+
font-size: 48px;
519+
color: var(--color-accent);
520+
opacity: 0.8;
521+
}
522+
523+
.drag-drop-content h4 {
524+
margin: 0;
525+
font-size: 14px;
526+
font-weight: 600;
527+
color: var(--text-primary);
528+
}
529+
530+
.drag-drop-content p {
531+
margin: 4px 0;
532+
font-size: 12px;
533+
color: var(--text-secondary);
534+
}
535+
536+
.drag-drop-content .btn-select-dir {
537+
margin: 8px 0 0 0;
538+
width: auto;
539+
padding: 8px 16px;
540+
font-size: 12px;
541+
}
542+
543+
.drag-drop-overlay {
544+
position: absolute;
545+
top: 0;
546+
left: 0;
547+
right: 0;
548+
bottom: 0;
549+
background: rgba(251, 191, 36, 0.15);
550+
backdrop-filter: blur(4px);
551+
border-radius: 6px;
552+
display: none;
553+
flex-direction: column;
554+
align-items: center;
555+
justify-content: center;
556+
z-index: 10;
557+
pointer-events: none;
558+
}
559+
560+
.drag-drop-zone.drag-over .drag-drop-overlay {
561+
display: flex;
562+
}
563+
564+
.drag-drop-icon-large {
565+
font-size: 64px;
566+
color: var(--color-accent);
567+
animation: bounce 0.6s ease infinite;
568+
}
569+
570+
.drag-drop-overlay h3 {
571+
margin: 8px 0 0 0;
572+
font-size: 16px;
573+
font-weight: 600;
574+
color: var(--color-accent);
575+
}
576+
577+
@keyframes bounce {
578+
0%, 100% { transform: translateY(0); }
579+
50% { transform: translateY(-10px); }
580+
}
581+
483582
.sidebar-select {
484583
padding: 0 12px;
485584
flex-shrink: 0;

0 commit comments

Comments
 (0)