@@ -374,7 +374,8 @@ export function App() {
374374 3. Add models
375375 </ h2 >
376376 < p className = "text-muted mb-5.5 leading-relaxed" >
377- Download each required model, then select the downloaded file.
377+ Download each required model, then drop or select the downloaded
378+ file.
378379 </ p >
379380 < div className = "grid gap-2.5" >
380381 { requiredFiles . map ( ( filename ) => (
@@ -515,14 +516,36 @@ function ModelFileSlot({
515516 error ?: string ;
516517 onSelect : ( files : File [ ] ) => void ;
517518} ) {
519+ const [ dragging , setDragging ] = useState ( false ) ;
520+
518521 return (
519522 < div data-testid = "model-file-slot" >
520523 < div
521524 className = { `flex min-h-13 items-center gap-3 rounded-md border px-4 py-3 transition-colors ${
522- ready
523- ? "border-success-border bg-success-surface hover:bg-success-surface-hover"
524- : "border-border-strong bg-surface-muted hover:border-drop-border-hover hover:bg-drop-surface-hover border-dashed"
525+ dragging
526+ ? "border-drop-border-hover bg-drop-surface-hover"
527+ : ready
528+ ? "border-success-border bg-success-surface hover:bg-success-surface-hover"
529+ : "border-border-strong bg-surface-muted hover:border-drop-border-hover hover:bg-drop-surface-hover border-dashed"
525530 } `}
531+ onDragEnter = { ( event ) => {
532+ event . preventDefault ( ) ;
533+ setDragging ( true ) ;
534+ } }
535+ onDragOver = { ( event ) => event . preventDefault ( ) }
536+ onDragLeave = { ( event ) => {
537+ if ( ! event . currentTarget . contains ( event . relatedTarget as Node ) ) {
538+ setDragging ( false ) ;
539+ }
540+ } }
541+ onDrop = { ( event ) => {
542+ event . preventDefault ( ) ;
543+ setDragging ( false ) ;
544+ const file = event . dataTransfer . files [ 0 ] ;
545+ if ( file ) {
546+ onSelect ( [ file ] ) ;
547+ }
548+ } }
526549 >
527550 < span
528551 className = { `flex size-6 shrink-0 items-center justify-center rounded-full text-sm font-bold ${
0 commit comments