Skip to content

Commit

Permalink
refactor file dropping for ImportAsset component
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoecheza committed Jan 16, 2025
1 parent b85d6c1 commit 03ab674
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 129 deletions.
2 changes: 1 addition & 1 deletion packages/@dcl/inspector/src/components/Assets/Assets.css
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@

.Assets .Assets-content {
background: var(--tree-bg-color) !important;
height: calc(100% - 36px);
height: 100%;
}

.Assets .Assets-content.Hide {
Expand Down
30 changes: 19 additions & 11 deletions packages/@dcl/inspector/src/components/Assets/Assets.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback } from 'react'
import React, { useCallback, useRef } from 'react'
import cx from 'classnames'
import { MdImageSearch } from 'react-icons/md'
import { HiOutlinePlus } from 'react-icons/hi'
Expand All @@ -17,6 +17,7 @@ import { CustomAssets } from '../CustomAssets'
import { selectCustomAssets } from '../../redux/app'
import { RenameAsset } from '../RenameAsset'
import { CreateCustomAsset } from '../CreateCustomAsset'
import { InputRef } from '../FileInput/FileInput'

import './Assets.css'

Expand All @@ -31,6 +32,7 @@ function Assets({ isAssetsPanelCollapsed }: { isAssetsPanelCollapsed: boolean })
const dispatch = useAppDispatch()
const tab = useAppSelector(getSelectedAssetsTab)
const customAssets = useAppSelector(selectCustomAssets)
const inputRef = useRef<InputRef>(null);

const handleTabClick = useCallback(
(tab: AssetsTab) => () => {
Expand All @@ -47,9 +49,14 @@ function Assets({ isAssetsPanelCollapsed }: { isAssetsPanelCollapsed: boolean })
const assetToRename = useAppSelector(selectAssetToRename)
const stagedCustomAsset = useAppSelector(selectStagedCustomAsset)

const handleImportClick = useCallback(() => {
inputRef.current?.onClick()
}, [inputRef])

return (
<div className="Assets">
<div className="Assets-buttons">
<button onClick={handleImportClick}>TOCAME BRO</button>
<div className="tab" onClick={handleTabClick(AssetsTab.FileSystem)} data-test-id={AssetsTab.FileSystem}>
<div className={cx({ underlined: tab === AssetsTab.FileSystem })}>
<FolderOpen />
Expand All @@ -76,16 +83,17 @@ function Assets({ isAssetsPanelCollapsed }: { isAssetsPanelCollapsed: boolean })
</div>
</div>
</div>
<div className={cx('Assets-content', { Hide: isAssetsPanelCollapsed })}>
{tab === AssetsTab.AssetsPack && <AssetsCatalog catalog={filteredCatalog} />}
{tab === AssetsTab.FileSystem && <ProjectAssetExplorer />}
{tab === AssetsTab.Import && <ImportAsset onSave={handleTabClick(AssetsTab.FileSystem)} />}
{tab === AssetsTab.CustomAssets && <CustomAssets />}
{tab === AssetsTab.RenameAsset && assetToRename && (
<RenameAsset assetId={assetToRename.id} currentName={assetToRename.name} />
)}
{tab === AssetsTab.CreateCustomAsset && stagedCustomAsset && <CreateCustomAsset />}
</div>
<ImportAsset onSave={handleTabClick(AssetsTab.FileSystem)} ref={inputRef}>
<div className={cx('Assets-content', { Hide: isAssetsPanelCollapsed })}>
{tab === AssetsTab.AssetsPack && <AssetsCatalog catalog={filteredCatalog} />}
{tab === AssetsTab.FileSystem && <ProjectAssetExplorer />}
{tab === AssetsTab.CustomAssets && <CustomAssets />}
{tab === AssetsTab.RenameAsset && assetToRename && (
<RenameAsset assetId={assetToRename.id} currentName={assetToRename.name} />
)}
{tab === AssetsTab.CreateCustomAsset && stagedCustomAsset && <CreateCustomAsset />}
</div>
</ImportAsset>
</div>
)
}
Expand Down
34 changes: 27 additions & 7 deletions packages/@dcl/inspector/src/components/FileInput/FileInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useRef, PropsWithChildren, useCallback } from 'react'
import React, { useImperativeHandle, useCallback, useEffect, useRef } from 'react'
import { useDrop } from 'react-dnd'
import { NativeTypes } from 'react-dnd-html5-backend'
import { PropTypes } from './types'
Expand All @@ -11,24 +11,35 @@ function parseAccept(accept: PropTypes['accept']) {
return value
}

