@syscore/ui-library 1.3.7 → 1.5.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.
- package/client/components/icons/ConceptIcons.tsx +2 -74
- package/client/components/ui/hero-section.tsx +45 -0
- package/client/components/ui/navigation.tsx +237 -76
- package/client/components/ui/page-header.tsx +145 -0
- package/client/components/ui/standard-table.tsx +554 -0
- package/client/global.css +198 -36
- package/client/lib/concept-colors.ts +115 -0
- package/client/lib/concept-icons.ts +45 -0
- package/client/lib/concepts-mock-data.ts +797 -0
- package/client/ui/Card.stories.tsx +2 -98
- package/client/ui/Hero.stories.tsx +72 -0
- package/client/ui/Navigation.stories.tsx +30 -21
- package/client/ui/PageHeader.stories.tsx +150 -0
- package/client/ui/Panel.stories.tsx +480 -0
- package/client/ui/StandardTable.stories.tsx +311 -0
- package/dist/img/half-sphere.png +0 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +46 -1
- package/dist/index.es.js +789 -265
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { cn } from "../../lib/utils";
|
|
3
|
+
import { conceptColors } from "../../lib/concept-colors";
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
export interface ConceptColor {
|
|
@@ -10,79 +11,6 @@ export interface ConceptColor {
|
|
|
10
11
|
contrast?: string;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
// Define the concept colors matching Figma design
|
|
14
|
-
export const conceptColors = {
|
|
15
|
-
mind: {
|
|
16
|
-
solid: "#0a5161",
|
|
17
|
-
light: "rgba(10,81,97,0.08)",
|
|
18
|
-
border: "rgba(10,81,97,0.16)",
|
|
19
|
-
prefix: "M",
|
|
20
|
-
},
|
|
21
|
-
community: {
|
|
22
|
-
solid: "#0f748a",
|
|
23
|
-
light: "rgba(15,116,138,0.12)",
|
|
24
|
-
border: "rgba(15,116,138,0.24)",
|
|
25
|
-
prefix: "C",
|
|
26
|
-
},
|
|
27
|
-
movement: {
|
|
28
|
-
solid: "#149ebd",
|
|
29
|
-
light: "rgba(20,158,189,0.12)",
|
|
30
|
-
border: "rgba(20,158,189,0.24)",
|
|
31
|
-
prefix: "V",
|
|
32
|
-
},
|
|
33
|
-
water: {
|
|
34
|
-
solid: "#39c9ea",
|
|
35
|
-
light: "rgba(57,201,234,0.12)",
|
|
36
|
-
border: "rgba(57,201,234,0.24)",
|
|
37
|
-
prefix: "W",
|
|
38
|
-
},
|
|
39
|
-
air: {
|
|
40
|
-
solid: "#87dff2",
|
|
41
|
-
light: "rgba(135,223,242,0.12)",
|
|
42
|
-
border: "rgba(135,223,242,0.24)",
|
|
43
|
-
prefix: "A",
|
|
44
|
-
contrast: "#7CCDDF",
|
|
45
|
-
},
|
|
46
|
-
light: {
|
|
47
|
-
solid: "#8aefdb",
|
|
48
|
-
light: "rgba(138,239,219,0.12)",
|
|
49
|
-
border: "rgba(138,239,219,0.24)",
|
|
50
|
-
prefix: "L",
|
|
51
|
-
contrast: "#7FDCC9",
|
|
52
|
-
},
|
|
53
|
-
thermalComfort: {
|
|
54
|
-
solid: "#3eddbf",
|
|
55
|
-
light: "rgba(62,221,191,0.12)",
|
|
56
|
-
border: "rgba(62,221,191,0.24)",
|
|
57
|
-
prefix: "T",
|
|
58
|
-
contrast: "#39CBB0",
|
|
59
|
-
},
|
|
60
|
-
nourishment: {
|
|
61
|
-
solid: "#17aa8d",
|
|
62
|
-
light: "rgba(23,170,141,0.12)",
|
|
63
|
-
border: "rgba(23,170,141,0.24)",
|
|
64
|
-
prefix: "N",
|
|
65
|
-
},
|
|
66
|
-
sound: {
|
|
67
|
-
solid: "#0c705c",
|
|
68
|
-
light: "rgba(12,112,92,0.12)",
|
|
69
|
-
border: "rgba(12,112,92,0.24)",
|
|
70
|
-
prefix: "S",
|
|
71
|
-
},
|
|
72
|
-
materials: {
|
|
73
|
-
solid: "#0a4f41",
|
|
74
|
-
light: "rgba(10,79,65,0.08)",
|
|
75
|
-
border: "rgba(10,79,65,0.16)",
|
|
76
|
-
prefix: "X",
|
|
77
|
-
},
|
|
78
|
-
innovation: {
|
|
79
|
-
solid: "#52545D",
|
|
80
|
-
light: "rgba(82,84,93,0.08)",
|
|
81
|
-
border: "rgba(82,84,93,0.16)",
|
|
82
|
-
prefix: "I",
|
|
83
|
-
},
|
|
84
|
-
} as const;
|
|
85
|
-
|
|
86
14
|
|
|
87
15
|
const DEFAULT_FILL = "#EFF5FB";
|
|
88
16
|
const DEFAULT_STROKE = "#2E74AD";
|
|
@@ -476,7 +404,7 @@ export const IconConceptThermalComfort: React.FC<ConceptIconProps> = ({
|
|
|
476
404
|
outlined = false,
|
|
477
405
|
}) => {
|
|
478
406
|
const conceptColor =
|
|
479
|
-
conceptColors.
|
|
407
|
+
conceptColors["thermal-comfort"].contrast || conceptColors["thermal-comfort"].solid;
|
|
480
408
|
const bgFill = outlined ? "white" : active ? conceptColor : DEFAULT_FILL;
|
|
481
409
|
const strokeColor = outlined ? conceptColor : active ? "white" : DEFAULT_STROKE;
|
|
482
410
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Button } from "./button"
|
|
2
|
+
import { motion } from "motion/react"
|
|
3
|
+
|
|
4
|
+
interface HeroSectionProps {
|
|
5
|
+
backgroundSlot?: React.ReactNode;
|
|
6
|
+
contentSlot?: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const HeroSection = ({ backgroundSlot, contentSlot }: HeroSectionProps) => {
|
|
10
|
+
return (
|
|
11
|
+
<section className="relative flex flex-col sm:pt-[169px] pt-24 items-center min-h-[454px] bg-cyan-900 overflow-hidden">
|
|
12
|
+
{backgroundSlot}
|
|
13
|
+
|
|
14
|
+
{/* Hero Content */}
|
|
15
|
+
<header className="relative z-10 flex flex-col items-center text-center overflow-visible">
|
|
16
|
+
<motion.h2
|
|
17
|
+
className="heading-small mb-6"
|
|
18
|
+
initial={{ opacity: 0, y: 20 }}
|
|
19
|
+
animate={{ opacity: 1, y: 0 }}
|
|
20
|
+
transition={{ duration: 0.6, delay: 0.3 }}
|
|
21
|
+
>
|
|
22
|
+
<span
|
|
23
|
+
style={{
|
|
24
|
+
background: "linear-gradient(90deg, #084654 0.08%, #2D718A 50.08%, #084654 100.08%)",
|
|
25
|
+
backgroundClip: "text",
|
|
26
|
+
WebkitBackgroundClip: "text",
|
|
27
|
+
WebkitTextFillColor: "transparent",
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
30
|
+
One unified, harmonized standard
|
|
31
|
+
</span>
|
|
32
|
+
</motion.h2>
|
|
33
|
+
<motion.h1
|
|
34
|
+
className="text-white heading-large mb-[70px]"
|
|
35
|
+
initial={{ opacity: 0, y: 20 }}
|
|
36
|
+
animate={{ opacity: 1, y: 0 }}
|
|
37
|
+
transition={{ duration: 0.6, delay: 0.4 }}
|
|
38
|
+
>
|
|
39
|
+
One WELL
|
|
40
|
+
</motion.h1>
|
|
41
|
+
{contentSlot}
|
|
42
|
+
</header>
|
|
43
|
+
</section>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { AnimatePresence, motion } from "motion/react";
|
|
3
3
|
import { cn } from "@/lib/utils";
|
|
4
|
-
import { UtilityClose } from "../icons/UtilityClose";
|
|
5
4
|
import { NavLogo } from "../icons/NavLogo";
|
|
6
5
|
import { NavAccount } from "../icons/NavAccount";
|
|
7
6
|
import { NavBullet } from "../icons/NavBullet";
|
|
8
7
|
import { Button } from "@/components/ui/button";
|
|
9
|
-
|
|
8
|
+
import { UtilityClearRegular } from "../icons/UtilityClearRegular";
|
|
9
|
+
import { StandardLogo } from "../icons/StandardLogo";
|
|
10
10
|
export interface NavItem {
|
|
11
11
|
label: string;
|
|
12
12
|
active?: boolean;
|
|
@@ -21,20 +21,170 @@ export type LinkComponent = React.ComponentType<{
|
|
|
21
21
|
onClick?: (e: React.MouseEvent) => void;
|
|
22
22
|
}>;
|
|
23
23
|
|
|
24
|
+
interface NavLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
25
|
+
href: string;
|
|
26
|
+
LinkComponent?: LinkComponent;
|
|
27
|
+
onLinkClick?: (href: string) => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const NavLink = React.forwardRef<HTMLAnchorElement, NavLinkProps>(
|
|
31
|
+
({ href, LinkComponent, onLinkClick, children, ...props }, ref) => {
|
|
32
|
+
if (LinkComponent) {
|
|
33
|
+
return (
|
|
34
|
+
<LinkComponent
|
|
35
|
+
href={href}
|
|
36
|
+
className={props.className}
|
|
37
|
+
aria-label={props["aria-label"]}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
</LinkComponent>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (onLinkClick) {
|
|
45
|
+
return (
|
|
46
|
+
<a
|
|
47
|
+
ref={ref}
|
|
48
|
+
href={href}
|
|
49
|
+
{...props}
|
|
50
|
+
onClick={(e) => {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
onLinkClick(href);
|
|
53
|
+
}}
|
|
54
|
+
>
|
|
55
|
+
{children}
|
|
56
|
+
</a>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<a ref={ref} href={href} {...props}>
|
|
62
|
+
{children}
|
|
63
|
+
</a>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
NavLink.displayName = "NavLink";
|
|
68
|
+
|
|
24
69
|
interface NavigationProps {
|
|
25
70
|
navItems?: NavItem[];
|
|
26
71
|
isStrategy?: boolean;
|
|
27
72
|
Link?: LinkComponent; // Optional Link component from routing library
|
|
28
73
|
onLinkClick?: (href: string) => void; // Fallback callback for navigation
|
|
29
74
|
onClose?: () => void;
|
|
75
|
+
pathname: string;
|
|
30
76
|
}
|
|
31
77
|
|
|
78
|
+
const ALPHA_PATH =
|
|
79
|
+
"M5.3387 0.0229882C5.37971 0.0229882 5.45295 0.0199228 5.5584 0.0137925C5.66386 0.00459714 5.74442 0 5.80007 0C6.72867 0 7.49908 0.269732 8.11131 0.809196C8.72354 1.34559 9.14097 2.09195 9.3636 3.04828C9.44855 3.47433 9.49835 3.96628 9.513 4.52414V5.16782C10.2014 4.07663 10.7287 2.85517 11.0948 1.50345C11.1505 1.29808 11.1959 1.17701 11.2311 1.14023C11.2662 1.10345 11.3761 1.08506 11.5606 1.08506C11.8535 1.08506 12 1.13563 12 1.23678C12 1.25211 11.9722 1.37778 11.9165 1.61379C11.5093 3.24751 10.7931 4.77701 9.76785 6.2023L9.53497 6.51034L9.55694 7.04368C9.59795 8.23295 9.72391 8.9318 9.93482 9.14023C9.97583 9.16782 10.0388 9.18161 10.1238 9.18161C10.32 9.15402 10.5031 9.06973 10.673 8.92874C10.8429 8.78774 10.963 8.62222 11.0333 8.43218C11.0597 8.32797 11.0948 8.26513 11.1388 8.24368C11.1798 8.22222 11.2852 8.21149 11.4551 8.21149C11.7364 8.21149 11.877 8.27739 11.877 8.40919C11.877 8.49808 11.8345 8.63142 11.7495 8.8092C11.5943 9.13103 11.3687 9.4069 11.0729 9.63678C10.777 9.8636 10.4475 9.97701 10.0842 9.97701H9.93482C8.97986 9.97701 8.3398 9.44674 8.01465 8.38621L7.95313 8.23448C7.20615 8.74942 6.79165 9.02835 6.70963 9.07126C5.66679 9.69042 4.61809 10 3.56353 10C2.56756 10 1.76346 9.70575 1.15123 9.11724C0.538997 8.52874 0.162578 7.75632 0.02197 6.8C0.0073233 6.71111 0 6.54866 0 6.31264C0 5.9295 0.02197 5.62146 0.0659099 5.38851C0.276822 4.06437 0.887587 2.8751 1.89821 1.82069C2.91175 0.769348 4.05859 0.170115 5.3387 0.0229882ZM1.83669 7.10805C1.83669 7.73946 1.9978 8.24368 2.32003 8.62069C2.64518 8.99464 3.09484 9.18161 3.66899 9.18161C4.03515 9.18161 4.44379 9.12337 4.89491 9.0069C5.6829 8.80153 6.44892 8.4046 7.19297 7.81609C7.29257 7.74253 7.38777 7.66437 7.47858 7.58161C7.56939 7.50192 7.64262 7.43295 7.69828 7.37471L7.78176 7.28276L7.76419 7.08506C7.76419 6.95326 7.75979 6.75862 7.75101 6.50115C7.74515 6.24368 7.74222 5.98927 7.74222 5.73793C7.72757 5.18008 7.71732 4.74636 7.71146 4.43678C7.70267 4.1272 7.67338 3.74866 7.62358 3.30115C7.57671 2.85364 7.5108 2.50728 7.42585 2.26207C7.3409 2.01992 7.22519 1.77471 7.07873 1.52644C6.92933 1.2751 6.73892 1.09425 6.50751 0.983908C6.27609 0.873563 6.00513 0.81839 5.69462 0.81839C4.72501 0.81839 3.87404 1.35479 3.14171 2.42759C2.79019 2.97318 2.49579 3.71647 2.25851 4.65747C1.9773 5.73333 1.83669 6.55019 1.83669 7.10805Z";
|
|
80
|
+
|
|
81
|
+
const PATH_LENGTH = 60;
|
|
82
|
+
|
|
83
|
+
const AlphaIcon = ({ dark }: { dark?: boolean }) => {
|
|
84
|
+
if (dark) {
|
|
85
|
+
return (
|
|
86
|
+
<svg
|
|
87
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
88
|
+
width="12"
|
|
89
|
+
height="10"
|
|
90
|
+
viewBox="0 0 12 10"
|
|
91
|
+
fill="none"
|
|
92
|
+
className="mt-1.5"
|
|
93
|
+
style={{ overflow: "visible" }}
|
|
94
|
+
>
|
|
95
|
+
<path d={ALPHA_PATH} fill="currentColor" />
|
|
96
|
+
{/* Animated stroke trace */}
|
|
97
|
+
{/* <motion.path
|
|
98
|
+
d={ALPHA_PATH}
|
|
99
|
+
fill="none"
|
|
100
|
+
stroke="#282A31"
|
|
101
|
+
strokeWidth="0.4"
|
|
102
|
+
strokeLinecap="round"
|
|
103
|
+
strokeLinejoin="round"
|
|
104
|
+
initial={{ strokeDashoffset: PATH_LENGTH }}
|
|
105
|
+
animate={{ strokeDashoffset: -PATH_LENGTH }}
|
|
106
|
+
style={{ strokeDasharray: `8 ${PATH_LENGTH - 8}` }}
|
|
107
|
+
transition={{
|
|
108
|
+
duration: 4,
|
|
109
|
+
repeat: Infinity,
|
|
110
|
+
ease: "linear",
|
|
111
|
+
}}
|
|
112
|
+
/> */}
|
|
113
|
+
</svg>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<svg
|
|
119
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
120
|
+
width="12"
|
|
121
|
+
height="10"
|
|
122
|
+
viewBox="0 0 12 10"
|
|
123
|
+
fill="none"
|
|
124
|
+
className="mt-1.5"
|
|
125
|
+
style={{ overflow: "visible" }}
|
|
126
|
+
>
|
|
127
|
+
{/* Base fill with gradient */}
|
|
128
|
+
<path
|
|
129
|
+
d={ALPHA_PATH}
|
|
130
|
+
fill="url(#paint0_linear_10081_30848)"
|
|
131
|
+
opacity="0.4"
|
|
132
|
+
/>
|
|
133
|
+
{/* Animated stroke trace with gradient */}
|
|
134
|
+
<motion.path
|
|
135
|
+
d={ALPHA_PATH}
|
|
136
|
+
fill="none"
|
|
137
|
+
stroke="url(#stroke_gradient)"
|
|
138
|
+
strokeWidth="0.4"
|
|
139
|
+
strokeLinecap="round"
|
|
140
|
+
strokeLinejoin="round"
|
|
141
|
+
initial={{ strokeDashoffset: PATH_LENGTH }}
|
|
142
|
+
animate={{ strokeDashoffset: -PATH_LENGTH }}
|
|
143
|
+
style={{ strokeDasharray: `8 ${PATH_LENGTH - 8}` }}
|
|
144
|
+
transition={{
|
|
145
|
+
duration: 2,
|
|
146
|
+
repeat: Infinity,
|
|
147
|
+
repeatDelay: 8,
|
|
148
|
+
ease: "linear",
|
|
149
|
+
}}
|
|
150
|
+
/>
|
|
151
|
+
<defs>
|
|
152
|
+
<linearGradient
|
|
153
|
+
id="paint0_linear_10081_30848"
|
|
154
|
+
x1="-3.27254"
|
|
155
|
+
y1="4.99923"
|
|
156
|
+
x2="6.36738"
|
|
157
|
+
y2="-2.36962"
|
|
158
|
+
gradientUnits="userSpaceOnUse"
|
|
159
|
+
>
|
|
160
|
+
<stop stopColor="#8AEFDB" />
|
|
161
|
+
<stop offset="0.5" stopColor="#D4BACE" />
|
|
162
|
+
<stop offset="1" stopColor="#CBE0F1" />
|
|
163
|
+
</linearGradient>
|
|
164
|
+
<linearGradient
|
|
165
|
+
id="stroke_gradient"
|
|
166
|
+
x1="0"
|
|
167
|
+
y1="0"
|
|
168
|
+
x2="12"
|
|
169
|
+
y2="10"
|
|
170
|
+
gradientUnits="userSpaceOnUse"
|
|
171
|
+
>
|
|
172
|
+
<stop stopColor="#8AEFDB" />
|
|
173
|
+
<stop offset="0.5" stopColor="#D4BACE" />
|
|
174
|
+
<stop offset="1" stopColor="#CBE0F1" />
|
|
175
|
+
</linearGradient>
|
|
176
|
+
</defs>
|
|
177
|
+
</svg>
|
|
178
|
+
);
|
|
179
|
+
};
|
|
180
|
+
|
|
32
181
|
export const Navigation: React.FC<NavigationProps> = ({
|
|
33
182
|
navItems,
|
|
34
183
|
isStrategy = false,
|
|
35
184
|
Link: LinkComponent,
|
|
36
185
|
onLinkClick,
|
|
37
186
|
onClose,
|
|
187
|
+
pathname,
|
|
38
188
|
}) => {
|
|
39
189
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
40
190
|
const [activeItem, setActiveItem] = React.useState<number | null>(null);
|
|
@@ -44,6 +194,8 @@ export const Navigation: React.FC<NavigationProps> = ({
|
|
|
44
194
|
const menuItemsRef = React.useRef<HTMLDivElement>(null);
|
|
45
195
|
const overlayRef = React.useRef<HTMLDivElement>(null);
|
|
46
196
|
|
|
197
|
+
const isHomepage = pathname === "/";
|
|
198
|
+
|
|
47
199
|
const handleMouseLeave = () => {
|
|
48
200
|
setIsOpen(false);
|
|
49
201
|
setActiveItem(null);
|
|
@@ -112,34 +264,43 @@ export const Navigation: React.FC<NavigationProps> = ({
|
|
|
112
264
|
|
|
113
265
|
<div className="navigation-container">
|
|
114
266
|
<div className="navigation-logo-container">
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
href="/"
|
|
134
|
-
className={cn(
|
|
135
|
-
"navigation-logo-link",
|
|
136
|
-
isStrategy && "navigation-logo-link--strategy",
|
|
267
|
+
<AnimatePresence mode="popLayout">
|
|
268
|
+
{!isHomepage && (
|
|
269
|
+
<motion.div
|
|
270
|
+
layout
|
|
271
|
+
initial={{ opacity: 0, scale: 0.8 }}
|
|
272
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
273
|
+
exit={{ opacity: 0, scale: 0.8 }}
|
|
274
|
+
transition={{ duration: 0.2, ease: "easeOut" }}
|
|
275
|
+
style={{ willChange: "transform, opacity" }}
|
|
276
|
+
>
|
|
277
|
+
<Button
|
|
278
|
+
size="icon"
|
|
279
|
+
className=" mr-6"
|
|
280
|
+
onClick={() => onClose?.()}
|
|
281
|
+
>
|
|
282
|
+
<UtilityClearRegular />
|
|
283
|
+
</Button>
|
|
284
|
+
</motion.div>
|
|
137
285
|
)}
|
|
138
|
-
|
|
139
|
-
|
|
286
|
+
</AnimatePresence>
|
|
287
|
+
|
|
288
|
+
<motion.div
|
|
289
|
+
layout
|
|
290
|
+
transition={{ duration: 0.2, ease: "easeOut" }}
|
|
140
291
|
>
|
|
141
|
-
<
|
|
142
|
-
|
|
292
|
+
<NavLink
|
|
293
|
+
href="/"
|
|
294
|
+
className={cn("navigation-logo-link")}
|
|
295
|
+
data-strategy={isStrategy}
|
|
296
|
+
aria-label="Home"
|
|
297
|
+
>
|
|
298
|
+
<NavLogo dark={isStrategy} />
|
|
299
|
+
|
|
300
|
+
<StandardLogo className={cn(!isStrategy ? "text-white" : "text-black")} />
|
|
301
|
+
<AlphaIcon dark={isStrategy} />
|
|
302
|
+
</NavLink>
|
|
303
|
+
</motion.div>
|
|
143
304
|
</div>
|
|
144
305
|
|
|
145
306
|
{!isStrategy ? (
|
|
@@ -147,54 +308,54 @@ export const Navigation: React.FC<NavigationProps> = ({
|
|
|
147
308
|
<ul className="navigation-nav-list">
|
|
148
309
|
{navItems
|
|
149
310
|
? navItems.map((item, index) => (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
311
|
+
<li
|
|
312
|
+
key={index + 1}
|
|
313
|
+
className="navigation-nav-item"
|
|
314
|
+
onMouseEnter={() => handleNavItemMouseEnter(index)}
|
|
315
|
+
>
|
|
316
|
+
<span className="navigation-nav-link">{item.label}</span>
|
|
317
|
+
|
|
318
|
+
{/* Underline */}
|
|
319
|
+
{activeItem === index + 1 && (
|
|
320
|
+
<motion.div
|
|
321
|
+
id="underline"
|
|
322
|
+
className="navigation-underline"
|
|
323
|
+
layoutId="underline"
|
|
324
|
+
transition={{ duration: 0.2, ease: "easeOut" }}
|
|
325
|
+
>
|
|
326
|
+
<div
|
|
327
|
+
className="navigation-underline-circle navigation-underline-circle--gradient"
|
|
328
|
+
style={{
|
|
329
|
+
width: "10px",
|
|
330
|
+
height: "5px",
|
|
331
|
+
borderBottomLeftRadius: "100px",
|
|
332
|
+
borderBottomRightRadius: "100px",
|
|
333
|
+
borderBottom: "0",
|
|
334
|
+
boxSizing: "border-box",
|
|
335
|
+
}}
|
|
336
|
+
/>
|
|
337
|
+
</motion.div>
|
|
338
|
+
)}
|
|
339
|
+
{index === 0 && (
|
|
340
|
+
<div
|
|
341
|
+
className="navigation-underline navigation-underline--static"
|
|
342
|
+
style={{ transition: "all 0.2s ease-out" }}
|
|
343
|
+
>
|
|
179
344
|
<div
|
|
180
|
-
className="navigation-underline navigation-underline--
|
|
181
|
-
style={{
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
</div>
|
|
195
|
-
)}
|
|
196
|
-
</li>
|
|
197
|
-
))
|
|
345
|
+
className="navigation-underline-circle navigation-underline-circle--white"
|
|
346
|
+
style={{
|
|
347
|
+
width: "10px",
|
|
348
|
+
height: "5px",
|
|
349
|
+
borderTopLeftRadius: "100px",
|
|
350
|
+
borderTopRightRadius: "100px",
|
|
351
|
+
borderBottom: "0",
|
|
352
|
+
boxSizing: "border-box",
|
|
353
|
+
}}
|
|
354
|
+
/>
|
|
355
|
+
</div>
|
|
356
|
+
)}
|
|
357
|
+
</li>
|
|
358
|
+
))
|
|
198
359
|
: null}
|
|
199
360
|
</ul>
|
|
200
361
|
</div>
|
|
@@ -204,7 +365,7 @@ export const Navigation: React.FC<NavigationProps> = ({
|
|
|
204
365
|
<NavLink
|
|
205
366
|
href="/"
|
|
206
367
|
aria-label="Account link"
|
|
207
|
-
className="navigation-account-link"
|
|
368
|
+
className={cn("navigation-account-link", isStrategy && "navigation-account-link--strategy")}
|
|
208
369
|
data-open={isOpen}
|
|
209
370
|
data-strategy={isStrategy}
|
|
210
371
|
>
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { motion, AnimatePresence } from "motion/react";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
// Root Component
|
|
8
|
+
interface PageHeaderProps extends React.ComponentPropsWithoutRef<"header"> {}
|
|
9
|
+
|
|
10
|
+
const PageHeader = React.forwardRef<HTMLElement, PageHeaderProps>(
|
|
11
|
+
({ children, className, ...props }, ref) => {
|
|
12
|
+
return (
|
|
13
|
+
<header ref={ref} className={cn("page-header", className)} {...props}>
|
|
14
|
+
{children}
|
|
15
|
+
</header>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
PageHeader.displayName = "PageHeader";
|
|
20
|
+
|
|
21
|
+
// TopSection - flex container for badges/actions
|
|
22
|
+
interface PageHeaderTopSectionProps
|
|
23
|
+
extends React.ComponentPropsWithoutRef<"div"> {}
|
|
24
|
+
|
|
25
|
+
const PageHeaderTopSection = React.forwardRef<
|
|
26
|
+
HTMLDivElement,
|
|
27
|
+
PageHeaderTopSectionProps
|
|
28
|
+
>(({ children, className, ...props }, ref) => {
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
ref={ref}
|
|
32
|
+
className={cn("page-header-top-section", className)}
|
|
33
|
+
{...props}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
PageHeaderTopSection.displayName = "PageHeaderTopSection";
|
|
40
|
+
|
|
41
|
+
// LeftContent - groups left-side elements
|
|
42
|
+
interface PageHeaderLeftContentProps
|
|
43
|
+
extends React.ComponentPropsWithoutRef<"div"> {}
|
|
44
|
+
|
|
45
|
+
const PageHeaderLeftContent = React.forwardRef<
|
|
46
|
+
HTMLDivElement,
|
|
47
|
+
PageHeaderLeftContentProps
|
|
48
|
+
>(({ children, className, ...props }, ref) => {
|
|
49
|
+
return (
|
|
50
|
+
<div
|
|
51
|
+
ref={ref}
|
|
52
|
+
className={cn("page-header-left-content", className)}
|
|
53
|
+
{...props}
|
|
54
|
+
>
|
|
55
|
+
{children}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
PageHeaderLeftContent.displayName = "PageHeaderLeftContent";
|
|
60
|
+
|
|
61
|
+
// Badge - with optional animation
|
|
62
|
+
interface PageHeaderBadgeProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
63
|
+
/** Whether to animate the badge appearance */
|
|
64
|
+
animated?: boolean;
|
|
65
|
+
/** Show badge conditionally */
|
|
66
|
+
show?: boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const PageHeaderBadge = React.forwardRef<HTMLDivElement, PageHeaderBadgeProps>(
|
|
70
|
+
({ children, animated = false, show = true, className, style, ...props }, ref) => {
|
|
71
|
+
if (animated) {
|
|
72
|
+
return (
|
|
73
|
+
<AnimatePresence>
|
|
74
|
+
{show && (
|
|
75
|
+
<motion.div
|
|
76
|
+
initial={{ opacity: 0, scale: 0.8 }}
|
|
77
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
78
|
+
exit={{ opacity: 0, scale: 0.8 }}
|
|
79
|
+
transition={{ duration: 0.2 }}
|
|
80
|
+
className={className}
|
|
81
|
+
style={style}
|
|
82
|
+
>
|
|
83
|
+
{children}
|
|
84
|
+
</motion.div>
|
|
85
|
+
)}
|
|
86
|
+
</AnimatePresence>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!show) return null;
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div ref={ref} className={className} style={style} {...props}>
|
|
94
|
+
{children}
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
PageHeaderBadge.displayName = "PageHeaderBadge";
|
|
100
|
+
|
|
101
|
+
// Title
|
|
102
|
+
interface PageHeaderTitleProps
|
|
103
|
+
extends React.ComponentPropsWithoutRef<"h1"> {}
|
|
104
|
+
|
|
105
|
+
const PageHeaderTitle = React.forwardRef<
|
|
106
|
+
HTMLHeadingElement,
|
|
107
|
+
PageHeaderTitleProps
|
|
108
|
+
>(({ children, className, ...props }, ref) => {
|
|
109
|
+
return (
|
|
110
|
+
<h1 ref={ref} className={cn("page-header-title", className)} {...props}>
|
|
111
|
+
{children}
|
|
112
|
+
</h1>
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
PageHeaderTitle.displayName = "PageHeaderTitle";
|
|
116
|
+
|
|
117
|
+
// Description
|
|
118
|
+
interface PageHeaderDescriptionProps
|
|
119
|
+
extends React.ComponentPropsWithoutRef<"p"> {}
|
|
120
|
+
|
|
121
|
+
const PageHeaderDescription = React.forwardRef<
|
|
122
|
+
HTMLParagraphElement,
|
|
123
|
+
PageHeaderDescriptionProps
|
|
124
|
+
>(({ children, className, ...props }, ref) => {
|
|
125
|
+
return (
|
|
126
|
+
<p
|
|
127
|
+
ref={ref}
|
|
128
|
+
className={cn("page-header-description", className)}
|
|
129
|
+
{...props}
|
|
130
|
+
>
|
|
131
|
+
{children}
|
|
132
|
+
</p>
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
PageHeaderDescription.displayName = "PageHeaderDescription";
|
|
136
|
+
|
|
137
|
+
// Compound exports
|
|
138
|
+
export {
|
|
139
|
+
PageHeader,
|
|
140
|
+
PageHeaderTopSection,
|
|
141
|
+
PageHeaderLeftContent,
|
|
142
|
+
PageHeaderBadge,
|
|
143
|
+
PageHeaderTitle,
|
|
144
|
+
PageHeaderDescription,
|
|
145
|
+
};
|