ml-ui-lib 1.0.25 → 1.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/* -------------------------
|
|
2
|
+
Navbar Base
|
|
3
|
+
------------------------- */
|
|
1
4
|
.navbar {
|
|
2
5
|
background: #fff;
|
|
3
6
|
border-bottom: 1px solid #eee;
|
|
@@ -18,17 +21,70 @@
|
|
|
18
21
|
max-height: 50px;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
/* -------------------------
|
|
25
|
+
Nav Items
|
|
26
|
+
------------------------- */
|
|
22
27
|
.nav-items {
|
|
23
28
|
display: flex;
|
|
24
|
-
overflow:
|
|
29
|
+
overflow: none;
|
|
25
30
|
gap: 1.5rem;
|
|
26
31
|
}
|
|
27
32
|
|
|
33
|
+
.navbar-item {
|
|
34
|
+
position: relative;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.navbar-item.has-dropdown>.navbar-link {
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Dropdown menu */
|
|
42
|
+
.navbar-dropdown {
|
|
43
|
+
/* hidden by default */
|
|
44
|
+
display: none;
|
|
45
|
+
padding: 20px 25px 10px 10px;
|
|
46
|
+
position: absolute;
|
|
47
|
+
top: 20px;
|
|
48
|
+
left: -25px;
|
|
49
|
+
background: #fff;
|
|
50
|
+
min-width: 180px;
|
|
51
|
+
/* box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15); */
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
z-index: 999;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.navbar-dropdown-link {
|
|
57
|
+
padding: 10px 15px;
|
|
58
|
+
color: #000;
|
|
59
|
+
text-decoration: none;
|
|
60
|
+
white-space: nowrap;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.navbar-dropdown-link:hover {
|
|
64
|
+
background: #f2f2f2;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Show dropdown on hover (desktop) */
|
|
68
|
+
.navbar-item.has-dropdown:hover .navbar-dropdown {
|
|
69
|
+
display: flex;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Add linear caret for items with dropdown */
|
|
73
|
+
.navbar-item.has-dropdown>.navbar-link::after {
|
|
74
|
+
content: ">";
|
|
75
|
+
display: inline-block;
|
|
76
|
+
margin-left: 6px;
|
|
77
|
+
font-size: 0.8em;
|
|
78
|
+
font-weight: bold;
|
|
79
|
+
transition: transform 0.3s ease;
|
|
80
|
+
transform: rotate(90deg);
|
|
81
|
+
}
|
|
28
82
|
|
|
83
|
+
/* -------------------------
|
|
84
|
+
Navbar Links
|
|
85
|
+
------------------------- */
|
|
29
86
|
.navbar-links {
|
|
30
87
|
display: flex;
|
|
31
|
-
/* gap: 1.5rem; */
|
|
32
88
|
transition: all 0.3s ease;
|
|
33
89
|
margin-left: 35px;
|
|
34
90
|
}
|
|
@@ -39,6 +95,28 @@
|
|
|
39
95
|
font-weight: 400;
|
|
40
96
|
font-size: 17px;
|
|
41
97
|
transition: color 0.2s;
|
|
98
|
+
display: inline-block;
|
|
99
|
+
/* allows width & height */
|
|
100
|
+
width: auto;
|
|
101
|
+
/* default for desktop */
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Style for parent items with sublinks (desktop) */
|
|
105
|
+
.navbar-link.parent-link {
|
|
106
|
+
cursor: default;
|
|
107
|
+
/* show pointer as normal arrow, not hand */
|
|
108
|
+
color: #333 !important;
|
|
109
|
+
/* normal text color */
|
|
110
|
+
/* font-weight: 500; */
|
|
111
|
+
/* optional: slightly bolder */
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Prevent hover effect for parent items */
|
|
115
|
+
.navbar-link.parent-link:hover {
|
|
116
|
+
color: #333;
|
|
117
|
+
/* do not turn red */
|
|
118
|
+
background: none;
|
|
119
|
+
/* no background change */
|
|
42
120
|
}
|
|
43
121
|
|
|
44
122
|
.navbar-links a:hover {
|
|
@@ -51,12 +129,9 @@
|
|
|
51
129
|
color: #ff0000;
|
|
52
130
|
}
|
|
53
131
|
|
|
54
|
-
/*
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
/* Burger Icon */
|
|
132
|
+
/* -------------------------
|
|
133
|
+
Burger Icon
|
|
134
|
+
------------------------- */
|
|
60
135
|
.burger {
|
|
61
136
|
display: none;
|
|
62
137
|
flex-direction: column;
|
|
@@ -90,7 +165,9 @@
|
|
|
90
165
|
transform: translateY(-8px) rotate(-45deg);
|
|
91
166
|
}
|
|
92
167
|
|
|
93
|
-
|
|
168
|
+
/* -------------------------
|
|
169
|
+
Responsive
|
|
170
|
+
------------------------- */
|
|
94
171
|
@media (min-width: 1000px) {
|
|
95
172
|
.navbar-container {
|
|
96
173
|
padding: 1rem 5rem;
|
|
@@ -101,22 +178,30 @@
|
|
|
101
178
|
.navbar-container {
|
|
102
179
|
padding: 1rem 0;
|
|
103
180
|
}
|
|
104
|
-
|
|
105
181
|
}
|
|
106
182
|
|
|
107
183
|
@media (max-width: 500px) {
|
|
108
184
|
.navbar-container {
|
|
109
185
|
margin: 0 !important;
|
|
110
186
|
}
|
|
111
|
-
|
|
112
187
|
}
|
|
113
188
|
|
|
114
189
|
.mobile-login-btn {
|
|
115
190
|
display: none;
|
|
116
191
|
}
|
|
117
192
|
|
|
118
|
-
/*
|
|
193
|
+
/* -------------------------
|
|
194
|
+
Mobile Menu
|
|
195
|
+
------------------------- */
|
|
119
196
|
@media (max-width: 992px) {
|
|
197
|
+
/* .navbar-item.has-dropdown>.navbar-link::after {
|
|
198
|
+
display: none;
|
|
199
|
+
} */
|
|
200
|
+
|
|
201
|
+
.separator {
|
|
202
|
+
display: none;
|
|
203
|
+
}
|
|
204
|
+
|
|
120
205
|
.mobile-login-btn {
|
|
121
206
|
display: block;
|
|
122
207
|
}
|
|
@@ -136,11 +221,10 @@
|
|
|
136
221
|
justify-content: space-between;
|
|
137
222
|
}
|
|
138
223
|
|
|
139
|
-
/* ⭐ SLIDE-IN MENU */
|
|
140
|
-
|
|
141
224
|
.nav-items {
|
|
142
225
|
gap: 0px;
|
|
143
226
|
flex-direction: column;
|
|
227
|
+
overflow: auto;
|
|
144
228
|
}
|
|
145
229
|
|
|
146
230
|
.navbar-links {
|
|
@@ -162,8 +246,9 @@
|
|
|
162
246
|
}
|
|
163
247
|
|
|
164
248
|
.navbar-links a {
|
|
165
|
-
|
|
249
|
+
display: block;
|
|
166
250
|
width: 100%;
|
|
251
|
+
padding: 1rem 50px;
|
|
167
252
|
font-size: 1.2rem;
|
|
168
253
|
}
|
|
169
254
|
|
|
@@ -176,8 +261,26 @@
|
|
|
176
261
|
color: #fff;
|
|
177
262
|
}
|
|
178
263
|
|
|
264
|
+
/* Mobile dropdown inside sliding menu */
|
|
265
|
+
.navbar-dropdown {
|
|
266
|
+
position: static;
|
|
267
|
+
display: flex !important;
|
|
268
|
+
flex-direction: column;
|
|
269
|
+
background: transparent;
|
|
270
|
+
box-shadow: none;
|
|
271
|
+
padding: 0px;
|
|
272
|
+
}
|
|
179
273
|
|
|
180
|
-
|
|
274
|
+
.navbar-dropdown-link {
|
|
275
|
+
padding-left: 50px;
|
|
276
|
+
color: #333;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.has-dropdown .navbar-dropdown-link {
|
|
280
|
+
padding: 1rem 70px;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/* MOBILE LOGIN FIXED AT BOTTOM */
|
|
181
284
|
.mobile-login-btn {
|
|
182
285
|
position: absolute;
|
|
183
286
|
bottom: 0;
|
|
@@ -185,20 +288,18 @@
|
|
|
185
288
|
width: 100%;
|
|
186
289
|
padding: 1.3rem;
|
|
187
290
|
border: none;
|
|
188
|
-
/* background: #d00000; */
|
|
189
291
|
color: #333;
|
|
190
292
|
font-size: 1.1rem;
|
|
191
293
|
font-weight: 600;
|
|
192
|
-
/* text-align: center; */
|
|
193
294
|
}
|
|
194
295
|
}
|
|
195
296
|
|
|
196
|
-
|
|
197
|
-
|
|
297
|
+
/* -------------------------
|
|
298
|
+
Login Button
|
|
299
|
+
------------------------- */
|
|
198
300
|
.login-btn {
|
|
199
301
|
color: #333;
|
|
200
302
|
border: none;
|
|
201
|
-
/* padding: 0.5rem 1.25rem; */
|
|
202
303
|
border-radius: 6px;
|
|
203
304
|
cursor: pointer;
|
|
204
305
|
transition: background 0.3s ease;
|
|
@@ -213,7 +314,6 @@
|
|
|
213
314
|
font-weight: 500;
|
|
214
315
|
}
|
|
215
316
|
|
|
216
|
-
|
|
217
317
|
.navbar-login-panel .spb-header {
|
|
218
318
|
padding: 0 !important;
|
|
219
319
|
border-bottom: none !important;
|
|
@@ -223,6 +323,7 @@
|
|
|
223
323
|
padding: 20px;
|
|
224
324
|
}
|
|
225
325
|
|
|
326
|
+
/* Overlay for desktop login panel */
|
|
226
327
|
@media (min-width: 591px) {
|
|
227
328
|
.overlay-side-content {
|
|
228
329
|
position: fixed;
|
|
@@ -274,23 +375,21 @@
|
|
|
274
375
|
gap: 20px;
|
|
275
376
|
}
|
|
276
377
|
|
|
378
|
+
/* Scrollbar styling */
|
|
277
379
|
::-webkit-scrollbar {
|
|
278
380
|
width: 5px;
|
|
279
381
|
}
|
|
280
382
|
|
|
281
|
-
/* Track */
|
|
282
383
|
::-webkit-scrollbar-track {
|
|
283
384
|
box-shadow: inset 0 0 5px grey;
|
|
284
385
|
border-radius: 10px;
|
|
285
386
|
}
|
|
286
387
|
|
|
287
|
-
/* Handle */
|
|
288
388
|
::-webkit-scrollbar-thumb {
|
|
289
389
|
background: #757575;
|
|
290
390
|
border-radius: 10px;
|
|
291
391
|
}
|
|
292
392
|
|
|
293
|
-
/* Handle on hover */
|
|
294
393
|
::-webkit-scrollbar-thumb:hover {
|
|
295
394
|
background: #4f4f4f;
|
|
296
395
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import './Navbar.css';
|
|
3
|
+
export interface NavbarSubItem {
|
|
4
|
+
name: string;
|
|
5
|
+
link: string;
|
|
6
|
+
target?: '_blank' | '_self';
|
|
7
|
+
}
|
|
3
8
|
export interface NavbarItem {
|
|
4
9
|
name: string;
|
|
5
10
|
link: string;
|
|
6
11
|
target?: '_blank' | '_self';
|
|
12
|
+
subLinks?: NavbarSubItem[];
|
|
7
13
|
}
|
|
8
14
|
export interface NavbarProps {
|
|
9
15
|
siteUrl?: string;
|
|
@@ -9,18 +9,26 @@ export const Navbar = ({ siteUrl, items, logoSrc = '', logoAlt = 'M Lhuillier Lo
|
|
|
9
9
|
const [isClosing, setIsClosing] = useState(false);
|
|
10
10
|
const [isMobile, setIsMobile] = useState(false);
|
|
11
11
|
const [currentPath, setCurrentPath] = useState(null);
|
|
12
|
+
const [openDropdown, setOpenDropdown] = useState(null);
|
|
12
13
|
useEffect(() => {
|
|
13
|
-
const handleResize = () => setIsMobile(window.innerWidth <=
|
|
14
|
+
const handleResize = () => setIsMobile(window.innerWidth <= 992);
|
|
14
15
|
handleResize();
|
|
15
16
|
setCurrentPath(window.location.pathname);
|
|
16
17
|
window.addEventListener('resize', handleResize);
|
|
17
18
|
return () => window.removeEventListener('resize', handleResize);
|
|
18
19
|
}, []);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (!menuOpen)
|
|
22
|
+
setOpenDropdown(null);
|
|
23
|
+
}, [menuOpen]);
|
|
19
24
|
const toggleMenu = () => setMenuOpen((prev) => !prev);
|
|
20
25
|
const toggleLogin = () => {
|
|
21
26
|
setMenuOpen(false);
|
|
22
27
|
setShowLogin((prev) => !prev);
|
|
23
28
|
};
|
|
29
|
+
const toggleDropdown = (name) => {
|
|
30
|
+
setOpenDropdown(prev => (prev === name ? null : name));
|
|
31
|
+
};
|
|
24
32
|
const handleInternalClose = () => {
|
|
25
33
|
setIsClosing(true);
|
|
26
34
|
setTimeout(() => {
|
|
@@ -28,17 +36,48 @@ export const Navbar = ({ siteUrl, items, logoSrc = '', logoAlt = 'M Lhuillier Lo
|
|
|
28
36
|
setIsClosing(false);
|
|
29
37
|
document.body.style.overflow = '';
|
|
30
38
|
onClose?.();
|
|
31
|
-
}, 350);
|
|
39
|
+
}, 350);
|
|
32
40
|
};
|
|
33
|
-
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (menuOpen) {
|
|
43
|
+
document.body.style.overflow = 'hidden';
|
|
44
|
+
document.body.style.touchAction = 'none';
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
document.body.style.overflow = '';
|
|
48
|
+
document.body.style.touchAction = '';
|
|
49
|
+
}
|
|
50
|
+
return () => {
|
|
51
|
+
document.body.style.overflow = '';
|
|
52
|
+
document.body.style.touchAction = '';
|
|
53
|
+
};
|
|
54
|
+
}, [menuOpen]);
|
|
55
|
+
return (_jsxs(_Fragment, { children: [_jsx("nav", { className: `navbar ${className}`, children: _jsxs("div", { className: "navbar-container", children: [_jsx("div", { className: "navbar-logo", children: _jsx("a", { href: siteUrl, className: "navbar-brand", children: _jsx("img", { src: logoSrc, alt: logoAlt, width: logoWidth, height: logoHeight, style: { cursor: 'pointer', display: 'block' } }) }) }), _jsxs("div", { style: { display: 'flex', flexDirection: 'row', gap: '10px', alignItems: 'center' }, children: [_jsxs("div", { className: `navbar-links ${menuOpen ? 'open' : ''}`, children: [_jsx("div", { className: "nav-items", children: items.map(item => {
|
|
56
|
+
const hasSubLinks = item.subLinks && item.subLinks.length > 0;
|
|
34
57
|
const linkPath = new URL(item.link, 'https://dummybase').pathname;
|
|
35
58
|
const isActive = currentPath === linkPath;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
const isDropdownOpen = openDropdown === item.name;
|
|
60
|
+
return (_jsxs("div", { className: `navbar-item ${hasSubLinks ? 'has-dropdown' : ''} ${isDropdownOpen ? 'open' : ''}`, children: [_jsx("a", { href: hasSubLinks && !isMobile ? '#' : item.link, target: item.target || '_self', className: `navbar-link ${isActive ? 'active' : ''} ${hasSubLinks && !isMobile ? 'parent-link' : ''}`, onClick: (e) => {
|
|
61
|
+
if (hasSubLinks) {
|
|
62
|
+
if (isMobile) {
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
toggleDropdown(item.name);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
e.preventDefault(); // prevent desktop click
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
setMenuOpen(false);
|
|
72
|
+
}
|
|
73
|
+
}, children: item.name }), hasSubLinks && (_jsx("div", { className: "navbar-dropdown", style: {
|
|
74
|
+
display: isMobile
|
|
75
|
+
? isDropdownOpen ? 'flex' : 'none'
|
|
76
|
+
: undefined,
|
|
77
|
+
}, children: item.subLinks.map(sub => (_jsx("a", { href: sub.link, target: sub.target || '_self', className: "navbar-dropdown-link", onClick: () => {
|
|
78
|
+
setMenuOpen(false);
|
|
79
|
+
setOpenDropdown(null);
|
|
80
|
+
}, children: sub.name }, sub.name))) }))] }, item.name));
|
|
81
|
+
}) }), isMobile && login && !logedinData && (_jsx("button", { className: "mobile-login-btn", onClick: toggleLogin, children: "Login" }))] }), _jsx("div", { className: 'separator', style: { color: '#aaaaaa', fontSize: '27px', padding: '0 15px' }, children: " | " }), _jsxs("div", { className: "navbar-right", children: [_jsxs("button", { className: `burger ${menuOpen ? 'active' : ''}`, onClick: toggleMenu, "aria-label": "Toggle menu", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }), !isMobile && login && !logedinData && (_jsx("span", { style: { color: '#e00000', fontWeight: '700' }, className: "login-btn", onClick: toggleLogin, children: "Login" }))] })] })] }) }), login && !logedinData && (_jsx(_Fragment, { children: !isMobile ? (showLogin && (_jsxs(_Fragment, { children: [_jsx("div", { className: "overlay-side-content", children: otherContent }), _jsx("div", { className: "navbar-login-panel", children: _jsxs(SlidingPanel, { isOpen: showLogin && !isClosing, width: "400px", height: "100%", position: "right", closeOnOverlayClick: false, onClose: handleInternalClose, children: [_jsx("div", { className: "navbar-panel-header" }), _jsx("div", { className: "navbar-panel-content", children: loginContent })] }) })] }))) : (_jsx("div", { className: "navbar-login-panel", children: _jsxs(SlidingPanel, { isOpen: showLogin, height: "70%", position: "bottom", onClose: handleInternalClose, children: [_jsx("div", { className: "navbar-panel-header" }), _jsx("div", { className: "navbar-panel-content", children: loginContent })] }) })) }))] }));
|
|
43
82
|
};
|
|
44
83
|
export default Navbar;
|