Skip to content

Commit

Permalink
feat: add Modal component + use it on ProjectAssetExplorer
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoecheza committed May 8, 2023
1 parent 69cd3db commit 9e1f5ad
Show file tree
Hide file tree
Showing 17 changed files with 204 additions and 23 deletions.
51 changes: 51 additions & 0 deletions packages/@dcl/inspector/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/@dcl/inspector/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@types/node": "^18.11.18",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@types/react-modal": "^3.16.0",
"@vscode/webview-ui-toolkit": "^1.2.2",
"@well-known-components/pushable-channel": "^1.0.3",
"classnames": "^2.3.2",
Expand All @@ -30,6 +31,7 @@
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0",
"react-icons": "^4.7.1",
"react-modal": "^3.16.1",
"typescript": "^5.0.2"
},
"files": [
Expand Down
8 changes: 7 additions & 1 deletion packages/@dcl/inspector/src/components/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Toolbar } from '../Toolbar'
import './App.css'
import { Resizable } from '../Resizable'
import ImportAsset from '../ImportAsset'
import { fileSystemEvent } from '../../hooks/catalog/useFileSystem'

enum Tab {
FileSystem = 'FileSystem',
Expand All @@ -33,6 +34,11 @@ const App = () => {
[tab]
)

const handleSave = useCallback(() => {
setTab(Tab.FileSystem)
fileSystemEvent.emit('change')
}, [])

return (
<Resizable type="horizontal" min={300} initial={300}>
<Box>
Expand All @@ -56,7 +62,7 @@ const App = () => {
<div className="footer-content">
{tab === Tab.AssetsPack && catalog && <AssetsCatalog value={catalog} />}
{tab === Tab.FileSystem && <ProjectAssetExplorer onImportAsset={handleTabClick(Tab.Import)} />}
{tab === Tab.Import && <ImportAsset onSave={handleTabClick(Tab.FileSystem)} />}
{tab === Tab.Import && <ImportAsset onSave={handleSave} />}
</div>
)}
<div className="footer-buttons">
Expand Down
2 changes: 1 addition & 1 deletion packages/@dcl/inspector/src/components/Block/Block.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
}

.Block.broken {
border: 1px #d33c3c dashed;
border: 1px var(--primary) dashed;
padding: 0 5px 8px 5px;
border-radius: 2px;
}
14 changes: 14 additions & 0 deletions packages/@dcl/inspector/src/components/Button/Button.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,17 @@
width: 24px;
height: 24px;
}

.Button.big {
padding: 16px;
font-size: 16px;
}

.Button.danger {
background-color: var(--primary);
}

.Button.danger:hover,
.Button.danger.active {
background-color: var(--primary-darker)
}
9 changes: 4 additions & 5 deletions packages/@dcl/inspector/src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import React from 'react'
import classNames from 'classnames'
import cx from 'classnames'

import { PropTypes } from './types'
import './Button.css'

function Button(props: PropTypes) {
function Button({ size, type, ...props }: PropTypes) {
return (
<button {...props} className={classNames('Button', props.className)}>
<button {...props} className={cx('Button', size, type, props.className)}>
{props.children}
</button>
)
}

export default Button
export default Button
7 changes: 6 additions & 1 deletion packages/@dcl/inspector/src/components/Button/types.ts
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
export type PropTypes = React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
type Button = React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>

export type PropTypes = Omit<Button, 'type' | 'size'> & {
type?: 'danger' | 'etc'
size?: 'big' | 'etc'
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
.TextField>input {
width: 100%;
color: var(--text);
background-color: var(--transparent-color);
background-color: var(--transparent);
outline: none;
border: none;
}

.TextField:last-child {
margin-right: 0px;
}
}
24 changes: 24 additions & 0 deletions packages/@dcl/inspector/src/components/Modal/Modal.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.Modal {
position: absolute;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
border: 1px solid var(--modal-content-border-color);
background: var(--modal-content-bg-color);
overflow: auto;
border-radius: 3px;
outline: none;
padding: 20px;
min-width: 500px;
min-height: 200px;
display: flex;
flex-direction: column;
justify-content: space-between;
}

.ModalOverlay {
position: fixed;
inset: 0px;
background-color: var(--modal-overlay-bg-color);
}
26 changes: 26 additions & 0 deletions packages/@dcl/inspector/src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react'
import _Modal from 'react-modal'

import { Props } from './types'

import './Modal.css'

const Modal = ({
children,
className = '',
overlayClassName = '',
...props
}: Props) => {
return (
<_Modal
ariaHideApp={false}
className={`${className} Modal`}
overlayClassName={`${overlayClassName} ModalOverlay`}
{...props}
>
{children}
</_Modal>
)
}

export default React.memo(Modal)
2 changes: 2 additions & 0 deletions packages/@dcl/inspector/src/components/Modal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Modal from './Modal'
export { Modal }
4 changes: 4 additions & 0 deletions packages/@dcl/inspector/src/components/Modal/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import React from 'react'
import Modal from 'react-modal'

export type Props = React.PropsWithChildren<Modal.Props>
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@

.ProjectView .with-context-menu {
height: 100%;
}
}

