Skip to content

Commit ec9fb6c

Browse files
Merge pull request #192 from Saifullah-dev/fix/toggle-navigation-pane
Add collapsible navigation pane
2 parents e5263d7 + 25151b6 commit ec9fb6c

23 files changed

+151
-41
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ type File = {
101101
| Name | Type | Description |
102102
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
103103
| `acceptedFileTypes` | string | (Optional) A comma-separated list of allowed file extensions for uploading specific file types (e.g., `.txt, .png, .pdf`). If omitted, all file types are accepted. |
104+
| `collapsibleNav` | boolean | Enables a collapsible navigation pane on the left side. When `true`, a toggle will be shown to expand or collapse the navigation pane. `default: false`. |
105+
| `defaultNavExpanded` | boolean | Sets the default expanded (`true`) or collapsed (`false`) state of the navigation pane when `collapsibleNav` is enabled. This only affects the initial render. `default: true`. |
104106
| `enableFilePreview` | boolean | A boolean flag indicating whether to use the default file previewer in the file manager `default: true`. |
105107
| `filePreviewPath` | string | The base URL for file previews e.g.`https://example.com`, file path will be appended automatically to it i.e. `https://example.com/yourFilePath`. |
106108
| `filePreviewComponent` | (file: [File](#-file-structure)) => React.ReactNode | (Optional) A callback function that provides a custom file preview. It receives the selected file as its argument and must return a valid React node, JSX element, or HTML. Use this prop to override the default file preview behavior. Example: [Custom Preview Usage](#custom-file-preview). |

frontend/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ type File = {
101101
| Name | Type | Description |
102102
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
103103
| `acceptedFileTypes` | string | (Optional) A comma-separated list of allowed file extensions for uploading specific file types (e.g., `.txt, .png, .pdf`). If omitted, all file types are accepted. |
104+
| `collapsibleNav` | boolean | Enables a collapsible navigation pane on the left side. When `true`, a toggle will be shown to expand or collapse the navigation pane. `default: false`. |
105+
| `defaultNavExpanded` | boolean | Sets the default expanded (`true`) or collapsed (`false`) state of the navigation pane when `collapsibleNav` is enabled. This only affects the initial render. `default: true`. |
104106
| `enableFilePreview` | boolean | A boolean flag indicating whether to use the default file previewer in the file manager `default: true`. |
105107
| `filePreviewPath` | string | The base URL for file previews e.g.`https://example.com`, file path will be appended automatically to it i.e. `https://example.com/yourFilePath`. |
106108
| `filePreviewComponent` | (file: [File](#-file-structure)) => React.ReactNode | (Optional) A callback function that provides a custom file preview. It receives the selected file as its argument and must return a valid React node, JSX element, or HTML. Use this prop to override the default file preview behavior. Example: [Custom Preview Usage](#custom-file-preview). |

frontend/src/FileManager/BreadCrumb/BreadCrumb.jsx

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { useEffect, useRef, useState } from "react";
2+
import PropTypes from "prop-types";
23
import { MdHome, MdMoreHoriz, MdOutlineNavigateNext } from "react-icons/md";
4+
import { TbLayoutSidebarLeftExpand, TbLayoutSidebarLeftCollapseFilled } from "react-icons/tb";
35
import { useFileNavigation } from "../../contexts/FileNavigationContext";
46
import { useDetectOutsideClick } from "../../hooks/useDetectOutsideClick";
57
import { useTranslation } from "../../contexts/TranslationProvider";
68
import "./BreadCrumb.scss";
79

8-
const BreadCrumb = () => {
10+
const BreadCrumb = ({ collapsibleNav, isNavigationPaneOpen, setNavigationPaneOpen }) => {
911
const [folders, setFolders] = useState([]);
1012
const [hiddenFolders, setHiddenFolders] = useState([]);
1113
const [hiddenFoldersWidth, setHiddenFoldersWidth] = useState([]);
@@ -19,6 +21,7 @@ const BreadCrumb = () => {
1921
setShowHiddenFolders(false);
2022
});
2123
const t = useTranslation();
24+
const navTogglerRef = useRef(null);
2225

2326
useEffect(() => {
2427
setFolders(() => {
@@ -42,9 +45,14 @@ const BreadCrumb = () => {
4245
const containerWidth = breadCrumbRef.current.clientWidth;
4346
const containerStyles = getComputedStyle(breadCrumbRef.current);
4447
const paddingLeft = parseFloat(containerStyles.paddingLeft);
48+
const navTogglerGap = collapsibleNav ? 2 : 0;
49+
const navTogglerDividerWidth = 1;
50+
const navTogglerWidth = collapsibleNav
51+
? navTogglerRef.current?.clientWidth + navTogglerDividerWidth
52+
: 0;
4553
const moreBtnGap = hiddenFolders.length > 0 ? 1 : 0;
46-
const flexGap = parseFloat(containerStyles.gap) * (folders.length + moreBtnGap);
47-
return containerWidth - (paddingLeft + flexGap);
54+
const flexGap = parseFloat(containerStyles.gap) * (folders.length + moreBtnGap + navTogglerGap);
55+
return containerWidth - (paddingLeft + flexGap + navTogglerWidth);
4856
};
4957

5058
const checkAvailableSpace = () => {
@@ -79,6 +87,29 @@ const BreadCrumb = () => {
7987
return (
8088
<div className="bread-crumb-container">
8189
<div className="breadcrumb" ref={breadCrumbRef}>
90+
{collapsibleNav && (
91+
<>
92+
<div
93+
ref={navTogglerRef}
94+
className="nav-toggler"
95+
title={`${
96+
isNavigationPaneOpen ? t("collapseNavigationPane") : t("expandNavigationPane")
97+
}`}
98+
>
99+
<span
100+
className="folder-name folder-name-btn"
101+
onClick={() => setNavigationPaneOpen((prev) => !prev)}
102+
>
103+
{isNavigationPaneOpen ? (
104+
<TbLayoutSidebarLeftCollapseFilled />
105+
) : (
106+
<TbLayoutSidebarLeftExpand />
107+
)}
108+
</span>
109+
</div>
110+
<div className="divider" />
111+
</>
112+
)}
82113
{folders.map((folder, index) => (
83114
<div key={index} style={{ display: "contents" }}>
84115
<span
@@ -124,4 +155,9 @@ const BreadCrumb = () => {
124155

125156
BreadCrumb.displayName = "BreadCrumb";
126157

158+
BreadCrumb.propTypes = {
159+
isNavigationPaneOpen: PropTypes.bool.isRequired,
160+
setNavigationPaneOpen: PropTypes.func.isRequired,
161+
};
162+
127163
export default BreadCrumb;

frontend/src/FileManager/BreadCrumb/BreadCrumb.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@
2121
background: var(--file-manager-primary-color) !important;
2222
}
2323

24+
.nav-toggler {
25+
display: flex;
26+
align-items: center;
27+
}
28+
29+
.divider {
30+
width: 1px;
31+
background-color: $border-color;
32+
}
33+
2434
.folder-name {
2535
display: flex;
2636
align-items: center;

frontend/src/FileManager/FileManager.jsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { useColumnResize } from "../hooks/useColumnResize";
1414
import PropTypes from "prop-types";
1515
import { dateStringValidator, urlValidator } from "../validators/propValidators";
1616
import { TranslationProvider } from "../contexts/TranslationProvider";
17-
import { useMemo } from "react";
17+
import { useMemo, useState } from "react";
1818
import { defaultPermissions } from "../constants";
1919
import "./FileManager.scss";
2020

@@ -49,7 +49,10 @@ const FileManager = ({
4949
fontFamily = "Nunito Sans, sans-serif",
5050
language = "en",
5151
permissions: userPermissions = {},
52+
collapsibleNav = false,
53+
defaultNavExpanded = true,
5254
}) => {
55+
const [isNavigationPaneOpen, setNavigationPaneOpen] = useState(defaultNavExpanded);
5356
const triggerAction = useTriggerAction();
5457
const { containerRef, colSizes, isDragging, handleMouseMove, handleMouseUp, handleMouseDown } =
5558
useColumnResize(20, 80);
@@ -86,16 +89,28 @@ const FileManager = ({
8689
onMouseUp={handleMouseUp}
8790
className="files-container"
8891
>
89-
<div className="navigation-pane" style={{ width: colSizes.col1 + "%" }}>
92+
<div
93+
className={`navigation-pane ${isNavigationPaneOpen ? "open" : "closed"}`}
94+
style={{
95+
width: colSizes.col1 + "%",
96+
}}
97+
>
9098
<NavigationPane onFileOpen={onFileOpen} />
9199
<div
92100
className={`sidebar-resize ${isDragging ? "sidebar-dragging" : ""}`}
93101
onMouseDown={handleMouseDown}
94102
/>
95103
</div>
96104

97-
<div className="folders-preview" style={{ width: colSizes.col2 + "%" }}>
98-
<BreadCrumb />
105+
<div
106+
className="folders-preview"
107+
style={{ width: (isNavigationPaneOpen ? colSizes.col2 : 100) + "%" }}
108+
>
109+
<BreadCrumb
110+
collapsibleNav={collapsibleNav}
111+
isNavigationPaneOpen={isNavigationPaneOpen}
112+
setNavigationPaneOpen={setNavigationPaneOpen}
113+
/>
99114
<FileList
100115
onCreateFolder={onCreateFolder}
101116
onRename={onRename}
@@ -184,6 +199,8 @@ FileManager.propTypes = {
184199
download: PropTypes.bool,
185200
delete: PropTypes.bool,
186201
}),
202+
collapsibleNav: PropTypes.bool,
203+
defaultNavExpanded: PropTypes.bool,
187204
};
188205

189206
export default FileManager;

frontend/src/FileManager/FileManager.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,21 @@ svg {
7878
}
7979
}
8080

81+
.navigation-pane.open {
82+
display: block;
83+
}
84+
85+
.navigation-pane.closed {
86+
display: none;
87+
}
88+
8189
.folders-preview {
8290
z-index: 2;
8391
background-color: white;
8492
padding-right: 0px;
8593
padding-left: 0px;
8694
border-bottom-right-radius: 8px;
95+
border-bottom-left-radius: 8px;
8796
}
8897
}
8998
}

frontend/src/locales/ar-SA.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,7 @@
4848
"percentDone": "{{percent}}% تم",
4949
"canceled": "تم الإلغاء",
5050
"invalidFileName": "لا يمكن أن يحتوي اسم الملف على أي من الحروف التالية: \\ / : * ? \" < > |",
51-
"folderExists": "هذا الموقع يحتوي بالفعل على مجلد باسم \"{{renameFile}}\"."
52-
}
51+
"folderExists": "هذا الموقع يحتوي بالفعل على مجلد باسم \"{{renameFile}}\".",
52+
"collapseNavigationPane": "طي لوحة التنقل",
53+
"expandNavigationPane": "توسيع لوحة التنقل"
54+
}

frontend/src/locales/de-DE.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,7 @@
4848
"percentDone": "{{percent}}% erledigt",
4949
"canceled": "Abgebrochen",
5050
"invalidFileName": "Ein Dateiname darf keines der folgenden Zeichen enthalten: \\ / : * ? \" < > |",
51-
"folderExists": "In diesem Zielordner gibt es bereits einen Ordner namens \"{{renameFile}}\"."
52-
}
51+
"folderExists": "In diesem Zielordner gibt es bereits einen Ordner namens \"{{renameFile}}\".",
52+
"collapseNavigationPane": "Navigationsbereich einklappen",
53+
"expandNavigationPane": "Navigationsbereich erweitern"
54+
}

frontend/src/locales/en-US.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,7 @@
4848
"percentDone": "{{percent}}% done",
4949
"canceled": "Canceled",
5050
"invalidFileName": "A file name can't contain any of the following characters: \\ / : * ? \" < > |",
51-
"folderExists": "This destination already contains a folder named \"{{renameFile}}\"."
52-
}
51+
"folderExists": "This destination already contains a folder named \"{{renameFile}}\".",
52+
"collapseNavigationPane": "Collapse Navigation Pane",
53+
"expandNavigationPane": "Expand Navigation Pane"
54+
}

frontend/src/locales/es-ES.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,7 @@
4848
"percentDone": "{{percent}}% completado",
4949
"canceled": "Cancelado",
5050
"invalidFileName": "Un nombre de archivo no puede contener ninguno de los siguientes caracteres: \\ / : * ? \" < > |",
51-
"folderExists": "Ya existe una carpeta llamada \"{{renameFile}}\" en este destino."
52-
}
51+
"folderExists": "Ya existe una carpeta llamada \"{{renameFile}}\" en este destino.",
52+
"collapseNavigationPane": "Contraer panel de navegación",
53+
"expandNavigationPane": "Expandir panel de navegación"
54+
}

frontend/src/locales/fr-FR.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,7 @@
4848
"percentDone": "{{percent}}% terminé",
4949
"canceled": "Annulé",
5050
"invalidFileName": "Un nom de fichier ne peut pas contenir les caractères suivants : \\ / : * ? \" < > |",
51-
"folderExists": "Cette destination contient déjà un dossier nommé \"{{renameFile}}\"."
52-
}
51+
"folderExists": "Cette destination contient déjà un dossier nommé \"{{renameFile}}\".",
52+
"collapseNavigationPane": "Réduire le panneau de navigation",
53+
"expandNavigationPane": "Développer le panneau de navigation"
54+
}

0 commit comments

Comments
 (0)