import { ChangeEventHandler, FC, KeyboardEventHandler, useCallback, useEffect, useState } from "react"; import styles from "./FileExplorer.module.css"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faArrowUp, faCaretLeft, faCaretRight, faCircleInfo, faCog, faDesktop, faFileLines, faHouse, faImage, faPlus, faSearch, faTrash } from "@fortawesome/free-solid-svg-icons"; import { QuickAccessButton } from "./QuickAccessButton"; import { ImportButton } from "./ImportButton"; import { Actions, ClickAction, CODE_EXTENSIONS, DialogBox, DirectoryList, Divider, FileEventHandler, FolderEventHandler, ModalProps, ModalsConfig, OnSelectionChangeParams, useAlert, useContextMenu, useHistory, useSystemManager, useVirtualRoot, useWindowedModal, useWindowsManager, utilStyles, Vector2, VirtualFile, VirtualFolder, VirtualFolderLink, VirtualRoot, WindowProps } from "@prozilla-os/core"; import { SELECTOR_MODE } from "../constants/fileExplorer.const"; import { FileProperties } from "./modals/file-properties/FileProperties"; import { JSX } from "react/jsx-runtime"; export interface FileExplorerProps extends WindowProps { path?: string; selectorMode?: number; Footer: FC; onSelectionChange: (params: OnSelectionChangeParams) => void; onSelectionFinish: Function; } export function FileExplorer({ app, path: startPath, selectorMode, Footer, onSelectionChange, onSelectionFinish }: FileExplorerProps) { const isSelector = (Footer != null && selectorMode != null && selectorMode !== SELECTOR_MODE.NONE); const virtualRoot = useVirtualRoot(); const windowsManager = useWindowsManager(); const { windowsConfig } = useSystemManager(); const [currentDirectory, setCurrentDirectory] = useState(virtualRoot?.navigate(startPath ?? "~") as VirtualFolder); const [path, setPath] = useState(currentDirectory?.path ?? ""); const [showHidden] = useState(true); const { history, stateIndex, pushState, undo, redo, undoAvailable, redoAvailable } = useHistory(currentDirectory.path); const { alert } = useAlert(); const { openWindowedModal } = useWindowedModal(); const { onContextMenu: onContextMenuFile } = useContextMenu({ Actions: (props) => { if (isSelector) { onSelectionChange?.({ files: [(file as VirtualFile).id], directory: currentDirectory }); onSelectionFinish?.(); return; } if (windowsManager != null) (file as VirtualFile).open(windowsManager); }}/> { (file as VirtualFile).delete(); }}/> { openWindowedModal({ title: `${(file as VirtualFile).id} ${windowsConfig.titleSeparator} Properties`, iconUrl: (file as VirtualFile).getIconUrl(), size: new Vector2(400, 500), Modal: (props: object) => }); }}/> }); const { onContextMenu: onContextMenuFolder } = useContextMenu({ Actions: (props) => { changeDirectory((folder as VirtualFolderLink).linkedPath ?? (folder as VirtualFolder).name); }}/> {/* { windowsManager?.open(APPS.TERMINAL, { startPath: (folder as VirtualFolder).path }); }}/> */} { (folder as VirtualFolder).delete(); }}/> }); // const { onContextMenu: onNew } = useContextMenu({ // modalsManager, // options: { // "File": () => { currentDirectory.createFile("New File"); }, // "Folder": () => { currentDirectory.createFolder("New Folder"); } // } // }); const changeDirectory = useCallback((path: string, absolute = false) => { if (path == null) return; if (currentDirectory == null) absolute = true; const directory = absolute ? virtualRoot?.navigate(path) : currentDirectory.navigate(path); if (directory != null) { setCurrentDirectory(directory as VirtualFolder); setPath(directory.root ? "/" : directory.path); pushState(directory.path); } }, [currentDirectory, pushState, virtualRoot]); useEffect(() => { if (history.length === 0) return; const path = history[stateIndex]; const directory = virtualRoot?.navigate(path); if (directory != null) { setCurrentDirectory(directory as VirtualFolder); setPath(directory.root ? "/" : directory.path); } }, [history, stateIndex, virtualRoot]); useEffect(() => { type Error = { message: string }; const onError = (error: unknown) => { alert({ title: (error as Error).message, text: "You have exceeded the virtual drive capacity. Files and folders will not be saved until more storage is freed.", iconUrl: app?.iconUrl as string | undefined, size: new Vector2(300, 200), single: true, }); }; virtualRoot?.on(VirtualRoot.EVENT_NAMES.ERROR, onError); return () => { virtualRoot?.off(VirtualRoot.EVENT_NAMES.ERROR, onError); }; }, []); const onPathChange = (event: Event) => { setPath((event.target as HTMLInputElement).value); }; const onKeyDown = (event: KeyboardEvent) => { let value = (event.target as HTMLInputElement).value; if (event.key === "Enter") { if (value === "") value = "~"; const directory = virtualRoot?.navigate(value); if (directory == null) { openWindowedModal({ title: "Error", iconUrl: app?.iconUrl as string | undefined, size: new Vector2(300, 150), Modal: (props: JSX.IntrinsicAttributes & ModalProps) =>

Invalid path: "{value}"

}); return; } setCurrentDirectory(directory as VirtualFolder); setPath(directory.root ? "/" : directory.path); } }; const itemCount = currentDirectory.getItemCount(showHidden); return (
}); // if (currentDirectory.canBeEdited) { // onNew(event); // } else { // } }} disabled={!currentDirectory.canBeEdited} >
{ changeDirectory("~"); }} icon={faHouse}/> { changeDirectory("~/Desktop"); }} icon={faDesktop}/> { changeDirectory("~/Pictures"); }} icon={faImage}/> { changeDirectory("~/Documents"); }} icon={faFileLines}/>
{ event.preventDefault(); if (isSelector) return void onSelectionFinish?.(); const options: Record = {}; if (file.extension === "md" || (file.extension != null && CODE_EXTENSIONS.includes(file.extension))) options.mode = "view"; windowsManager?.openFile(file, options); }} onOpenFolder={(event, folder) => { changeDirectory((folder as VirtualFolderLink).linkedPath ?? folder.name); }} onContextMenuFile={onContextMenuFile as unknown as FileEventHandler} onContextMenuFolder={onContextMenuFolder as unknown as FolderEventHandler} allowMultiSelect={selectorMode !== SELECTOR_MODE.SINGLE} onSelectionChange={onSelectionChange} />
{!isSelector ?

{itemCount === 1 ? itemCount + " item" : itemCount + " items" }

:
}
); }