ml-ui-lib 1.0.25 → 1.0.26
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,8 +221,6 @@
|
|
|
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;
|
|
@@ -162,8 +245,9 @@
|
|
|
162
245
|
}
|
|
163
246
|
|
|
164
247
|
.navbar-links a {
|
|
165
|
-
|
|
248
|
+
display: block;
|
|
166
249
|
width: 100%;
|
|
250
|
+
padding: 1rem 50px;
|
|
167
251
|
font-size: 1.2rem;
|
|
168
252
|
}
|
|
169
253
|
|
|
@@ -176,8 +260,26 @@
|
|
|
176
260
|
color: #fff;
|
|
177
261
|
}
|
|
178
262
|
|
|
263
|
+
/* Mobile dropdown inside sliding menu */
|
|
264
|
+
.navbar-dropdown {
|
|
265
|
+
position: static;
|
|
266
|
+
display: flex !important;
|
|
267
|
+
flex-direction: column;
|
|
268
|
+
background: transparent;
|
|
269
|
+
box-shadow: none;
|
|
270
|
+
padding: 0px;
|
|
271
|
+
}
|
|
179
272
|
|
|
180
|
-
|
|
273
|
+
.navbar-dropdown-link {
|
|
274
|
+
padding-left: 50px;
|
|
275
|
+
color: #333;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.has-dropdown .navbar-dropdown-link {
|
|
279
|
+
padding: 1rem 70px;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* MOBILE LOGIN FIXED AT BOTTOM */
|
|
181
283
|
.mobile-login-btn {
|
|
182
284
|
position: absolute;
|
|
183
285
|
bottom: 0;
|
|
@@ -185,20 +287,18 @@
|
|
|
185
287
|
width: 100%;
|
|
186
288
|
padding: 1.3rem;
|
|
187
289
|
border: none;
|
|
188
|
-
/* background: #d00000; */
|
|
189
290
|
color: #333;
|
|
190
291
|
font-size: 1.1rem;
|
|
191
292
|
font-weight: 600;
|
|
192
|
-
/* text-align: center; */
|
|
193
293
|
}
|
|
194
294
|
}
|
|
195
295
|
|
|
196
|
-
|
|
197
|
-
|
|
296
|
+
/* -------------------------
|
|
297
|
+
Login Button
|
|
298
|
+
------------------------- */
|
|
198
299
|
.login-btn {
|
|
199
300
|
color: #333;
|
|
200
301
|
border: none;
|
|
201
|
-
/* padding: 0.5rem 1.25rem; */
|
|
202
302
|
border-radius: 6px;
|
|
203
303
|
cursor: pointer;
|
|
204
304
|
transition: background 0.3s ease;
|
|
@@ -213,7 +313,6 @@
|
|
|
213
313
|
font-weight: 500;
|
|
214
314
|
}
|
|
215
315
|
|
|
216
|
-
|
|
217
316
|
.navbar-login-panel .spb-header {
|
|
218
317
|
padding: 0 !important;
|
|
219
318
|
border-bottom: none !important;
|
|
@@ -223,6 +322,7 @@
|
|
|
223
322
|
padding: 20px;
|
|
224
323
|
}
|
|
225
324
|
|
|
325
|
+
/* Overlay for desktop login panel */
|
|
226
326
|
@media (min-width: 591px) {
|
|
227
327
|
.overlay-side-content {
|
|
228
328
|
position: fixed;
|
|
@@ -274,23 +374,21 @@
|
|
|
274
374
|
gap: 20px;
|
|
275
375
|
}
|
|
276
376
|
|
|
377
|
+
/* Scrollbar styling */
|
|
277
378
|
::-webkit-scrollbar {
|
|
278
379
|
width: 5px;
|
|
279
380
|
}
|
|
280
381
|
|
|
281
|
-
/* Track */
|
|
282
382
|
::-webkit-scrollbar-track {
|
|
283
383
|
box-shadow: inset 0 0 5px grey;
|
|
284
384
|
border-radius: 10px;
|
|
285
385
|
}
|
|
286
386
|
|
|
287
|
-
/* Handle */
|
|
288
387
|
::-webkit-scrollbar-thumb {
|
|
289
388
|
background: #757575;
|
|
290
389
|
border-radius: 10px;
|
|
291
390
|
}
|
|
292
391
|
|
|
293
|
-
/* Handle on hover */
|
|
294
392
|
::-webkit-scrollbar-thumb:hover {
|
|
295
393
|
background: #4f4f4f;
|
|
296
394
|
}
|
|
@@ -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,6 +9,7 @@ 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
14
|
const handleResize = () => setIsMobile(window.innerWidth <= 590);
|
|
14
15
|
handleResize();
|
|
@@ -16,11 +17,18 @@ export const Navbar = ({ siteUrl, items, logoSrc = '', logoAlt = 'M Lhuillier Lo
|
|
|
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;
|