.RemoveAsset.Modal > div button {
margin-right: 12px;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { useCallback, useState } from 'react'
import { IoIosArrowDown, IoIosArrowForward, IoIosImage } from 'react-icons/io'
import { AiFillFolder } from 'react-icons/ai'

import { useSdk } from '../../hooks/sdk/useSdk'
import { fileSystemEvent } from '../../hooks/catalog/useFileSystem'
import { Tree } from '../Tree'
import { AssetNode, AssetNodeFolder } from './types'
import { AiFillFolder } from 'react-icons/ai'
import { Modal } from '../Modal'
import Button from '../Button'

import ContextMenu from './ContextMenu'
import { useSdk } from '../../hooks/sdk/useSdk'
import { AssetNode, AssetNodeFolder } from './types'
import { getFullNodePath } from './utils'

function noop() {}
Expand All @@ -22,8 +26,9 @@ export const ROOT = 'File System'
export type TreeNode = Omit<AssetNode, 'children'> & { children?: string[] }

function ProjectView({ folders, onImportAsset }: Props) {
const [open, setOpen] = useState(new Set<string>())
const sdk = useSdk()
const [open, setOpen] = useState(new Set<string>())
const [modal, setModal] = useState<{ isOpen: boolean; value: string } | undefined>(undefined)
const getTree = useCallback(() => {
const tree = new Map<string, TreeNode>()
tree.set(ROOT, { children: folders.map(f => f.name), name: ROOT, type: 'folder', parent: null })
Expand Down Expand Up @@ -58,15 +63,48 @@ function ProjectView({ folders, onImportAsset }: Props) {
setOpen(new Set(open))
}, [open, setOpen])

const handleRemove = useCallback((value: string) => {
const node = tree.get(value)!
sdk?.dataLayer.removeAsset({ path: getFullNodePath(node) })
const shouldOpenModal = useCallback((value: string) => {
if (!sdk || modal?.isOpen) return false
const { GltfContainer } = sdk.components
for (const [_, _value] of sdk.engine.getEntitiesWith(GltfContainer)) {
if (_value.src === value) {
return true
}
}
return false
}, [])

const handleRemove = useCallback(async (value: string) => {
const path = getFullNodePath(tree.get(value)!).slice(1)
if (shouldOpenModal(path)) return setModal({ isOpen: true, value: path })
await removeAsset(path)
}, [open, setOpen])

const removeAsset = useCallback(async (path: string) => {
if (!sdk) return
await sdk.dataLayer.removeAsset({ path })
fileSystemEvent.emit('change')
}, [])

const handleConfirm = useCallback(async () => {
if (!modal) return
await removeAsset(modal.value)
setModal(undefined)
}, [modal, setModal])

const handleModalClose = useCallback(() => setModal(undefined), [])

if (!folders.length) return null

return (
<div className="ProjectView">
<Modal isOpen={!!modal?.isOpen} onRequestClose={handleModalClose} className="RemoveAsset">
<h2>⚠️ Removing this asset will break some components</h2>
<div>
<Button type="danger" size="big" onClick={handleConfirm}>Delete anyway</Button>
<Button size="big" onClick={handleModalClose}>Cancel</Button>
</div>
</Modal>
<MyTree
className="editor-assets-tree"
value={ROOT}
Expand Down
5 changes: 4 additions & 1 deletion packages/@dcl/inspector/src/hooks/sdk/useComponentInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ export const useComponentInput = <ComponentValueType extends object, InputType e
updateInputs(fromComponentValueToInput(componentValue))
}, [componentValue])

const validate = useCallback((input: InputType | null): input is InputType => input !== null && validateInput(input), [input, ...deps])
const validate = useCallback(
(input: InputType | null): input is InputType => input !== null && validateInput(input),
[input, ...deps]
)

// sync inputs -> engine
useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Transform, Entity, EntityMappingMode, IEngine, Composite, OnChangeFunction, CompositeDefinition } from '@dcl/ecs'
import { Entity, EntityMappingMode, IEngine, Composite, OnChangeFunction, CompositeDefinition } from '@dcl/ecs'

import { DataLayerRpcServer, FileSystemInterface } from '../types'
import { getFilesInDirectory } from './fs-utils'
Expand Down Expand Up @@ -121,8 +121,6 @@ export async function initRpcMethods(
const prevValue = await fs.readFile(filePath)
await fs.rm(filePath)
undoRedo.addUndoFile([{ prevValue, newValue: null, path: filePath }])
const asd = engine.addEntity()
Transform.create(asd)
}
return {}
}
Expand Down
Loading

0 comments on commit 9e1f5ad

Please sign in to comment.