Skip to content

Commit bc2d68a

Browse files
Merge pull request #68 from Saifullah-dev/65-breadcrumb-handle-overflow
65 breadcrumb handle overflow
2 parents d9185cb + c522dd3 commit bc2d68a

File tree

6 files changed

+188
-56
lines changed

6 files changed

+188
-56
lines changed

frontend/src/FileManager/BreadCrumb/BreadCrumb.jsx

Lines changed: 106 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,121 @@
1-
import { useEffect, useState } from "react";
2-
import { MdHome, MdOutlineNavigateNext } from "react-icons/md";
3-
import "./BreadCrumb.scss";
1+
import { useEffect, useRef, useState } from "react";
2+
import { MdHome, MdMoreHoriz, MdOutlineNavigateNext } from "react-icons/md";
43
import { useFileNavigation } from "../../contexts/FileNavigationContext";
4+
import { useDetectOutsideClick } from "../../hooks/useDetectOutsideClick";
5+
import "./BreadCrumb.scss";
56

67
const BreadCrumb = () => {
78
const [folders, setFolders] = useState([]);
9+
const [hiddenFolders, setHiddenFolders] = useState([]);
10+
const [hiddenFoldersWidth, setHiddenFoldersWidth] = useState([]);
11+
const [showHiddenFolders, setShowHiddenFolders] = useState(false);
12+
813
const { currentPath, setCurrentPath } = useFileNavigation();
14+
const breadCrumbRef = useRef(null);
15+
const foldersRef = useRef([]);
16+
const moreBtnRef = useRef(null);
17+
const popoverRef = useDetectOutsideClick(() => {
18+
setShowHiddenFolders(false);
19+
});
920

1021
useEffect(() => {
11-
setFolders(currentPath?.split("/"));
22+
setFolders(() => {
23+
let path = "";
24+
return currentPath?.split("/").map((item) => {
25+
return {
26+
name: item || "Home",
27+
path: item === "" ? item : (path += `/${item}`),
28+
};
29+
});
30+
});
31+
setHiddenFolders([]);
32+
setHiddenFoldersWidth([]);
1233
}, [currentPath]);
1334

14-
const switchPath = (index) => {
15-
if (index < folders.length - 1) {
16-
setCurrentPath(() => {
17-
const toSlice = folders.length - (index + 1);
18-
const switchFolders = folders.slice(0, -toSlice);
19-
return switchFolders.join("/");
20-
});
21-
}
35+
const switchPath = (path) => {
36+
setCurrentPath(path);
37+
};
38+
39+
const getBreadCrumbWidth = () => {
40+
const containerWidth = breadCrumbRef.current.clientWidth;
41+
const containerStyles = getComputedStyle(breadCrumbRef.current);
42+
const paddingLeft = parseFloat(containerStyles.paddingLeft);
43+
const moreBtnGap = hiddenFolders.length > 0 ? 1 : 0;
44+
const flexGap = parseFloat(containerStyles.gap) * (folders.length + moreBtnGap);
45+
return containerWidth - (paddingLeft + flexGap);
2246
};
2347

48+
const checkAvailableSpace = () => {
49+
const availableSpace = getBreadCrumbWidth();
50+
const remainingFoldersWidth = foldersRef.current.reduce((prev, curr) => {
51+
if (!curr) return prev;
52+
return prev + curr.clientWidth;
53+
}, 0);
54+
const moreBtnWidth = moreBtnRef.current?.clientWidth || 0;
55+
return availableSpace - (remainingFoldersWidth + moreBtnWidth);
56+
};
57+
58+
const isBreadCrumbOverflowing = () => {
59+
return breadCrumbRef.current.scrollWidth > breadCrumbRef.current.clientWidth;
60+
};
61+
62+
useEffect(() => {
63+
if (isBreadCrumbOverflowing()) {
64+
const hiddenFolder = folders[1];
65+
const hiddenFolderWidth = foldersRef.current[1]?.clientWidth;
66+
setHiddenFoldersWidth((prev) => [...prev, hiddenFolderWidth]);
67+
setHiddenFolders((prev) => [...prev, hiddenFolder]);
68+
setFolders((prev) => prev.filter((_, index) => index !== 1));
69+
} else if (hiddenFolders.length > 0 && checkAvailableSpace() > hiddenFoldersWidth.at(-1)) {
70+
const newFolders = [folders[0], hiddenFolders.at(-1), ...folders.slice(1)];
71+
setFolders(newFolders);
72+
setHiddenFolders((prev) => prev.slice(0, -1));
73+
setHiddenFoldersWidth((prev) => prev.slice(0, -1));
74+
}
75+
}, [isBreadCrumbOverflowing]);
76+
2477
return (
25-
<div className="breadcrumb">
26-
{folders.map((folder, index) => (
27-
<span key={index} className="folder-name" onClick={() => switchPath(index)}>
28-
{index === 0 ? (
29-
<>
30-
<MdHome /> Home
31-
</>
32-
) : (
33-
<>
34-
<MdOutlineNavigateNext /> {folder}
35-
</>
36-
)}
37-
</span>
38-
))}
78+
<div className="bread-crumb-container">
79+
<div className="breadcrumb" ref={breadCrumbRef}>
80+
{folders.map((folder, index) => (
81+
<div key={index} style={{ display: "contents" }}>
82+
<span
83+
className="folder-name"
84+
onClick={() => switchPath(folder.path)}
85+
ref={(el) => (foldersRef.current[index] = el)}
86+
>
87+
{index === 0 ? <MdHome /> : <MdOutlineNavigateNext />}
88+
{folder.name}
89+
</span>
90+
{hiddenFolders?.length > 0 && index === 0 && (
91+
<button
92+
className="folder-name folder-name-btn"
93+
onClick={() => setShowHiddenFolders(true)}
94+
ref={moreBtnRef}
95+
title="Show more folders"
96+
>
97+
<MdMoreHoriz size={22} className="hidden-folders" />
98+
</button>
99+
)}
100+
</div>
101+
))}
102+
</div>
103+
104+
{showHiddenFolders && (
105+
<ul ref={popoverRef.ref} className="hidden-folders-container">
106+
{hiddenFolders.map((folder, index) => (
107+
<li
108+
key={index}
109+
onClick={() => {
110+
switchPath(folder.path);
111+
setShowHiddenFolders(false);
112+
}}
113+
>
114+
{folder.name}
115+
</li>
116+
))}
117+
</ul>
118+
)}
39119
</div>
40120
);
41121
};
Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,79 @@
11
@import "../../styles/variables";
22

3-
.breadcrumb {
4-
height: calc(5.8% - 21px);
5-
display: flex;
6-
gap: 0.5rem;
7-
border-bottom: 1px solid #dddddd;
8-
padding: 10px 15px;
9-
overflow-x: scroll;
3+
.bread-crumb-container {
4+
position: relative;
105

11-
&::-webkit-scrollbar {
12-
height: 3px;
13-
}
6+
.breadcrumb {
7+
height: calc(5.8% - 21px);
8+
display: flex;
9+
gap: 0.5rem;
10+
border-bottom: 1px solid #dddddd;
11+
padding: 10px 0 10PX 15px;
12+
overflow-x: hidden;
13+
14+
&::-webkit-scrollbar {
15+
height: 3px;
16+
}
17+
18+
&::-webkit-scrollbar-thumb {
19+
background: $primary-color !important;
20+
}
21+
22+
.folder-name {
23+
display: flex;
24+
align-items: center;
25+
gap: 0.25rem;
26+
font-weight: 500;
27+
min-width: fit-content;
28+
29+
&:hover {
30+
cursor: pointer;
31+
color: $secondary-color;
32+
}
33+
}
34+
35+
.hidden-folders {
36+
padding: 0 4px;
37+
}
38+
39+
.folder-name-btn {
40+
background-color: transparent;
41+
border: none;
42+
padding: 0;
43+
44+
&:hover,
45+
&:focus {
46+
cursor: pointer;
47+
color: $primary-color;
48+
background-color: #dddcdc;
49+
border-radius: 5px;
50+
}
51+
}
1452

15-
&::-webkit-scrollbar-thumb {
16-
background: $primary-color !important;
1753
}
1854
}
55+
56+
.hidden-folders-container {
57+
position: absolute;
58+
margin: 0;
59+
z-index: 2;
60+
background-color: rgb(99, 99, 99);
61+
color: white;
62+
padding: 4px;
63+
border-radius: 5px;
64+
font-size: .9em;
65+
left: 3rem;
66+
display: flex;
67+
flex-direction: column;
68+
gap: 5px;
69+
70+
li {
71+
padding: 5px 10px;
72+
border-radius: 4px;
73+
74+
&:hover {
75+
cursor: pointer;
76+
background-color: rgb(117, 117, 117);
77+
}
78+
}
79+
}

frontend/src/FileManager/FileList/FileItem.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ const FileItem = ({
8383
const handleFileAccess = () => {
8484
setVisible(false);
8585
if (file.isDirectory) {
86-
setCurrentPath((prev) => prev + "/" + file.name);
86+
setCurrentPath(file.path);
8787
setSelectedFileIndex(null);
8888
setSelectedFile(null);
8989
} else {

frontend/src/FileManager/FileManager.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ const FileManager = ({
9393
);
9494
};
9595

96+
FileManager.displayName = "FileManager";
97+
9698
FileManager.propTypes = {
9799
files: PropTypes.arrayOf(
98100
PropTypes.shape({

frontend/src/FileManager/FileManager.scss

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,19 +89,6 @@ svg {
8989
padding-left: 0px;
9090
border-bottom-right-radius: 8px;
9191
}
92-
93-
.folder-name {
94-
display: flex;
95-
align-items: center;
96-
gap: 0.25rem;
97-
font-weight: 500;
98-
min-width: fit-content;
99-
100-
&:hover {
101-
cursor: pointer;
102-
color: $secondary-color;
103-
}
104-
}
10592
}
10693
}
10794

frontend/src/FileManager/Toolbar/Toolbar.scss

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
display: flex;
1111
justify-content: space-between;
1212

13-
> div {
13+
>div {
1414
display: flex;
1515
}
1616

@@ -39,7 +39,7 @@
3939
display: flex;
4040
justify-content: space-between;
4141

42-
> div {
42+
>div {
4343
display: flex;
4444
position: relative;
4545
}
@@ -57,6 +57,7 @@
5757
margin: 0;
5858
border: 1px solid #c4c4c4;
5959
border-radius: 5px;
60+
6061
ul {
6162
list-style: none;
6263
padding-left: 0;
@@ -113,10 +114,11 @@
113114
}
114115

115116
.icon-only {
116-
padding: 8px !important;
117+
padding: 0 8px !important;
117118

118119
&:focus {
119120
background-color: rgb(0 0 0 / 12%);
121+
border-radius: 3px;
120122
}
121123
}
122124

@@ -126,4 +128,4 @@
126128
width: 1px;
127129
margin: 0 5px;
128130
}
129-
}
131+
}

0 commit comments

Comments
 (0)