import { IndexLoaderData, paths } from 'Router' import { ActionButton } from './ActionButton' import Tooltip from './Tooltip' import { FileEntry } from '@tauri-apps/api/fs' import { Dispatch, useRef, useState } from 'react' import { useNavigate } from 'react-router-dom' import { Dialog, Disclosure } from '@headlessui/react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faChevronRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons' import { useFileContext } from 'hooks/useFileContext' import { useHotkeys } from 'react-hotkeys-hook' import { kclManager } from 'lang/KclSinglton' import styles from './FileTree.module.css' import { sortProject } from 'lib/tauriFS' function getIndentationCSS(level: number) { return `calc(1rem * ${level + 1})` } function RenameForm({ fileOrDir, setIsRenaming, level = 0, }: { fileOrDir: FileEntry setIsRenaming: Dispatch> level?: number }) { const { send } = useFileContext() const inputRef = useRef(null) function handleRenameSubmit(e: React.FormEvent) { e.preventDefault() setIsRenaming(false) send({ type: 'Rename file', data: { oldName: fileOrDir.name || '', newName: inputRef.current?.value || fileOrDir.name || '', isDir: fileOrDir.children !== undefined, }, }) } function handleKeyDown(e: React.KeyboardEvent) { if (e.key === 'Escape') { e.stopPropagation() setIsRenaming(false) } } return (
) } function DeleteConfirmationDialog({ fileOrDir, setIsOpen, }: { fileOrDir: FileEntry setIsOpen: Dispatch> }) { const { send } = useFileContext() return ( setIsOpen(false)} className="relative z-50" >
Delete {fileOrDir.children !== undefined ? 'Folder' : 'File'} This will permanently delete "{fileOrDir.name || 'this file'}" {fileOrDir.children !== undefined ? ' and all of its contents. ' : '. '} This action cannot be undone.
{ send({ type: 'Delete file', data: fileOrDir }) setIsOpen(false) }} icon={{ icon: faTrashAlt, bgClassName: 'bg-destroy-80', iconClassName: 'text-destroy-20 group-hover:text-destroy-10 hover:text-destroy-10 dark:text-destroy-20 dark:group-hover:text-destroy-10 dark:hover:text-destroy-10', }} className="hover:border-destroy-40 dark:hover:border-destroy-40" > Delete setIsOpen(false)}> Cancel
) } const FileTreeItem = ({ project, currentFile, fileOrDir, closePanel, level = 0, }: { project?: IndexLoaderData['project'] currentFile?: IndexLoaderData['file'] fileOrDir: FileEntry closePanel: ( focusableElement?: | HTMLElement | React.MutableRefObject | undefined ) => void level?: number }) => { const { send, context } = useFileContext() const navigate = useNavigate() const [isRenaming, setIsRenaming] = useState(false) const [isConfirmingDelete, setIsConfirmingDelete] = useState(false) const isCurrentFile = fileOrDir.path === currentFile?.path function handleKeyUp(e: React.KeyboardEvent) { if (e.metaKey && e.key === 'Backspace') { // Open confirmation dialog setIsConfirmingDelete(true) } else if (e.key === 'Enter') { // Show the renaming form setIsRenaming(true) } else if (e.code === 'Space') { openFile() } } function openFile() { if (fileOrDir.children !== undefined) return // Don't open directories kclManager.setCode('') navigate(`${paths.FILE}/${encodeURIComponent(fileOrDir.path)}`) closePanel() } return ( <> {fileOrDir.children === undefined ? (
  • {!isRenaming ? ( ) : ( )}
  • ) : ( {({ open }) => (
    {!isRenaming ? ( e.currentTarget.focus()} onClickCapture={(e) => send({ type: 'Set selected directory', data: fileOrDir }) } onFocusCapture={(e) => send({ type: 'Set selected directory', data: fileOrDir }) } onKeyDown={(e) => e.key === 'Enter' && e.preventDefault()} onKeyUp={handleKeyUp} > {fileOrDir.name} ) : (
    )}
      { send({ type: 'Set selected directory', data: fileOrDir }) }} onFocusCapture={(e) => send({ type: 'Set selected directory', data: fileOrDir }) } > {fileOrDir.children?.map((child) => ( ))}
    )}
    )} {isConfirmingDelete && ( )} ) } interface FileTreeProps { className?: string file?: IndexLoaderData['file'] closePanel: ( focusableElement?: | HTMLElement | React.MutableRefObject | undefined ) => void } export const FileTree = ({ className = '', file, closePanel, }: FileTreeProps) => { const { send, context } = useFileContext() useHotkeys('meta + n', createFile) useHotkeys('meta + shift + n', createFolder) async function createFile() { send({ type: 'Create file', data: { name: '', makeDir: false } }) } async function createFolder() { send({ type: 'Create file', data: { name: '', makeDir: true } }) } return (

    Files

    Create File Create Folder
      { send({ type: 'Set selected directory', data: context.project }) }} > {sortProject(context.project.children || []).map((fileOrDir) => ( ))}
    ) } function KclIcon({ className = '' }: { className?: string }) { return ( ) }