@stackshift-ui/navigation 6.0.3 → 6.0.5-beta.0

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.
@@ -0,0 +1,252 @@
1
+ import { Button } from "@stackshift-ui/button";
2
+ import { Container } from "@stackshift-ui/container";
3
+ import { Flex } from "@stackshift-ui/flex";
4
+ import { Image } from "@stackshift-ui/image";
5
+ import { Link } from "@stackshift-ui/link";
6
+ import { Section } from "@stackshift-ui/section";
7
+ import { Text } from "@stackshift-ui/text";
8
+ import React from "react";
9
+ import { NavigationProps, ResponsiveNavLinksProps } from ".";
10
+ import { logoLink } from "./helper";
11
+ import { LabeledRoute, LabeledRouteWithKey, Logo } from "./types";
12
+
13
+ export default function Navigation_C({
14
+ links,
15
+ primaryButton,
16
+ secondaryButton,
17
+ logo,
18
+ }: NavigationProps) {
19
+ const [menu, setMenu] = React.useState(false);
20
+ const showMenu = () => {
21
+ setMenu(prevState => !prevState);
22
+ };
23
+
24
+ return (
25
+ <Section className="bg-background">
26
+ <nav className="relative py-6">
27
+ <Container maxWidth={1280}>
28
+ <Flex align="center">
29
+ <NavLinks links={links} />
30
+ <LogoSection logo={logo} />
31
+ <Buttons primaryButton={primaryButton} secondaryButton={secondaryButton} />
32
+ <MobileMenu showMenu={showMenu} />
33
+ </Flex>
34
+ </Container>
35
+ </nav>
36
+ <ResponsiveNavLinks
37
+ menu={menu}
38
+ showMenu={showMenu}
39
+ links={links}
40
+ primaryButton={primaryButton}
41
+ secondaryButton={secondaryButton}
42
+ />
43
+ </Section>
44
+ );
45
+ }
46
+
47
+ function NavLinks({ links }: { links?: LabeledRouteWithKey[] }) {
48
+ if (!links) return null;
49
+
50
+ return (
51
+ <ul className="hidden lg:flex lg:w-auto lg:items-center lg:space-x-6">
52
+ {links?.map((link, index) => (
53
+ <React.Fragment key={index}>
54
+ {link?.label && <NavItem link={link} />}
55
+ {links.length !== index + 1 ? <NavIcon /> : null}
56
+ </React.Fragment>
57
+ ))}
58
+ </ul>
59
+ );
60
+ }
61
+
62
+ function NavItem({ link }: { link?: LabeledRouteWithKey }) {
63
+ if (!link) return null;
64
+
65
+ return (
66
+ <li>
67
+ <Button
68
+ as="link"
69
+ ariaLabel={link?.label}
70
+ link={link}
71
+ className="text-sm text-gray-500 no-underline hover:text-gray-900">
72
+ {link?.label}
73
+ </Button>
74
+ </li>
75
+ );
76
+ }
77
+
78
+ function NavIcon() {
79
+ return (
80
+ <li className="text-gray-500">
81
+ <svg
82
+ className="w-4 h-4 current-fill"
83
+ xmlns="http://www.w3.org/2000/svg"
84
+ fill="none"
85
+ viewBox="0 0 24 24"
86
+ stroke="currentColor">
87
+ <path
88
+ strokeLinecap="round"
89
+ strokeLinejoin="round"
90
+ strokeWidth="2"
91
+ d="M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z"></path>
92
+ </svg>
93
+ </li>
94
+ );
95
+ }
96
+
97
+ function LogoSection({ logo }: { logo?: Logo }) {
98
+ if (!logo) return null;
99
+
100
+ return (
101
+ <div className="lg:absolute lg:left-1/2 lg:top-1/2 lg:-translate-x-1/2 lg:-translate-y-1/2 lg:transform">
102
+ <Link
103
+ aria-label={`Go to ${logoLink(logo) === "/" ? "home page" : logoLink(logo)}`}
104
+ className="text-3xl font-bold leading-none"
105
+ href={logoLink(logo)}
106
+ target={logo?.linkTarget}
107
+ rel={logo?.linkTarget === "_blank" ? "noopener noreferrer" : ""}>
108
+ <Image
109
+ src={logo?.image}
110
+ alt={logo?.alt ?? "navigation-logo"}
111
+ width={60}
112
+ height={60}
113
+ className="text-3xl font-bold leading-none"
114
+ />
115
+ </Link>
116
+ </div>
117
+ );
118
+ }
119
+
120
+ function Buttons({
121
+ primaryButton,
122
+ secondaryButton,
123
+ }: {
124
+ primaryButton?: LabeledRoute;
125
+ secondaryButton?: LabeledRoute;
126
+ }) {
127
+ return (
128
+ <div className="hidden text-right lg:ml-auto lg:block lg:w-1/3">
129
+ {primaryButton?.label && (
130
+ <Button
131
+ as="link"
132
+ ariaLabel={primaryButton?.label}
133
+ link={primaryButton}
134
+ className="hidden lg:inline-block px-4 py-3 mb-2 text-gray-900 lg:ml-auto lg:mr-3 font-semibold rounded-global bg-secondary hover:bg-secondary/50">
135
+ {primaryButton?.label}
136
+ </Button>
137
+ )}
138
+ {secondaryButton?.label && (
139
+ <Button
140
+ as="link"
141
+ ariaLabel={secondaryButton?.label}
142
+ link={secondaryButton}
143
+ className="hidden lg:inline-block px-4 py-3 mb-2 leading-loose text-center text-white font-semibold bg-primary hover:bg-primary-foreground rounded-global">
144
+ {secondaryButton?.label}
145
+ </Button>
146
+ )}
147
+ </div>
148
+ );
149
+ }
150
+
151
+ function MobileMenu({ showMenu }: { showMenu: () => void }) {
152
+ return (
153
+ <div className="ml-auto lg:hidden">
154
+ <Button
155
+ variant="unstyled"
156
+ as="button"
157
+ ariaLabel="Navigation menu"
158
+ className="flex items-center p-3 navbar-burger text-primary"
159
+ onClick={showMenu}>
160
+ <svg
161
+ className="block w-4 h-4 fill-current"
162
+ viewBox="0 0 20 20"
163
+ xmlns="http://www.w3.org/2000/svg">
164
+ <title>Mobile menu</title>
165
+ <path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"></path>
166
+ </svg>
167
+ </Button>
168
+ </div>
169
+ );
170
+ }
171
+
172
+ function ResponsiveNavLinks({
173
+ menu,
174
+ showMenu,
175
+ links,
176
+ primaryButton,
177
+ secondaryButton,
178
+ }: ResponsiveNavLinksProps) {
179
+ return (
180
+ <div className={`${menu ? null : "hidden"} mobile-nav relative z-50`}>
181
+ <div
182
+ className="fixed inset-0 bg-gray-800 opacity-25 navbar-backdrop"
183
+ onClick={showMenu}></div>
184
+ <nav className="fixed top-0 bottom-0 left-0 flex flex-col w-5/6 max-w-sm px-6 py-6 overflow-y-auto bg-white border-r">
185
+ <div className="flex items-center mb-8">
186
+ <Button
187
+ variant="unstyled"
188
+ as="button"
189
+ ariaLabel="Navigation menu"
190
+ className="navbar-close"
191
+ onClick={showMenu}>
192
+ <svg
193
+ className="w-6 h-6 text-gray-500 cursor-pointer hover:text-gray-500"
194
+ xmlns="http://www.w3.org/2000/svg"
195
+ fill="none"
196
+ viewBox="0 0 24 24"
197
+ stroke="currentColor">
198
+ <path
199
+ strokeLinecap="round"
200
+ strokeLinejoin="round"
201
+ strokeWidth="2"
202
+ d="M6 18L18 6M6 6l12 12"></path>
203
+ </svg>
204
+ </Button>
205
+ </div>
206
+ <div>
207
+ <ul>
208
+ {links &&
209
+ links?.map((link, index) => (
210
+ <li className="mb-1" key={index}>
211
+ <Button
212
+ as="link"
213
+ ariaLabel={link?.label}
214
+ link={link}
215
+ className="block p-4 text-sm font-semibold text-gray-700 no-underline rounded hover:bg-secondary-foreground hover:text-primary">
216
+ {link?.label}
217
+ </Button>
218
+ </li>
219
+ ))}
220
+ </ul>
221
+ </div>
222
+ <div className="mt-auto">
223
+ <div className="pt-6">
224
+ {primaryButton?.label && (
225
+ <Button
226
+ as="link"
227
+ ariaLabel={primaryButton?.label}
228
+ link={primaryButton}
229
+ className="block px-4 py-3 mb-2 text-gray-900 text-center lg:ml-auto lg:mr-3 font-semibold rounded-global bg-secondary hover:bg-secondary/50">
230
+ {primaryButton?.label}
231
+ </Button>
232
+ )}
233
+ {secondaryButton?.label && (
234
+ <Button
235
+ as="link"
236
+ ariaLabel={secondaryButton?.label}
237
+ link={secondaryButton}
238
+ className="block px-4 py-3 mb-2 leading-loose text-center text-white font-semibold bg-primary hover:bg-primary-foreground rounded-global">
239
+ {secondaryButton?.label}
240
+ </Button>
241
+ )}
242
+ </div>
243
+ <Text fontSize="xs" className="my-4 text-center text-gray-700">
244
+ <span>{`© ${new Date().getFullYear()} All rights reserved.`}</span>
245
+ </Text>
246
+ </div>
247
+ </nav>
248
+ </div>
249
+ );
250
+ }
251
+
252
+ export { Navigation_C };
@@ -0,0 +1,250 @@
1
+ import { Button } from "@stackshift-ui/button";
2
+ import { Container } from "@stackshift-ui/container";
3
+ import { Flex } from "@stackshift-ui/flex";
4
+ import { Image } from "@stackshift-ui/image";
5
+ import { Link } from "@stackshift-ui/link";
6
+ import { Section } from "@stackshift-ui/section";
7
+ import { Text } from "@stackshift-ui/text";
8
+ import React from "react";
9
+ import { NavigationProps, ResponsiveNavLinksProps } from ".";
10
+ import { logoLink } from "./helper";
11
+ import { LabeledRoute, LabeledRouteWithKey, Logo } from "./types";
12
+
13
+ export default function Navigation_D({
14
+ links,
15
+ primaryButton,
16
+ secondaryButton,
17
+ logo,
18
+ }: NavigationProps) {
19
+ const [menu, setMenu] = React.useState(false);
20
+ const showMenu = () => {
21
+ setMenu(prevState => !prevState);
22
+ };
23
+
24
+ return (
25
+ <Section className="bg-background">
26
+ <nav className="relative px-6 py-6">
27
+ <Container maxWidth={1000}>
28
+ <Flex align="center" justify="between">
29
+ <NavLinks links={links} />
30
+ <LogoSection logo={logo} />
31
+ <Buttons primaryButton={primaryButton} secondaryButton={secondaryButton} />
32
+ <MobileMenu showMenu={showMenu} />
33
+ </Flex>
34
+ </Container>
35
+ </nav>
36
+ <ResponsiveNavLinks
37
+ menu={menu}
38
+ showMenu={showMenu}
39
+ links={links}
40
+ primaryButton={primaryButton}
41
+ secondaryButton={secondaryButton}
42
+ />
43
+ </Section>
44
+ );
45
+ }
46
+
47
+ function NavLinks({ links }: { links?: LabeledRouteWithKey[] }) {
48
+ if (!links) return null;
49
+
50
+ return (
51
+ <Flex className="hidden lg:flex" align="center">
52
+ <ul className="flex space-x-5">
53
+ {links.map((link, index) => (
54
+ <React.Fragment key={index}>
55
+ {link?.label && <NavItem link={link} />}
56
+ {links.length !== index + 1 && <NavIcon />}
57
+ </React.Fragment>
58
+ ))}
59
+ </ul>
60
+ </Flex>
61
+ );
62
+ }
63
+
64
+ function NavItem({ link }: { link?: LabeledRouteWithKey }) {
65
+ if (!link) return null;
66
+
67
+ return (
68
+ <li>
69
+ <Button
70
+ as="link"
71
+ ariaLabel={link?.label}
72
+ link={link}
73
+ className="text-sm text-gray-500 no-underline hover:text-gray-900">
74
+ {link?.label}
75
+ </Button>
76
+ </li>
77
+ );
78
+ }
79
+
80
+ function NavIcon() {
81
+ return (
82
+ <li className="text-gray-500">
83
+ <svg
84
+ className="w-4 h-4 current-fill"
85
+ xmlns="http://www.w3.org/2000/svg"
86
+ fill="none"
87
+ viewBox="0 0 24 24"
88
+ stroke="currentColor">
89
+ <path
90
+ strokeLinecap="round"
91
+ strokeLinejoin="round"
92
+ strokeWidth="2"
93
+ d="M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z"></path>
94
+ </svg>
95
+ </li>
96
+ );
97
+ }
98
+
99
+ function LogoSection({ logo }: { logo?: Logo }) {
100
+ if (!logo) return null;
101
+
102
+ return (
103
+ <Flex className="flex-1 justify-start lg:justify-center">
104
+ <Link
105
+ aria-label={`Go to ${logoLink(logo) === "/" ? "home page" : logoLink(logo)}`}
106
+ className="text-3xl font-bold leading-none"
107
+ href={logoLink(logo)}
108
+ target={logo?.linkTarget}
109
+ rel={logo?.linkTarget === "_blank" ? "noopener noreferrer" : ""}>
110
+ <Image
111
+ src={logo?.image}
112
+ alt={logo?.alt ?? "navigation-logo"}
113
+ width={100}
114
+ height={100}
115
+ className="object-contain"
116
+ />
117
+ </Link>
118
+ </Flex>
119
+ );
120
+ }
121
+
122
+ function Buttons({
123
+ primaryButton,
124
+ secondaryButton,
125
+ }: {
126
+ primaryButton?: LabeledRoute;
127
+ secondaryButton?: LabeledRoute;
128
+ }) {
129
+ return (
130
+ <Flex className="hidden lg:flex justify-end space-x-4">
131
+ {primaryButton?.label && (
132
+ <Button
133
+ as="link"
134
+ ariaLabel={primaryButton?.label}
135
+ link={primaryButton}
136
+ className="px-4 py-3 mb-2 text-gray-900 font-semibold rounded-global bg-secondary hover:bg-secondary/50">
137
+ {primaryButton?.label}
138
+ </Button>
139
+ )}
140
+ {secondaryButton?.label && (
141
+ <Button
142
+ as="link"
143
+ ariaLabel={secondaryButton?.label}
144
+ link={secondaryButton}
145
+ className="px-4 py-3 mb-2 leading-loose text-center text-white font-semibold bg-primary hover:bg-primary-foreground rounded-global">
146
+ {secondaryButton?.label}
147
+ </Button>
148
+ )}
149
+ </Flex>
150
+ );
151
+ }
152
+
153
+ function MobileMenu({ showMenu }: { showMenu: () => void }) {
154
+ return (
155
+ <div className="ml-auto lg:hidden">
156
+ <Button
157
+ variant="unstyled"
158
+ as="button"
159
+ ariaLabel="Navigation menu"
160
+ className="flex items-center p-3 navbar-burger text-primary"
161
+ onClick={showMenu}>
162
+ <svg
163
+ className="block w-4 h-4 fill-current"
164
+ viewBox="0 0 20 20"
165
+ xmlns="http://www.w3.org/2000/svg">
166
+ <title>Mobile menu</title>
167
+ <path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"></path>
168
+ </svg>
169
+ </Button>
170
+ </div>
171
+ );
172
+ }
173
+
174
+ function ResponsiveNavLinks({
175
+ menu,
176
+ showMenu,
177
+ links,
178
+ primaryButton,
179
+ secondaryButton,
180
+ }: ResponsiveNavLinksProps) {
181
+ return (
182
+ <div className={`${menu ? null : "hidden"} mobile-nav relative z-50`}>
183
+ <div
184
+ className="fixed inset-0 bg-gray-800 opacity-25 navbar-backdrop"
185
+ onClick={showMenu}></div>
186
+ <nav className="fixed top-0 bottom-0 left-0 flex flex-col w-5/6 max-w-sm px-6 py-6 overflow-y-auto bg-white border-r">
187
+ <div className="flex items-center mb-8">
188
+ <Button
189
+ variant="unstyled"
190
+ as="button"
191
+ ariaLabel="Navigation menu"
192
+ className="navbar-close"
193
+ onClick={showMenu}>
194
+ <svg
195
+ className="w-6 h-6 text-gray-500 cursor-pointer hover:text-gray-500"
196
+ xmlns="http://www.w3.org/2000/svg"
197
+ fill="none"
198
+ viewBox="0 0 24 24"
199
+ stroke="currentColor">
200
+ <path
201
+ strokeLinecap="round"
202
+ strokeLinejoin="round"
203
+ strokeWidth="2"
204
+ d="M6 18L18 6M6 6l12 12"></path>
205
+ </svg>
206
+ </Button>
207
+ </div>
208
+ <ul>
209
+ {links &&
210
+ links.map((link, index) => (
211
+ <li className="mb-1" key={index}>
212
+ <Button
213
+ as="link"
214
+ ariaLabel={link.label}
215
+ link={link}
216
+ className="block p-4 text-sm font-semibold text-gray-700 no-underline rounded hover:bg-secondary-foreground hover:text-primary">
217
+ {link.label}
218
+ </Button>
219
+ </li>
220
+ ))}
221
+ </ul>
222
+ <div className="mt-auto pt-6">
223
+ {primaryButton?.label && (
224
+ <Button
225
+ as="link"
226
+ ariaLabel={primaryButton.label}
227
+ link={primaryButton}
228
+ className="block px-4 py-3 mb-2 text-center font-semibold rounded-global bg-secondary hover:bg-secondary/50">
229
+ {primaryButton.label}
230
+ </Button>
231
+ )}
232
+ {secondaryButton?.label && (
233
+ <Button
234
+ as="link"
235
+ ariaLabel={secondaryButton.label}
236
+ link={secondaryButton}
237
+ className="block px-4 py-3 mb-2 leading-loose text-center text-white font-semibold bg-primary hover:bg-primary-foreground rounded-global">
238
+ {secondaryButton.label}
239
+ </Button>
240
+ )}
241
+ </div>
242
+ <Text fontSize="xs" muted className="my-4 text-center">
243
+ <span>{`© ${new Date().getFullYear()} All rights reserved.`}</span>
244
+ </Text>
245
+ </nav>
246
+ </div>
247
+ );
248
+ }
249
+
250
+ export { Navigation_D };