diff --git a/README.md b/README.md index 768dfb3..64905a8 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ type File = { | `fileUploadConfig` | { url: string; headers?: { [key: string]: string } } | Configuration object for file uploads. It includes the upload URL (`url`) and an optional `headers` object for setting custom HTTP headers in the upload request. The `headers` object can accept any standard or custom headers required by the server. Example: `{ url: "https://example.com/fileupload", headers: { Authorization: "Bearer" + TOKEN, "X-Custom-Header": "value" } }` | | `files` | Array<[File](#-file-structure)> | An array of file and folder objects representing the current directory structure. Each object includes `name`, `isDirectory`, and `path` properties. | | `height` | string \| number | The height of the component `default: 600px`. Can be a string (e.g., `'100%'`, `'10rem'`) or a number (in pixels). | -| `initialPath` | string | The path of the directory to be loaded initially.This path should be a path of a folder which is included in `files` array. | +| `initialPath` | string | The path of the directory to be loaded initially e.g. `/Documents`. This should be the path of a folder which is included in `files` array. Default value is `""` | | `isLoading` | boolean | A boolean state indicating whether the application is currently performing an operation, such as creating, renaming, or deleting a file/folder. Displays a loading state if set `true`. | | `layout` | "list" \| "grid" | Specifies the default layout style for the file manager. Can be either "list" or "grid". Default value is "grid". | | `maxFileSize` | number | For limiting the maximum upload file size in bytes. | diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 0000000..2ffab02 --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1,2 @@ +VITE_API_BASE_URL=http://localhost:3000/api/file-system +VITE_API_FILES_BASE_URL=http://localhost:3000 \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md index 9b2aaa5..64905a8 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -96,6 +96,7 @@ type File = { | `fileUploadConfig` | { url: string; headers?: { [key: string]: string } } | Configuration object for file uploads. It includes the upload URL (`url`) and an optional `headers` object for setting custom HTTP headers in the upload request. The `headers` object can accept any standard or custom headers required by the server. Example: `{ url: "https://example.com/fileupload", headers: { Authorization: "Bearer" + TOKEN, "X-Custom-Header": "value" } }` | | `files` | Array<[File](#-file-structure)> | An array of file and folder objects representing the current directory structure. Each object includes `name`, `isDirectory`, and `path` properties. | | `height` | string \| number | The height of the component `default: 600px`. Can be a string (e.g., `'100%'`, `'10rem'`) or a number (in pixels). | +| `initialPath` | string | The path of the directory to be loaded initially e.g. `/Documents`. This should be the path of a folder which is included in `files` array. Default value is `""` | | `isLoading` | boolean | A boolean state indicating whether the application is currently performing an operation, such as creating, renaming, or deleting a file/folder. Displays a loading state if set `true`. | | `layout` | "list" \| "grid" | Specifies the default layout style for the file manager. Can be either "list" or "grid". Default value is "grid". | | `maxFileSize` | number | For limiting the maximum upload file size in bytes. | diff --git a/frontend/src/FileManager/FileList/FilesHeader.jsx b/frontend/src/FileManager/FileList/FilesHeader.jsx index 95a2207..753aae4 100644 --- a/frontend/src/FileManager/FileList/FilesHeader.jsx +++ b/frontend/src/FileManager/FileList/FilesHeader.jsx @@ -10,7 +10,7 @@ const FilesHeader = ({ unselectFiles }) => { const { currentPathFiles } = useFileNavigation(); const allFilesSelected = useMemo(() => { - return selectedFiles.length === currentPathFiles.length; + return currentPathFiles.length > 0 && selectedFiles.length === currentPathFiles.length; }, [selectedFiles, currentPathFiles]); const handleSelectAll = (e) => { @@ -30,7 +30,7 @@ const FilesHeader = ({ unselectFiles }) => { >
{(showSelectAll || allFilesSelected) && ( - + )}
Name
diff --git a/frontend/src/components/Checkbox/Checkbox.jsx b/frontend/src/components/Checkbox/Checkbox.jsx index a31e7db..7e804b6 100644 --- a/frontend/src/components/Checkbox/Checkbox.jsx +++ b/frontend/src/components/Checkbox/Checkbox.jsx @@ -1,6 +1,6 @@ import "./Checkbox.scss"; -const Checkbox = ({ name, id, checked, onClick, onChange, className = "", title }) => { +const Checkbox = ({ name, id, checked, onClick, onChange, className = "", title, disabled = false }) => { return ( ); }; diff --git a/frontend/src/components/Checkbox/Checkbox.scss b/frontend/src/components/Checkbox/Checkbox.scss index 5614618..1e34e6b 100644 --- a/frontend/src/components/Checkbox/Checkbox.scss +++ b/frontend/src/components/Checkbox/Checkbox.scss @@ -1,6 +1,10 @@ .fm-checkbox { accent-color: white; + &:disabled { + cursor: default !important; + } + &:hover { cursor: pointer; } diff --git a/frontend/src/components/ContextMenu/ContextMenu.jsx b/frontend/src/components/ContextMenu/ContextMenu.jsx index 916031d..170cb32 100644 --- a/frontend/src/components/ContextMenu/ContextMenu.jsx +++ b/frontend/src/components/ContextMenu/ContextMenu.jsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { FaChevronRight } from "react-icons/fa6"; import SubMenu from "./SubMenu"; import "./ContextMenu.scss"; @@ -7,6 +7,9 @@ const ContextMenu = ({ filesViewRef, contextMenuRef, menuItems, visible, clickPo const [left, setLeft] = useState(0); const [top, setTop] = useState(0); const [activeSubMenuIndex, setActiveSubMenuIndex] = useState(null); + const [subMenuPosition, setSubMenuPosition] = useState("right"); + + const subMenuRef = useRef(null); const contextMenuPosition = () => { const { clickX, clickY } = clickPosition; @@ -31,9 +34,11 @@ const ContextMenu = ({ filesViewRef, contextMenuRef, menuItems, visible, clickPo if (right) { setLeft(`${leftToCursor}px`); + setSubMenuPosition("right"); } else if (left) { // Location: -width of the context menu from cursor's position i.e. left side setLeft(`${leftToCursor - menuWidth}px`); + setSubMenuPosition("left"); } if (top) { @@ -80,7 +85,7 @@ const ContextMenu = ({ filesViewRef, contextMenuRef, menuItems, visible, clickPo .filter((item) => !item.hidden) .map((item, index) => { const hasChildren = item.hasOwnProperty("children"); - const activeSubMenu = activeSubMenuIndex === index; + const activeSubMenu = activeSubMenuIndex === index && hasChildren; return (
  • - {activeSubMenu && } + {activeSubMenu && ( + + )} )}
  • diff --git a/frontend/src/components/ContextMenu/ContextMenu.scss b/frontend/src/components/ContextMenu/ContextMenu.scss index 3ab6754..ab33754 100644 --- a/frontend/src/components/ContextMenu/ContextMenu.scss +++ b/frontend/src/components/ContextMenu/ContextMenu.scss @@ -60,7 +60,6 @@ .sub-menu { position: absolute; - left: calc(100% - 2px); top: 0; background-color: white; border: 1px solid #c6c6c6; @@ -80,6 +79,14 @@ } } } + + .sub-menu.right { + left: calc(100% - 2px); + } + + .sub-menu.left { + left: calc(-83%); + } } } diff --git a/frontend/src/components/ContextMenu/SubMenu.jsx b/frontend/src/components/ContextMenu/SubMenu.jsx index df04d88..6e9dc08 100644 --- a/frontend/src/components/ContextMenu/SubMenu.jsx +++ b/frontend/src/components/ContextMenu/SubMenu.jsx @@ -1,8 +1,8 @@ import { FaCheck } from "react-icons/fa6"; -const SubMenu = ({ list }) => { +const SubMenu = ({ subMenuRef, list, position = "right" }) => { return ( -