parent
85b63b9268
commit
c13301fda9
@ -0,0 +1,59 @@ |
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import React, { useEffect, useRef } from 'react' |
||||||
|
import { FileType } from '../types' |
||||||
|
|
||||||
|
export interface FileLabelProps { |
||||||
|
file: FileType, |
||||||
|
focusEdit: { |
||||||
|
element: string |
||||||
|
type: string |
||||||
|
isNew: boolean |
||||||
|
lastEdit: string |
||||||
|
} |
||||||
|
editModeOff: (content: string) => void |
||||||
|
} |
||||||
|
|
||||||
|
export const FileLabel = (props: FileLabelProps) => { |
||||||
|
const { file, focusEdit, editModeOff } = props |
||||||
|
const isEditable = focusEdit.element === file.path |
||||||
|
const labelRef = useRef(null) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (isEditable) { |
||||||
|
setTimeout(() => { |
||||||
|
labelRef.current.focus() |
||||||
|
}, 0) |
||||||
|
} |
||||||
|
}, [isEditable]) |
||||||
|
|
||||||
|
const handleEditInput = (event: React.KeyboardEvent<HTMLDivElement>) => { |
||||||
|
if (event.which === 13) { |
||||||
|
event.preventDefault() |
||||||
|
editModeOff(labelRef.current.innerText) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const handleEditBlur = (event: React.SyntheticEvent) => { |
||||||
|
event.stopPropagation() |
||||||
|
editModeOff(labelRef.current.innerText) |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<div |
||||||
|
className='remixui_items d-inline-block w-100' |
||||||
|
ref={labelRef} |
||||||
|
suppressContentEditableWarning={true} |
||||||
|
contentEditable={isEditable} |
||||||
|
onKeyDown={handleEditInput} |
||||||
|
onBlur={handleEditBlur} |
||||||
|
> |
||||||
|
<span |
||||||
|
title={file.path} |
||||||
|
className={'remixui_label ' + (file.isDirectory ? 'folder' : 'remixui_leaf')} |
||||||
|
data-path={file.path} |
||||||
|
> |
||||||
|
{ file.name } |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import React, { SyntheticEvent, useState } from 'react' |
||||||
|
import { FileType } from '../types' |
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import { TreeView, TreeViewItem } from '@remix-ui/tree-view' |
||||||
|
import { getPathIcon } from '@remix-ui/helper' |
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import { FileLabel } from './file-label' |
||||||
|
|
||||||
|
export interface RenderFileProps { |
||||||
|
file: FileType, |
||||||
|
index: number, |
||||||
|
focusEdit: { element: string, type: string, isNew: boolean, lastEdit: string }, |
||||||
|
focusElement: { key: string, type: 'file' | 'folder' | 'gist' }[], |
||||||
|
focusContext: { element: string, x: number, y: number, type: string }, |
||||||
|
ctrlKey: boolean, |
||||||
|
expandPath: string[], |
||||||
|
editModeOff: (content: string) => void, |
||||||
|
handleClickFolder: (path: string, type: string) => void, |
||||||
|
handleClickFile: (path: string, type: string) => void, |
||||||
|
handleContextMenu: (pageX: number, pageY: number, path: string, content: string, type: string) => void |
||||||
|
} |
||||||
|
|
||||||
|
export const FileRender = (props: RenderFileProps) => { |
||||||
|
const { file } = props |
||||||
|
|
||||||
|
if (!file || !file.path || typeof file === 'string' || typeof file === 'number' || typeof file === 'boolean') return |
||||||
|
const [hover, setHover] = useState<boolean>(false) |
||||||
|
const labelClass = props.focusEdit.element === file.path |
||||||
|
? 'bg-light' : props.focusElement.findIndex(item => item.key === file.path) !== -1 |
||||||
|
? 'bg-secondary' : hover |
||||||
|
? 'bg-light border' : (props.focusContext.element === file.path) && (props.focusEdit.element !== file.path) |
||||||
|
? 'bg-light border' : '' |
||||||
|
const icon = getPathIcon(file.path) |
||||||
|
const spreadProps = { |
||||||
|
onClick: (e) => e.stopPropagation() |
||||||
|
} |
||||||
|
|
||||||
|
const handleFolderClick = (event: SyntheticEvent) => { |
||||||
|
event.stopPropagation() |
||||||
|
if (props.focusEdit.element !== file.path) props.handleClickFolder(file.path, file.type) |
||||||
|
} |
||||||
|
|
||||||
|
const handleFileClick = (event: SyntheticEvent) => { |
||||||
|
event.stopPropagation() |
||||||
|
if (props.focusEdit.element !== file.path) props.handleClickFile(file.path, file.type) |
||||||
|
} |
||||||
|
|
||||||
|
const handleContextMenu = (event: PointerEvent) => { |
||||||
|
event.preventDefault() |
||||||
|
event.stopPropagation() |
||||||
|
props.handleContextMenu(event.pageX, event.pageY, file.path, (event.target as HTMLElement).textContent, file.type) |
||||||
|
} |
||||||
|
|
||||||
|
const handleMouseOut = (event: SyntheticEvent) => { |
||||||
|
event.stopPropagation() |
||||||
|
setHover(false) |
||||||
|
} |
||||||
|
|
||||||
|
const handleMouseOver = (event: SyntheticEvent) => { |
||||||
|
event.stopPropagation() |
||||||
|
setHover(true) |
||||||
|
} |
||||||
|
|
||||||
|
if (file.isDirectory) { |
||||||
|
return ( |
||||||
|
<TreeViewItem |
||||||
|
id={`treeViewItem${file.path}`} |
||||||
|
iconX='pr-3 fa fa-folder' |
||||||
|
iconY='pr-3 fa fa-folder-open' |
||||||
|
key={`${file.path + props.index}`} |
||||||
|
label={<FileLabel file={file} focusEdit={props.focusEdit} editModeOff={props.editModeOff} />} |
||||||
|
onClick={handleFolderClick} |
||||||
|
onContextMenu={handleContextMenu} |
||||||
|
labelClass={labelClass} |
||||||
|
controlBehaviour={ props.ctrlKey } |
||||||
|
expand={props.expandPath.includes(file.path)} |
||||||
|
onMouseOver={handleMouseOver} |
||||||
|
onMouseOut={handleMouseOut} |
||||||
|
> |
||||||
|
{ |
||||||
|
file.child ? <TreeView id={`treeView${file.path}`} key={`treeView${file.path}`} {...spreadProps }>{ |
||||||
|
Object.keys(file.child).map((key, index) => <FileRender |
||||||
|
file={file.child[key]} |
||||||
|
index={index} |
||||||
|
focusContext={props.focusContext} |
||||||
|
focusEdit={props.focusEdit} |
||||||
|
focusElement={props.focusElement} |
||||||
|
ctrlKey={props.ctrlKey} |
||||||
|
editModeOff={props.editModeOff} |
||||||
|
handleClickFile={props.handleClickFile} |
||||||
|
handleClickFolder={props.handleClickFolder} |
||||||
|
handleContextMenu={props.handleContextMenu} |
||||||
|
expandPath={props.expandPath} |
||||||
|
/>) |
||||||
|
} |
||||||
|
</TreeView> : <TreeView id={`treeView${file.path}`} key={`treeView${file.path}`} {...spreadProps }/> |
||||||
|
} |
||||||
|
</TreeViewItem> |
||||||
|
) |
||||||
|
} else { |
||||||
|
return ( |
||||||
|
<TreeViewItem |
||||||
|
id={`treeViewItem${file.path}`} |
||||||
|
key={`treeView${file.path}`} |
||||||
|
label={<FileLabel file={file} focusEdit={props.focusEdit} editModeOff={props.editModeOff} />} |
||||||
|
onClick={handleFileClick} |
||||||
|
onContextMenu={handleContextMenu} |
||||||
|
icon={icon} |
||||||
|
labelClass={labelClass} |
||||||
|
onMouseOver={handleMouseOver} |
||||||
|
onMouseOut={handleMouseOut} |
||||||
|
/> |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -1,61 +0,0 @@ |
|||||||
.remixui_container { |
|
||||||
display : flex; |
|
||||||
flex-direction : row; |
|
||||||
width : 100%; |
|
||||||
height : 100%; |
|
||||||
box-sizing : border-box; |
|
||||||
} |
|
||||||
.remixui_fileexplorer { |
|
||||||
display : flex; |
|
||||||
flex-direction : column; |
|
||||||
position : relative; |
|
||||||
width : 100%; |
|
||||||
padding-left : 6px; |
|
||||||
padding-right : 6px; |
|
||||||
padding-top : 6px; |
|
||||||
} |
|
||||||
.remixui_fileExplorerTree { |
|
||||||
cursor : default; |
|
||||||
} |
|
||||||
.remixui_gist { |
|
||||||
padding : 10px; |
|
||||||
} |
|
||||||
.remixui_gist i { |
|
||||||
cursor : pointer; |
|
||||||
} |
|
||||||
.remixui_gist i:hover { |
|
||||||
color : orange; |
|
||||||
} |
|
||||||
.remixui_connectToLocalhost { |
|
||||||
padding : 10px; |
|
||||||
} |
|
||||||
.remixui_connectToLocalhost i { |
|
||||||
cursor : pointer; |
|
||||||
} |
|
||||||
.remixui_connectToLocalhost i:hover { |
|
||||||
color : var(--secondary) |
|
||||||
} |
|
||||||
.remixui_uploadFile { |
|
||||||
padding : 10px; |
|
||||||
} |
|
||||||
.remixui_uploadFile label:hover { |
|
||||||
color : var(--secondary) |
|
||||||
} |
|
||||||
.remixui_uploadFile label { |
|
||||||
cursor : pointer; |
|
||||||
} |
|
||||||
.remixui_treeview { |
|
||||||
overflow-y : auto; |
|
||||||
} |
|
||||||
.remixui_dialog { |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
} |
|
||||||
.remixui_dialogParagraph { |
|
||||||
margin-bottom: 2em; |
|
||||||
word-break: break-word; |
|
||||||
} |
|
||||||
.remixui_menuicon { |
|
||||||
padding-right : 10px; |
|
||||||
} |
|
||||||
|
|
Loading…
Reference in new issue