Skip to content

Commit 5595db6

Browse files
authored
Merge pull request #4189 from Blargian/usability_improvements_menu
Styling: usability improvements to navbar
2 parents 7f06ca7 + 3d85fb8 commit 5595db6

File tree

2 files changed

+166
-124
lines changed

2 files changed

+166
-124
lines changed

src/components/DocsCategoryDropdown/index.jsx

Lines changed: 118 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,29 @@ import styles from "./styles.module.css";
1010

1111
function DocsCategoryDropdown({ dropdownCategory }) {
1212
const [isOpen, setIsOpen] = useState(false);
13+
const [isVisible, setIsVisible] = useState(false);
1314
const [dropdownStyles, setDropdownStyles] = useState({
1415
top: "0px",
1516
left: "0px",
1617
});
1718
const dropdownMenuRef = useRef(null);
1819
const triggerRef = useRef(null); // Reference for the individual menu item trigger
20+
const hideTimeoutRef = useRef(null);
1921

2022
const handleMouseEnter = () => {
23+
if (hideTimeoutRef.current) {
24+
clearTimeout(hideTimeoutRef.current);
25+
hideTimeoutRef.current = null;
26+
}
2127
setIsOpen(true);
28+
setTimeout(() => setIsVisible(true), 10);
2229
};
2330

2431
const handleMouseLeave = () => {
25-
setIsOpen(false);
32+
setIsVisible(false);
33+
hideTimeoutRef.current = setTimeout(() => {
34+
setIsOpen(false);
35+
}, 150);
2636
};
2737

2838
// Use useEffect to update the dropdown position when isOpen changes
@@ -42,17 +52,17 @@ function DocsCategoryDropdown({ dropdownCategory }) {
4252
} else {
4353
// Align to center
4454
left =
45-
triggerRect.left + triggerRect.width / 2 - dropdownRect.width / 2;
55+
triggerRect.left + triggerRect.width / 2 - dropdownRect.width / 2;
4656
}
4757

4858
// Ensure the dropdown doesn't go off-screen
4959
left = Math.max(
50-
10,
51-
Math.min(left, viewportWidth - dropdownRect.width - 10),
60+
10,
61+
Math.min(left, viewportWidth - dropdownRect.width - 10),
5262
);
5363

5464
setDropdownStyles({
55-
top: `${triggerRect.bottom}px`, // Align the dropdown below the menu item
65+
top: `${triggerRect.bottom}px`, // Back to original positioning
5666
left: `${left}px`, // Align the dropdown with the menu item
5767
});
5868
}
@@ -67,132 +77,130 @@ function DocsCategoryDropdown({ dropdownCategory }) {
6777

6878
// Guard against undefined sidebar
6979
const isSelected =
70-
sidebar && sidebar.name && dropdownCategory
71-
? sidebar.name === dropdownCategory.customProps.sidebar
72-
: false;
80+
sidebar && sidebar.name && dropdownCategory
81+
? sidebar.name === dropdownCategory.customProps.sidebar
82+
: false;
7383

7484
return (
75-
<div
76-
className={styles.docsNavDropdownContainer}
77-
onMouseEnter={handleMouseEnter}
78-
onMouseLeave={handleMouseLeave}
79-
>
85+
<div
86+
className={styles.docsNavDropdownContainer}
87+
onMouseEnter={handleMouseEnter}
88+
onMouseLeave={handleMouseLeave}
89+
>
8090
<span
81-
className={styles.docsNavDropdownToolbarLink}
82-
ref={triggerRef} // Attach the ref to the individual link that triggers the dropdown
91+
className={styles.docsNavDropdownToolbarLink}
92+
ref={triggerRef} // Attach the ref to the individual link that triggers the dropdown
8393
>
8494
<Link
85-
className={`${styles.docsNavDropdownToolbarTopLevelLink} ${isSelected ? styles.docsNavSelected : ""
95+
className={`${styles.docsNavDropdownToolbarTopLevelLink} ${isSelected ? styles.docsNavSelected : ""
8696
}`}
87-
href={dropdownCategory.customProps.href}
97+
href={dropdownCategory.customProps.href}
8898
>
8999
<Translate
90-
id={`sidebar.dropdownCategories.category.${dropdownCategory.label}`}
91-
description={`Translation for ${dropdownCategory.label}`}
100+
id={`sidebar.dropdownCategories.category.${dropdownCategory.label}`}
101+
description={`Translation for ${dropdownCategory.label}`}
92102
>
93103
{dropdownCategory.label}
94104
</Translate>
95105
</Link>{" "}
96106
<DropdownCaret />
97107
</span>
98-
{isOpen && (
99-
<DropdownContent
100-
dropdownCategory={dropdownCategory}
101-
handleMouseLeave={handleMouseLeave}
102-
dropdownStyles={dropdownStyles} // Pass the dynamic styles to position the dropdown
103-
dropdownMenuRef={dropdownMenuRef} // Pass the ref to the dropdown content
104-
/>
105-
)}
106-
</div>
108+
{isOpen && (
109+
<DropdownContent
110+
dropdownCategory={dropdownCategory}
111+
handleMouseLeave={handleMouseLeave}
112+
dropdownStyles={dropdownStyles} // Pass the dynamic styles to position the dropdown
113+
dropdownMenuRef={dropdownMenuRef} // Pass the ref to the dropdown content
114+
isVisible={isVisible}
115+
/>
116+
)}
117+
</div>
107118
);
108119
}
109120

110121
export const DocsCategoryDropdownLinkOnly = ({ title, link }) => {
111122
return (
112-
<div className={styles.docsNavDropdownContainer}>
113-
<Link href={link} className={styles.docsNavDropdownToolbarTopLevelLink}>
114-
<span>{title}</span>
115-
</Link>
116-
</div>
123+
<div className={styles.docsNavDropdownContainer}>
124+
<Link href={link} className={styles.docsNavDropdownToolbarTopLevelLink}>
125+
<span>{title}</span>
126+
</Link>
127+
</div>
117128
);
118129
};
119130

120131
const DropdownContent = ({
121-
dropdownCategory,
122-
handleMouseLeave,
123-
dropdownStyles,
124-
dropdownMenuRef,
125-
}) => {
132+
dropdownCategory,
133+
handleMouseLeave,
134+
dropdownStyles,
135+
dropdownMenuRef,
136+
isVisible,
137+
}) => {
126138
const [hovered, setHovered] = useState(null);
127139

128140
return (
129-
<div
130-
ref={dropdownMenuRef}
131-
className={styles.docsNavDropdownMenu}
132-
style={{ position: "fixed", ...dropdownStyles }}
133-
>
134141
<div
135-
key={99}
136-
className={`${styles.docsNavMenuItem} ${hovered === 99 ? styles.docsNavHovered : ""}`}
137-
onMouseEnter={() => setHovered(99)}
138-
onMouseLeave={() => setHovered(null)}
142+
ref={dropdownMenuRef}
143+
className={`${styles.docsNavDropdownMenu} ${isVisible ? styles.visible : ''}`}
144+
style={{ position: "fixed", ...dropdownStyles }}
139145
>
140146
<Link
141-
to={dropdownCategory.customProps.href}
142-
className={styles.docsNavMenuHeader}
143-
onClick={handleMouseLeave}
144-
>
145-
<Translate
146-
id={`sidebar.dropdownCategories.category.${dropdownCategory.label}`}
147-
description={`Translation for ${dropdownCategory.label}`}
148-
>
149-
{dropdownCategory.label}
150-
</Translate>
151-
</Link>
152-
<div className={styles.docsNavMenuDescription}>
153-
<Translate
154-
id={`sidebar.dropdownCategories.category.description.${dropdownCategory.label}`}
155-
description={`Translation for ${dropdownCategory.label} description`}
156-
>
157-
{dropdownCategory.description}
158-
</Translate>
159-
</div>
160-
</div>
161-
<hr className={styles.docsNavMenuDivider} />
162-
<div className={styles.docsNavMenuItems}>
163-
{dropdownCategory.items.map((item, index) => (
164-
<div
165-
key={index}
166-
className={`${styles.docsNavMenuItem} ${hovered === index ? styles.docsNavHovered : ""}`}
167-
onMouseEnter={() => setHovered(index)}
147+
key={99}
148+
to={dropdownCategory.customProps.href}
149+
className={`${styles.docsNavMenuItem} ${hovered === 99 ? styles.docsNavHovered : ""}`}
150+
onMouseEnter={() => setHovered(99)}
168151
onMouseLeave={() => setHovered(null)}
169-
>
170-
<Link
171-
to={item.href}
172-
className={styles.docsNavItemTitle}
173-
onClick={handleMouseLeave}
152+
onClick={handleMouseLeave}
153+
style={{ textDecoration: 'none', display: 'block' }}
154+
>
155+
<div className={styles.docsNavMenuHeader}>
156+
<Translate
157+
id={`sidebar.dropdownCategories.category.${dropdownCategory.label}`}
158+
description={`Translation for ${dropdownCategory.label}`}
174159
>
175-
<Translate
176-
id={`sidebar.dropdownCategories.category.${dropdownCategory.label}.${item.label}`}
177-
description={`Translation for ${dropdownCategory.label}.${item.label}`}
178-
>
179-
{item.label}
180-
</Translate>
181-
182-
</Link>
183-
<div className={styles.docsNavItemDescription}>
184-
<Translate
185-
id={`sidebar.dropdownCategories.category.${dropdownCategory.label}.${item.label}.description`}
186-
description={`Translation for ${dropdownCategory.label}.${item.label} description`}
187-
>
188-
{item.description}
189-
</Translate>
190-
191-
</div>
160+
{dropdownCategory.label}
161+
</Translate>
162+
</div>
163+
<div className={styles.docsNavMenuDescription}>
164+
<Translate
165+
id={`sidebar.dropdownCategories.category.description.${dropdownCategory.label}`}
166+
description={`Translation for ${dropdownCategory.label} description`}
167+
>
168+
{dropdownCategory.description}
169+
</Translate>
192170
</div>
193-
))}
171+
</Link>
172+
<hr className={styles.docsNavMenuDivider} />
173+
<div className={styles.docsNavMenuItems}>
174+
{dropdownCategory.items.map((item, index) => (
175+
<Link
176+
key={index}
177+
to={item.href}
178+
className={`${styles.docsNavMenuItem} ${hovered === index ? styles.docsNavHovered : ""}`}
179+
onMouseEnter={() => setHovered(index)}
180+
onMouseLeave={() => setHovered(null)}
181+
onClick={handleMouseLeave}
182+
style={{ textDecoration: 'none', display: 'block' }}
183+
>
184+
<div className={styles.docsNavItemTitle}>
185+
<Translate
186+
id={`sidebar.dropdownCategories.category.${dropdownCategory.label}.${item.label}`}
187+
description={`Translation for ${dropdownCategory.label}.${item.label}`}
188+
>
189+
{item.label}
190+
</Translate>
191+
</div>
192+
<div className={styles.docsNavItemDescription}>
193+
<Translate
194+
id={`sidebar.dropdownCategories.category.${dropdownCategory.label}.${item.label}.description`}
195+
description={`Translation for ${dropdownCategory.label}.${item.label} description`}
196+
>
197+
{item.description}
198+
</Translate>
199+
</div>
200+
</Link>
201+
))}
202+
</div>
194203
</div>
195-
</div>
196204
);
197205
};
198206

@@ -211,24 +219,24 @@ const DropdownCaret = () => {
211219
};
212220

213221
return (
214-
<span style={{ marginLeft: "8px" }}>
222+
<span style={{ marginLeft: "8px" }}>
215223
<svg
216-
xmlns="http://www.w3.org/2000/svg"
217-
width="6"
218-
height="10"
219-
viewBox="0 0 6 10"
220-
style={rotatedIconStyle}
224+
xmlns="http://www.w3.org/2000/svg"
225+
width="6"
226+
height="10"
227+
viewBox="0 0 6 10"
228+
style={rotatedIconStyle}
221229
>
222230
<path
223-
stroke="currentColor"
224-
strokeLinecap="round"
225-
strokeLinejoin="round"
226-
strokeWidth="1.5"
227-
d="M1 9L5 5 1 1"
231+
stroke="currentColor"
232+
strokeLinecap="round"
233+
strokeLinejoin="round"
234+
strokeWidth="1.5"
235+
d="M1 9L5 5 1 1"
228236
/>
229237
</svg>
230238
</span>
231239
);
232240
};
233241

234-
export default DocsCategoryDropdown;
242+
export default DocsCategoryDropdown;

0 commit comments

Comments
 (0)