export function FileInput(props: PropsWithChildren<PropTypes>) {
export interface InputRef {
onClick: () => void;
}

export const FileInput = React.forwardRef<InputRef, React.PropsWithChildren<PropTypes>>((props, parentRef) => {
const { onDrop } = props
const inputRef = useRef<HTMLInputElement>(null)
const acceptExtensions = Object.values(props.accept ?? []).flat()
const inputRef = useRef<HTMLInputElement>(null)

const [_, drop] = useDrop(
const [{ isHover }, drop] = useDrop(
() => ({
accept: [NativeTypes.FILE],
drop(item: { files: File[] }) {
if (onDrop) onDrop(item.files)
},
canDrop(item: { files: File[] }) {
return item.files.every((file) => !!acceptExtensions.find((ext) => file.name.endsWith(ext)))
}
},
collect: (monitor) => ({
isHover: monitor.canDrop() && monitor.isOver()
})
}),
[props]
)

const handleClick = useCallback(() => {
inputRef?.current?.click()
}, [inputRef])

const handleFileSelected = useCallback(
(e: React.ChangeEvent<HTMLInputElement>): void => {
const files = Array.from(e.target.files ?? [])
Expand All @@ -37,8 +48,17 @@ export function FileInput(props: PropsWithChildren<PropTypes>) {
[onDrop]
)

useEffect(() => {
props.onHover?.(isHover)
return () => props.onHover?.(false)
}, [isHover])

useImperativeHandle(parentRef, () => ({
onClick: handleClick,
}), [handleClick]);

return (
<div ref={drop} onClick={() => inputRef?.current?.click()}>
<div ref={drop}>
<input
disabled={props.disabled}
ref={inputRef}
Expand All @@ -51,6 +71,6 @@ export function FileInput(props: PropsWithChildren<PropTypes>) {
{props.children}
</div>
)
}
})

export default FileInput
1 change: 1 addition & 0 deletions packages/@dcl/inspector/src/components/FileInput/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface PropTypes {
onDrop(files: File[]): void
onHover?(isHover: boolean): void
accept?: Record<string, string[]>
disabled?: boolean
}
45 changes: 26 additions & 19 deletions packages/@dcl/inspector/src/components/ImportAsset/ImportAsset.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
.ImportAsset {
height: 100%;
padding: 8px;
}

.ImportAsset > div:first-child {
height: 100%;
}

.ImportAssetHover {
padding: 8px;
}

.ImportAssetHover > div:first-child {
display: flex;
flex-direction: column;
align-items: center;
Expand All @@ -19,11 +26,11 @@
overflow-y: auto;
}

.ImportAsset > div > span:last-of-type {
.ImportAssetHover > div > span:last-of-type {
text-align: center;
}

.ImportAsset .upload-icon {
.ImportAssetHover .upload-icon {
background-color: var(--list-item-hover-bg-color);
width: 40px;
height: 40px;
Expand All @@ -35,19 +42,19 @@
flex-shrink: 0;
}

.ImportAsset .Container {
.ImportAssetHover .Container {
overflow: visible;
height: unset;
background-color: var(--list-item-hover-bg-color);
margin-right: 20px;
}

.ImportAsset .Container svg {
.ImportAssetHover .Container svg {
width: 40px;
height: 40px;
}

.ImportAsset .Container .content {
.ImportAssetHover .Container .content {
height: 100%;
width: 100%;
display: flex;
Expand All @@ -57,7 +64,7 @@
position: relative;
}

.ImportAsset .Container .remove-icon {
.ImportAssetHover .Container .remove-icon {
position: absolute;
display: flex;
align-items: center;
Expand All @@ -68,12 +75,12 @@
border-radius: 50%;
}

.ImportAsset .Container .remove-icon svg {
.ImportAssetHover .Container .remove-icon svg {
width: 14px;
height: 14px;
}

.ImportAsset .Container .file-title {
.ImportAssetHover .Container .file-title {
margin-top: 8px;
text-overflow: ellipsis;
overflow: hidden;
Expand All @@ -82,49 +89,49 @@
text-align: center;
}

.ImportAsset .file-container {
.ImportAssetHover .file-container {
display: flex;
flex-direction: row;
margin-top: 16px;
}
.ImportAsset .file-container .Container {
.ImportAssetHover .file-container .Container {
width: 120px;
}

.ImportAsset .file-container .Text.Field {
.ImportAssetHover .file-container .Text.Field {
width: auto;
height: 24px;
}

.ImportAsset .file-container .error .Text.Field {
.ImportAssetHover .file-container .error .Text.Field {
border-color: red;
}

.ImportAsset .file-container > div:nth-child(2) {
.ImportAssetHover .file-container > div:nth-child(2) {
display: flex;
flex-direction: column;
justify-content: center;
}

.ImportAsset .file-container > div:nth-child(2) button {
.ImportAssetHover .file-container > div:nth-child(2) button {
background-color: var(--primary-main);
}

.ImportAsset .error {
.ImportAssetHover .error {
color: var(--primary-main);
margin-top: 6px;
}

.ImportAsset .file-container .AssetPreview {
.ImportAssetHover .file-container .AssetPreview {
width: 100px;
height: 100px;
}

.ImportAsset .warning {
.ImportAssetHover .warning {
color: var(--danger);
margin-top: 6px;
}

.ImportAsset .text {
.ImportAssetHover .text {
text-align: center;
}
Loading

0 comments on commit 03ab674

Please sign in to comment.