Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,69 @@ type File = {
| `primaryColor` | string | The primary color for the component's theme. Accepts any valid CSS color format (e.g., `'blue'`, `'#E97451'`, `'rgb(52, 152, 219)'`). This color will be applied to buttons, highlights, and other key elements. `default: #6155b4`. |
| `width` | string \| number | The width of the component `default: 100%`. Can be a string (e.g., `'100%'`, `'10rem'`) or a number (in pixels). |



## Action properties

| Property | Type | Description |
|---------------|------------|-------------------------------------------------------------------------------------------------------------------------|
| **title** | `string` | Display name of the action (e.g., "Rename", "Delete", "Download"). |
| **key** | `string` | Unique identifier for the action (e.g., "rename", "delete", "download"). |
| **onClick** | `Function` | Function executed when the action is triggered, receiving selected item/items as an argument. |
| **showToolbar** | `boolean` | Determines if the action appears in the toolbar (`true` = visible, `false` = hidden). |
| **showMenu** | `boolean` | Determines if the action appears in the context menu (`true` = visible, `false` = hidden). |
| **multiple** | `boolean` | Defines if the action supports multiple selections (`true` = supports multiple items, `false` = single selection only). |
| **applyTo** (TBD) | `string[]` \| `undefined` | Specifies applicable file types (e.g., folder, pdf, mp4). If undefined, the action applies to all types. |
| **icon** | `ReactNode` | Defines the icon associated with the action (e.g., "mdi-delete"). |
| **hidden** | `boolean` | Controls whether the action is hidden from the UI (`true` = hidden, `false` = visible). |


## Example Usage

```JSX
<FileManager
config={{
actions: [
{
title: "Open",
key: "open",
onClick: handleFileOpen,
showToolbar: false,
showMenu: true,
},
{
title: "Copy",
key: "copy",
onClick: handleCopy,
showToolbar: true,
showMenu: true,
},
{
title: "Custom Action",
key: "custom-action",
onClick: handleCustomAction,
showToolbar: true,
showMenu: false,
multiple: false,
applyTo: [''],
icon: <FaRegUser size={18} />,
hidden: false
},
],
}}
{...}
/>
```

## Notes

- `title` property might be handy to maintain internationalization(i18n).
- `applyTo` helps limit actions to **specific file types**, ensuring they are only displayed where applicable.
- `hidden: true` can be useful for **conditionally displaying actions** based on user roles, permissions, or UI state.

---


## ⌨️ Keyboard Shortcuts

| **Action** | **Shortcut** |
Expand Down Expand Up @@ -222,3 +285,4 @@ Check `backend/.env.example` for database configuration details.
## ©️ License

React File Manager is [MIT Licensed](LICENSE).

69 changes: 64 additions & 5 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { copyItemAPI, moveItemAPI } from "./api/fileTransferAPI";
import { getAllFilesAPI } from "./api/getAllFilesAPI";
import { downloadFile } from "./api/downloadFileAPI";
import "./App.scss";
import { FaRegPaste, FaRegUser } from "react-icons/fa6";

function App() {
const fileUploadConfig = {
Expand Down Expand Up @@ -109,6 +110,10 @@ function App() {
console.log(`Opening file: ${file.name}`);
};

const handleCustomAction = (file) => {
console.log(`Custom Action:`, file);
};

const handleError = (error, file) => {
console.error(error);
};
Expand All @@ -133,18 +138,72 @@ function App() {
<div className="app">
<div className="file-manager-container">
<FileManager
config={{
actions: [
{
key: "open",
onClick: handleFileOpen,
},
{
key: "copy",
onClick: handleCopy,
},
{
title: "Move",
key: "cut",
onClick: handleCut,
},
{
title: "Paste",
key: "paste",
onClick: handlePaste,
},
{
title: "Rename",
key: "rename",
onClick: handleRename,
},
{
title: "Delete",
key: "delete",
onClick: handleDelete,
},
{
title: "Download",
key: "download",
onClick: handleDownload,
},
{
title: "Custom Menu Action",
key: "custom-action",
onClick: handleCustomAction,
showToolbar: false,
showMenu: true,
multiple: false,
applyTo: [''], // TODO: types of file on which action will be visible (undefined | folder | pdf | mp4 | ect...)
icon: <FaRegPaste size={18} />,
hidden: false
},
{
title: "Toolbar Action",
key: "custom-tb-action",
onClick: handleCustomAction,
showToolbar: true,
showMenu: false,
multiple: false,
applyTo: [''],
icon: <FaRegUser size={18} />,
hidden: false
},
],
}}
files={files}
fileUploadConfig={fileUploadConfig}
isLoading={isLoading}
onCreateFolder={handleCreateFolder}
onFileUploading={handleFileUploading}
onFileUploaded={handleFileUploaded}
onCut={handleCut}
onCopy={handleCopy}
onPaste={handlePaste}
onRename={handleRename}
onDownload={handleDownload}
onDelete={handleDelete}
onLayoutChange={handleLayoutChange}
onRefresh={handleRefresh}
onFileOpen={handleFileOpen}
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/FileManager/FileList/FileItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import CreateFolderAction from "../Actions/CreateFolder/CreateFolder.action";
import RenameAction from "../Actions/Rename/Rename.action";
import { getDataSize } from "../../utils/getDataSize";
import { formatDate } from "../../utils/formatDate";
import { getActionByKey } from "../../utils/getActionByKey";
import { useFileNavigation } from "../../contexts/FileNavigationContext";
import { useSelection } from "../../contexts/SelectionContext";
import { useClipBoard } from "../../contexts/ClipboardContext";
Expand All @@ -16,10 +17,9 @@ const dragIconSize = 50;
const FileItem = ({
index,
file,
actions,
onCreateFolder,
onRename,
enableFilePreview,
onFileOpen,
filesViewRef,
selectedFileIndexes,
triggerAction,
Expand All @@ -46,7 +46,8 @@ const FileItem = ({
clipBoard.files.find((f) => f.name === file.name && f.path === file.path);

const handleFileAccess = () => {
onFileOpen(file);
const openAction = getActionByKey(actions, "open");
openAction.onClick(file);
if (file.isDirectory) {
setCurrentPath(file.path);
setSelectedFiles([]);
Expand Down Expand Up @@ -234,7 +235,7 @@ const FileItem = ({
<RenameAction
filesViewRef={filesViewRef}
file={file}
onRename={onRename}
onRename={getActionByKey(actions, "rename").onClick}
triggerAction={triggerAction}
/>
)}
Expand Down
10 changes: 4 additions & 6 deletions frontend/src/FileManager/FileList/FileList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ import "./FileList.scss";

const FileList = ({
onCreateFolder,
onRename,
onFileOpen,
onRefresh,
enableFilePreview,
triggerAction,
actions
}) => {
const { currentPathFiles } = useFileNavigation();
const filesViewRef = useRef(null);
Expand All @@ -31,7 +30,7 @@ const FileList = ({
selectedFileIndexes,
clickPosition,
isSelectionCtx,
} = useFileList(onRefresh, enableFilePreview, triggerAction);
} = useFileList(onRefresh, enableFilePreview, triggerAction, actions);

const contextMenuRef = useDetectOutsideClick(() => setVisible(false));

Expand All @@ -51,9 +50,8 @@ const FileList = ({
key={index}
index={index}
file={file}
actions={actions}
onCreateFolder={onCreateFolder}
onRename={onRename}
onFileOpen={onFileOpen}
enableFilePreview={enableFilePreview}
triggerAction={triggerAction}
filesViewRef={filesViewRef}
Expand All @@ -71,7 +69,7 @@ const FileList = ({
<ContextMenu
filesViewRef={filesViewRef}
contextMenuRef={contextMenuRef.ref}
menuItems={isSelectionCtx ? selecCtxItems : emptySelecCtxItems}
menuItems={isSelectionCtx ? selecCtxItems() : emptySelecCtxItems}
visible={visible}
setVisible={setVisible}
clickPosition={clickPosition}
Expand Down
Loading