add bottom padding to fe menu span

pull/3999/head
Joseph Izang 1 year ago committed by Aniket
parent 6f13b6a734
commit 4cf72511e8
  1. 122
      libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx
  2. 293
      libs/remix-ui/workspace/src/lib/components/file-explorer.tsx

@ -1,9 +1,9 @@
import { CustomTooltip } from '@remix-ui/helper'
import React, { useState, useEffect, } from 'react' //eslint-disable-line
import { FormattedMessage } from 'react-intl'
import { Placement } from 'react-bootstrap/esm/Overlay'
import { FileExplorerMenuProps } from '../types'
const _paq = window._paq = window._paq || []
import {CustomTooltip} from '@remix-ui/helper'
import React, {useState, useEffect} from 'react' //eslint-disable-line
import {FormattedMessage} from 'react-intl'
import {Placement} from 'react-bootstrap/esm/Overlay'
import {FileExplorerMenuProps} from '../types'
const _paq = (window._paq = window._paq || [])
export const FileExplorerMenu = (props: FileExplorerMenuProps) => {
const [state, setState] = useState({
@ -44,18 +44,24 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => {
icon: 'fab fa-github',
placement: 'bottom-start'
}
].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })),
].filter(
(item) =>
props.menuItems &&
props.menuItems.find((name) => {
return name === item.action
})
),
actions: {}
})
const enableDirUpload = { directory: "", webkitdirectory: "" }
const enableDirUpload = {directory: '', webkitdirectory: ''}
useEffect(() => {
const actions = {
updateGist: () => {}
}
setState(prevState => {
return { ...prevState, actions }
setState((prevState) => {
return {...prevState, actions}
})
}, [])
@ -67,32 +73,53 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => {
tooltipClasses="text-nowrap"
tooltipText={props.title}
>
<span className='remixui_label' data-path={props.title} style={{ fontWeight: 'bold' }}>{ props.title }</span>
<span
className="remixui_label"
data-path={props.title}
style={{fontWeight: 'bold'}}
>
{props.title}
</span>
</CustomTooltip>
<span className="pl-0">{
state.menuItems.map(({ action, title, icon, placement }, index) => {
<span className="pl-0 pb-1">
{state.menuItems.map(({action, title, icon, placement}, index) => {
if (action === 'uploadFile') {
return (
<CustomTooltip
placement={placement as Placement}
tooltipId="uploadFileTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id={`filePanel.${action}`} defaultMessage={title} />}
tooltipText={
<FormattedMessage
id={`filePanel.${action}`}
defaultMessage={title}
/>
}
key={`index-${action}-${placement}-${icon}`}
>
<label
id={action}
data-id={'fileExplorerUploadFile' + action }
data-id={'fileExplorerUploadFile' + action}
className={icon + ' mb-0 px-1 remixui_newFile'}
key={`index-${action}-${placement}-${icon}`}
>
<input id="fileUpload" data-id="fileExplorerFileUpload" type="file" onChange={(e) => {
e.stopPropagation()
_paq.push(['trackEvent', 'fileExplorer', 'fileAction', action])
props.uploadFile(e.target)
e.target.value = null
}}
multiple />
<input
id="fileUpload"
data-id="fileExplorerFileUpload"
type="file"
onChange={(e) => {
e.stopPropagation()
_paq.push([
'trackEvent',
'fileExplorer',
'fileAction',
action
])
props.uploadFile(e.target)
e.target.value = null
}}
multiple
/>
</label>
</CustomTooltip>
)
@ -102,22 +129,38 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => {
placement={placement as Placement}
tooltipId="uploadFolderTooltip"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id={`filePanel.${action}`} defaultMessage={title} />}
tooltipText={
<FormattedMessage
id={`filePanel.${action}`}
defaultMessage={title}
/>
}
key={`index-${action}-${placement}-${icon}`}
>
<label
id={action}
data-id={'fileExplorerUploadFolder' + action }
data-id={'fileExplorerUploadFolder' + action}
className={icon + ' mb-0 px-1 remixui_newFile'}
key={`index-${action}-${placement}-${icon}`}
>
<input id="folderUpload" data-id="fileExplorerFolderUpload" type="file" onChange={(e) => {
e.stopPropagation()
_paq.push(['trackEvent', 'fileExplorer', 'fileAction', action])
props.uploadFolder(e.target)
e.target.value = null
}}
{...enableDirUpload} multiple />
<input
id="folderUpload"
data-id="fileExplorerFolderUpload"
type="file"
onChange={(e) => {
e.stopPropagation()
_paq.push([
'trackEvent',
'fileExplorer',
'fileAction',
action
])
props.uploadFolder(e.target)
e.target.value = null
}}
{...enableDirUpload}
multiple
/>
</label>
</CustomTooltip>
)
@ -127,7 +170,12 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => {
placement={placement as Placement}
tooltipId={`${action}-${title}-${icon}-${index}`}
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id={`filePanel.${action}`} defaultMessage={title} />}
tooltipText={
<FormattedMessage
id={`filePanel.${action}`}
defaultMessage={title}
/>
}
key={`${action}-${title}-${index}`}
>
<span
@ -135,7 +183,12 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => {
data-id={'fileExplorerNewFile' + action}
onClick={(e) => {
e.stopPropagation()
_paq.push(['trackEvent', 'fileExplorer', 'fileAction', action])
_paq.push([
'trackEvent',
'fileExplorer',
'fileAction',
action
])
if (action === 'createNewFile') {
props.createNewFile()
} else if (action === 'createNewFolder') {
@ -148,8 +201,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => {
}}
className={'newFile ' + icon + ' px-1 remixui_newFile'}
key={`${action}-${title}-${index}`}
>
</span>
></span>
</CustomTooltip>
)
}

@ -1,22 +1,41 @@
import React, { useEffect, useState, useRef, SyntheticEvent } from 'react' // eslint-disable-line
import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line
import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line
import { FileExplorerContextMenu } from './file-explorer-context-menu' // eslint-disable-line
import { FileExplorerProps, WorkSpaceState } from '../types'
import React, {useEffect, useState, useRef, SyntheticEvent} from 'react' // eslint-disable-line
import {TreeView, TreeViewItem} from '@remix-ui/tree-view' // eslint-disable-line
import {FileExplorerMenu} from './file-explorer-menu' // eslint-disable-line
import {FileExplorerContextMenu} from './file-explorer-context-menu' // eslint-disable-line
import {FileExplorerProps, WorkSpaceState} from '../types'
import '../css/file-explorer.css'
import { checkSpecialChars, extractNameFromKey, extractParentFromKey, joinPath } from '@remix-ui/helper'
import {
checkSpecialChars,
extractNameFromKey,
extractParentFromKey,
joinPath
} from '@remix-ui/helper'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { FileRender } from './file-render'
import { Drag } from "@remix-ui/drag-n-drop"
import { ROOT_PATH } from '../utils/constants'
import {FileRender} from './file-render'
import {Drag} from '@remix-ui/drag-n-drop'
import {ROOT_PATH} from '../utils/constants'
export const FileExplorer = (props: FileExplorerProps) => {
const { name, contextMenuItems, removedContextMenuItems, files, workspaceState, toGist, addMenuItems,
removeMenuItems, handleContextMenu, handleNewFileInput, handleNewFolderInput, uploadFile, uploadFolder, fileState } = props
const [state, setState] = useState<WorkSpaceState>( workspaceState)
const {
name,
contextMenuItems,
removedContextMenuItems,
files,
workspaceState,
toGist,
addMenuItems,
removeMenuItems,
handleContextMenu,
handleNewFileInput,
handleNewFolderInput,
uploadFile,
uploadFolder,
fileState
} = props
const [state, setState] = useState<WorkSpaceState>(workspaceState)
const treeRef = useRef<HTMLDivElement>(null)
useEffect(() => {
if (contextMenuItems) {
addMenuItems(contextMenuItems)
@ -31,8 +50,16 @@ export const FileExplorer = (props: FileExplorerProps) => {
useEffect(() => {
if (props.focusEdit) {
setState(prevState => {
return { ...prevState, focusEdit: { element: props.focusEdit, type: 'file', isNew: true, lastEdit: null } }
setState((prevState) => {
return {
...prevState,
focusEdit: {
element: props.focusEdit,
type: 'file',
isNew: true,
lastEdit: null
}
}
})
}
}, [props.focusEdit])
@ -45,21 +72,21 @@ export const FileExplorer = (props: FileExplorerProps) => {
if (treeRef.current) {
const keyPressHandler = (e: KeyboardEvent) => {
if (e.shiftKey) {
setState(prevState => {
return { ...prevState, ctrlKey: true }
setState((prevState) => {
return {...prevState, ctrlKey: true}
})
}
}
const keyUpHandler = (e: KeyboardEvent) => {
if (!e.shiftKey) {
setState(prevState => {
return { ...prevState, ctrlKey: false }
setState((prevState) => {
return {...prevState, ctrlKey: false}
})
}
}
const targetDocument = treeRef.current
targetDocument.addEventListener('keydown', keyPressHandler)
targetDocument.addEventListener('keyup', keyUpHandler)
return () => {
@ -70,7 +97,11 @@ export const FileExplorer = (props: FileExplorerProps) => {
}, [treeRef.current])
const hasReservedKeyword = (content: string): boolean => {
if (state.reservedKeywords.findIndex(value => content.startsWith(value)) !== -1) return true
if (
state.reservedKeywords.findIndex((value) => content.startsWith(value)) !==
-1
)
return true
else return false
}
@ -78,7 +109,12 @@ export const FileExplorer = (props: FileExplorerProps) => {
try {
props.dispatchCreateNewFile(newFilePath, ROOT_PATH)
} catch (error) {
return props.modal('File Creation Failed', typeof error === 'string' ? error : error.message, 'Close', async () => {})
return props.modal(
'File Creation Failed',
typeof error === 'string' ? error : error.message,
'Close',
async () => {}
)
}
}
@ -86,7 +122,12 @@ export const FileExplorer = (props: FileExplorerProps) => {
try {
props.dispatchCreateNewFolder(newFolderPath, ROOT_PATH)
} catch (e) {
return props.modal('Folder Creation Failed', typeof e === 'string' ? e : e.message, 'Close', async () => {})
return props.modal(
'Folder Creation Failed',
typeof e === 'string' ? e : e.message,
'Close',
async () => {}
)
}
}
@ -94,42 +135,66 @@ export const FileExplorer = (props: FileExplorerProps) => {
try {
props.dispatchRenamePath(oldPath, newPath)
} catch (error) {
props.modal('Rename File Failed', 'Unexpected error while renaming: ' + typeof error === 'string' ? error : error.message, 'Close', async () => {})
props.modal(
'Rename File Failed',
'Unexpected error while renaming: ' + typeof error === 'string'
? error
: error.message,
'Close',
async () => {}
)
}
}
const publishToGist = (path?: string, type?: string) => {
props.modal('Create a public gist', `Are you sure you want to anonymously publish all your files in the ${name} workspace as a public gist on github.com?`, 'OK', () => toGist(path, type), 'Cancel', () => {})
props.modal(
'Create a public gist',
`Are you sure you want to anonymously publish all your files in the ${name} workspace as a public gist on github.com?`,
'OK',
() => toGist(path, type),
'Cancel',
() => {}
)
}
const handleClickFile = (path: string, type: 'folder' | 'file' | 'gist') => {
if (!state.ctrlKey) {
props.dispatchHandleClickFile(path, type)
} else {
if (props.focusElement.findIndex(item => item.key === path) !== -1) {
const focusElement = props.focusElement.filter(item => item.key !== path)
if (props.focusElement.findIndex((item) => item.key === path) !== -1) {
const focusElement = props.focusElement.filter(
(item) => item.key !== path
)
props.dispatchSetFocusElement(focusElement)
} else {
const nonRootFocus = props.focusElement.filter((el) => { return !(el.key === '' && el.type === 'folder') })
const nonRootFocus = props.focusElement.filter((el) => {
return !(el.key === '' && el.type === 'folder')
})
nonRootFocus.push({ key: path, type })
nonRootFocus.push({key: path, type})
props.dispatchSetFocusElement(nonRootFocus)
}
}
}
const handleClickFolder = async (path: string, type: 'folder' | 'file' | 'gist') => {
const handleClickFolder = async (
path: string,
type: 'folder' | 'file' | 'gist'
) => {
if (state.ctrlKey) {
if (props.focusElement.findIndex(item => item.key === path) !== -1) {
const focusElement = props.focusElement.filter(item => item.key !== path)
if (props.focusElement.findIndex((item) => item.key === path) !== -1) {
const focusElement = props.focusElement.filter(
(item) => item.key !== path
)
props.dispatchSetFocusElement(focusElement)
} else {
const nonRootFocus = props.focusElement.filter((el) => { return !(el.key === '' && el.type === 'folder') })
const nonRootFocus = props.focusElement.filter((el) => {
return !(el.key === '' && el.type === 'folder')
})
nonRootFocus.push({ key: path, type })
nonRootFocus.push({key: path, type})
props.dispatchSetFocusElement(nonRootFocus)
}
} else {
@ -139,10 +204,16 @@ export const FileExplorer = (props: FileExplorerProps) => {
expandPath = [...new Set([...props.expandPath, path])]
props.dispatchFetchDirectory(path)
} else {
expandPath = [...new Set(props.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(path)))]
expandPath = [
...new Set(
props.expandPath.filter(
(key) => key && typeof key === 'string' && !key.startsWith(path)
)
)
]
}
props.dispatchSetFocusElement([{ key: path, type }])
props.dispatchSetFocusElement([{key: path, type}])
props.dispatchHandleExpandPath(expandPath)
}
}
@ -151,37 +222,63 @@ export const FileExplorer = (props: FileExplorerProps) => {
if (typeof content === 'string') content = content.trim()
const parentFolder = extractParentFromKey(state.focusEdit.element)
if (!content || (content.trim() === '')) {
if (!content || content.trim() === '') {
if (state.focusEdit.isNew) {
props.dispatchRemoveInputField(parentFolder)
setState(prevState => {
return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } }
setState((prevState) => {
return {
...prevState,
focusEdit: {element: null, isNew: false, type: '', lastEdit: ''}
}
})
} else {
setState(prevState => {
return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } }
setState((prevState) => {
return {
...prevState,
focusEdit: {element: null, isNew: false, type: '', lastEdit: ''}
}
})
}
} else {
if (state.focusEdit.lastEdit === content) {
return setState(prevState => {
return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } }
return setState((prevState) => {
return {
...prevState,
focusEdit: {element: null, isNew: false, type: '', lastEdit: ''}
}
})
}
if (checkSpecialChars(content)) {
props.modal('Validation Error', 'Special characters are not allowed', 'OK', () => {})
props.modal(
'Validation Error',
'Special characters are not allowed',
'OK',
() => {}
)
} else {
if (state.focusEdit.isNew) {
if (hasReservedKeyword(content)) {
props.dispatchRemoveInputField(parentFolder)
props.modal('Reserved Keyword', `File name contains Remix reserved keywords. '${content}'`, 'Close', () => {})
props.modal(
'Reserved Keyword',
`File name contains Remix reserved keywords. '${content}'`,
'Close',
() => {}
)
} else {
state.focusEdit.type === 'file' ? createNewFile(joinPath(parentFolder, content)) : createNewFolder(joinPath(parentFolder, content))
state.focusEdit.type === 'file'
? createNewFile(joinPath(parentFolder, content))
: createNewFolder(joinPath(parentFolder, content))
props.dispatchRemoveInputField(parentFolder)
}
} else {
if (hasReservedKeyword(content)) {
props.modal('Reserved Keyword', `File name contains Remix reserved keywords. '${content}'`, 'Close', () => {})
props.modal(
'Reserved Keyword',
`File name contains Remix reserved keywords. '${content}'`,
'Close',
() => {}
)
} else {
if (state.focusEdit.element) {
const oldPath: string = state.focusEdit.element
@ -192,24 +289,39 @@ export const FileExplorer = (props: FileExplorerProps) => {
}
}
}
setState(prevState => {
return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } }
setState((prevState) => {
return {
...prevState,
focusEdit: {element: null, isNew: false, type: '', lastEdit: ''}
}
})
}
}
}
const handleFileExplorerMenuClick = (e: SyntheticEvent) => {
e.stopPropagation()
if (e && (e.target as any).getAttribute('data-id') === 'fileExplorerUploadFileuploadFile') return // we don't want to let propagate the input of type file
if (e && (e.target as any).getAttribute('data-id') === 'fileExplorerFileUpload') return // we don't want to let propagate the input of type file
if (
e &&
(e.target as any).getAttribute('data-id') ===
'fileExplorerUploadFileuploadFile'
)
return // we don't want to let propagate the input of type file
if (
e &&
(e.target as any).getAttribute('data-id') === 'fileExplorerFileUpload'
)
return // we don't want to let propagate the input of type file
let expandPath = []
if (!props.expandPath.includes(ROOT_PATH)) {
expandPath = [ROOT_PATH, ...new Set([...props.expandPath])]
} else {
expandPath = [...new Set(props.expandPath.filter(key => key && (typeof key === 'string')))]
expandPath = [
...new Set(
props.expandPath.filter((key) => key && typeof key === 'string')
)
]
}
props.dispatchHandleExpandPath(expandPath)
}
@ -218,23 +330,34 @@ export const FileExplorer = (props: FileExplorerProps) => {
try {
props.dispatchMoveFile(src, dest)
} catch (error) {
props.modal('Moving File Failed', 'Unexpected error while moving file: ' + src, 'Close', async () => {})
}
props.modal(
'Moving File Failed',
'Unexpected error while moving file: ' + src,
'Close',
async () => {}
)
}
}
const handleFolderMove = (dest: string, src: string) => {
try {
props.dispatchMoveFolder(src, dest)
} catch (error) {
props.modal('Moving Folder Failed', 'Unexpected error while moving folder: ' + src, 'Close', async () => {})
}
props.modal(
'Moving Folder Failed',
'Unexpected error while moving folder: ' + src,
'Close',
async () => {}
)
}
}
return (
<Drag onFileMoved={handleFileMove} onFolderMoved={handleFolderMove}>
<div ref={treeRef} tabIndex={0} style={{ outline: "none" }}>
<TreeView id='treeView'>
<TreeViewItem id="treeViewItem"
<div ref={treeRef} tabIndex={0} style={{outline: 'none'}}>
<TreeView id="treeView">
<TreeViewItem
id="treeViewItem"
controlBehaviour={true}
label={
<div onClick={handleFileExplorerMenuClick}>
@ -249,28 +372,30 @@ export const FileExplorer = (props: FileExplorerProps) => {
/>
</div>
}
expand={true}>
<div className='pb-4 mb-4'>
<TreeView id='treeViewMenu'>
{
files[ROOT_PATH] && Object.keys(files[ROOT_PATH]).map((key, index) => <FileRender
file={files[ROOT_PATH][key]}
fileDecorations={fileState}
index={index}
focusContext={state.focusContext}
focusEdit={state.focusEdit}
focusElement={props.focusElement}
ctrlKey={state.ctrlKey}
expandPath={props.expandPath}
editModeOff={editModeOff}
handleClickFile={handleClickFile}
handleClickFolder={handleClickFolder}
handleContextMenu={handleContextMenu}
key={index}
showIconsMenu={props.showIconsMenu}
hideIconsMenu={props.hideIconsMenu}
/>)
}
expand={true}
>
<div className="pb-4 mb-4">
<TreeView id="treeViewMenu">
{files[ROOT_PATH] &&
Object.keys(files[ROOT_PATH]).map((key, index) => (
<FileRender
file={files[ROOT_PATH][key]}
fileDecorations={fileState}
index={index}
focusContext={state.focusContext}
focusEdit={state.focusEdit}
focusElement={props.focusElement}
ctrlKey={state.ctrlKey}
expandPath={props.expandPath}
editModeOff={editModeOff}
handleClickFile={handleClickFile}
handleClickFolder={handleClickFolder}
handleContextMenu={handleContextMenu}
key={index}
showIconsMenu={props.showIconsMenu}
hideIconsMenu={props.hideIconsMenu}
/>
))}
</TreeView>
</div>
</TreeViewItem>

Loading…
Cancel
Save