@agilant/toga-blox 1.0.5
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/Dockerfile +9 -0
- package/README.md +69 -0
- package/assets/Logo.png +0 -0
- package/assets/compass-card-image-2.png +0 -0
- package/assets/compass-card-image-3.png +0 -0
- package/assets/compass-card-image-4.png +0 -0
- package/assets/compass-card-image.png +0 -0
- package/assets/compass-logo.png +0 -0
- package/assets/compass-tech-hero-bg.png +0 -0
- package/assets/contact-image.png +0 -0
- package/assets/green-laptop.png +0 -0
- package/assets/heroImage.png +0 -0
- package/assets/placeholder-no-image-available.png +0 -0
- package/assets/team.png +0 -0
- package/declarations.d.ts +4 -0
- package/docker-compose.yml +22 -0
- package/global.css +4 -0
- package/index.js +4 -0
- package/nodemon.json +5 -0
- package/package.json +70 -0
- package/postcss.config.js +6 -0
- package/src/components/Badge/Badge.stories.tsx +284 -0
- package/src/components/Badge/Badge.test.tsx +185 -0
- package/src/components/Badge/Badge.tsx +137 -0
- package/src/components/Badge/Badge.types.tsx +28 -0
- package/src/components/Badge/badgeClassNames.tsx +152 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/Card/Card.stories.tsx +91 -0
- package/src/components/Card/Card.test.tsx +53 -0
- package/src/components/Card/Card.tsx +30 -0
- package/src/components/Card/Card.types.ts +11 -0
- package/src/components/Card/DUMMYPRODUCTDATA.json +670 -0
- package/src/components/Card/cardClassNames.ts +49 -0
- package/src/components/Card/index.ts +3 -0
- package/src/components/Card/templates/CompassCardTemplate.tsx +58 -0
- package/src/components/Card/templates/HorizontalCardTemplate.tsx +184 -0
- package/src/components/Card/templates/VerticalCardTemplate.tsx +154 -0
- package/src/components/Footer/ContactInfoItem.tsx +20 -0
- package/src/components/Footer/DUMMYFOOTERDATA.json +132 -0
- package/src/components/Footer/Footer.stories.tsx +292 -0
- package/src/components/Footer/Footer.test.tsx +90 -0
- package/src/components/Footer/Footer.tsx +159 -0
- package/src/components/Footer/Footer.types.tsx +61 -0
- package/src/components/Footer/footerClassNames.tsx +57 -0
- package/src/components/FormButton/FormButton.stories.tsx +199 -0
- package/src/components/FormButton/FormButton.test.tsx +73 -0
- package/src/components/FormButton/FormButton.tsx +116 -0
- package/src/components/FormButton/FormButton.types.ts +32 -0
- package/src/components/FormButton/formButtonClassNames.tsx +153 -0
- package/src/components/FormButton/index.ts +2 -0
- package/src/components/GenericList/DUMMYLISTDATA.json +560 -0
- package/src/components/GenericList/GenericList.stories.tsx +104 -0
- package/src/components/GenericList/GenericList.test.tsx +29 -0
- package/src/components/GenericList/GenericList.tsx +146 -0
- package/src/components/GenericList/genericListClassNames.tsx +8 -0
- package/src/components/GenericList/templates/DummyDataList.tsx +23 -0
- package/src/components/GenericList/templates/DynamicIconList.tsx +74 -0
- package/src/components/HamburgerButton/HamburgerButton.tsx +68 -0
- package/src/components/HamburgerButton/HamburgerButton.types.tsx +6 -0
- package/src/components/HamburgerButton/index.ts +2 -0
- package/src/components/Header/DUMMYICONDATA.json +136 -0
- package/src/components/Header/Header.stories.tsx +521 -0
- package/src/components/Header/Header.test.tsx +323 -0
- package/src/components/Header/Header.tsx +289 -0
- package/src/components/Header/Header.types.ts +52 -0
- package/src/components/Header/headerClassNames.tsx +50 -0
- package/src/components/Header/headerContext.tsx +125 -0
- package/src/components/Header/index.ts +2 -0
- package/src/components/Hero/Hero.stories.tsx +69 -0
- package/src/components/Hero/Hero.test.tsx +109 -0
- package/src/components/Hero/Hero.tsx +58 -0
- package/src/components/Hero/Hero.types.ts +9 -0
- package/src/components/Hero/index.ts +2 -0
- package/src/components/Icon/Icon.stories.tsx +227 -0
- package/src/components/Icon/Icon.test.tsx +53 -0
- package/src/components/Icon/Icon.tsx +208 -0
- package/src/components/Icon/Icon.types.ts +24 -0
- package/src/components/Icon/iconClassNames.ts +79 -0
- package/src/components/Icon/index.ts +2 -0
- package/src/components/Image/Image.stories.tsx +79 -0
- package/src/components/Image/Image.test.tsx +87 -0
- package/src/components/Image/Image.tsx +49 -0
- package/src/components/Image/Image.types.ts +11 -0
- package/src/components/Image/index.ts +2 -0
- package/src/components/Input/Input.stories.tsx +651 -0
- package/src/components/Input/Input.test.tsx +90 -0
- package/src/components/Input/Input.tsx +226 -0
- package/src/components/Input/Input.types.ts +52 -0
- package/src/components/Input/InputMemoTypes.tsx +32 -0
- package/src/components/Input/index.ts +2 -0
- package/src/components/Input/inputClassNames.tsx +169 -0
- package/src/components/MobileMenu/MobileMenu.tsx +41 -0
- package/src/components/MobileMenu/MobileMenu.types.tsx +30 -0
- package/src/components/MobileMenu/index.ts +2 -0
- package/src/components/Nav/DUMMYNAVDATA.json +234 -0
- package/src/components/Nav/Nav.stories.tsx +181 -0
- package/src/components/Nav/Nav.test.tsx +89 -0
- package/src/components/Nav/Nav.tsx +242 -0
- package/src/components/Nav/Nav.types.tsx +35 -0
- package/src/components/Nav/index.ts +2 -0
- package/src/components/Nav/navClassNames.tsx +192 -0
- package/src/components/Page/TableDataDummy.tsx +216 -0
- package/src/components/Page/ViewPageTemplate.stories.tsx +546 -0
- package/src/components/Page/ViewPageTemplate.test.tsx +361 -0
- package/src/components/Page/ViewPageTemplate.tsx +10 -0
- package/src/components/Page/ViewPageTemplate.types.ts +6 -0
- package/src/components/Page/index.ts +2 -0
- package/src/components/PageSection/PageSection.stories.tsx +114 -0
- package/src/components/PageSection/PageSection.tsx +12 -0
- package/src/components/PageSection/PageSection.types.ts +6 -0
- package/src/components/PageSection/PageSections.test.tsx +88 -0
- package/src/components/PageSection/index.ts +2 -0
- package/src/components/Text/Text.stories.tsx +60 -0
- package/src/components/Text/Text.test.tsx +52 -0
- package/src/components/Text/Text.tsx +80 -0
- package/src/components/Text/Text.types.ts +12 -0
- package/src/components/Text/index.ts +2 -0
- package/src/components/Toaster/Toaster.stories.tsx +122 -0
- package/src/components/Toaster/Toaster.test.tsx +61 -0
- package/src/components/Toaster/Toaster.tsx +80 -0
- package/src/components/Toaster/Toaster.types.ts +12 -0
- package/src/components/Toaster/index.ts +2 -0
- package/src/hoc/index.ts +2 -0
- package/src/hoc/styling/withStoryBook.tsx +19 -0
- package/src/main.css +3 -0
- package/src/setupTests.ts +1 -0
- package/src/userHoc/index.ts +1 -0
- package/src/userHoc/withMemo.tsx +20 -0
- package/src/utils/assertTagName.tsx +7 -0
- package/src/utils/generateAccordionItem.tsx +102 -0
- package/src/utils/generateFooterContacts.tsx +75 -0
- package/src/utils/generateNavMenu.tsx +54 -0
- package/src/utils/generateSocialList.tsx +34 -0
- package/src/utils/getFontAwesomeIcon.tsx +25 -0
- package/src/utils/inputValidation.tsx +26 -0
- package/tailwind.config.js +32 -0
- package/tsconfig.json +25 -0
- package/vite.config.ts +33 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, beforeEach, test } from "vitest";
|
|
3
|
+
import Badge from "./Badge";
|
|
4
|
+
import Text from "../Text/Text";
|
|
5
|
+
import Image from "../Image/Image";
|
|
6
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
7
|
+
import {
|
|
8
|
+
faCircleExclamation,
|
|
9
|
+
faCheck,
|
|
10
|
+
} from "@fortawesome/free-solid-svg-icons";
|
|
11
|
+
|
|
12
|
+
describe("<Badge />", () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
render(
|
|
15
|
+
<Badge
|
|
16
|
+
type="span"
|
|
17
|
+
color="red"
|
|
18
|
+
borderColor="red"
|
|
19
|
+
hoverColor="none"
|
|
20
|
+
badgeSize="large"
|
|
21
|
+
testId="priority-badge"
|
|
22
|
+
mobileIcon={<FontAwesomeIcon icon={faCircleExclamation} />}
|
|
23
|
+
mobileIconLabel="Priority"
|
|
24
|
+
text={
|
|
25
|
+
<Text
|
|
26
|
+
size="md"
|
|
27
|
+
color="black"
|
|
28
|
+
text="Priority"
|
|
29
|
+
fontFamily="serif"
|
|
30
|
+
tag="h2"
|
|
31
|
+
additionalClasses="font-bold"
|
|
32
|
+
/>
|
|
33
|
+
}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("renders badge", () => {
|
|
39
|
+
const badge = screen.getByTestId("priority-badge");
|
|
40
|
+
expect(badge).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("has correct text", () => {
|
|
44
|
+
expect(screen.getByTestId("priority-badge")).toHaveTextContent("Priority");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("has correct background color", () => {
|
|
48
|
+
const badge = screen.getByTestId("priority-badge");
|
|
49
|
+
expect(badge).toHaveClass("bg-red-200");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("has correct border color", () => {
|
|
53
|
+
const badge = screen.getByTestId("priority-badge");
|
|
54
|
+
expect(badge).toHaveClass("border-red-500");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("<Badge /> with icon", () => {
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
render(
|
|
62
|
+
<Badge
|
|
63
|
+
type="span"
|
|
64
|
+
color="green"
|
|
65
|
+
borderColor="green"
|
|
66
|
+
hoverColor="none"
|
|
67
|
+
badgeSize="large"
|
|
68
|
+
testId="icon-badge"
|
|
69
|
+
tagStyle={false}
|
|
70
|
+
cursorPointer={false}
|
|
71
|
+
icon={<FontAwesomeIcon icon={faCheck} />}
|
|
72
|
+
mobileIcon={<FontAwesomeIcon icon={faCheck} />}
|
|
73
|
+
mobileIconLabel="Complete"
|
|
74
|
+
text={
|
|
75
|
+
<Text
|
|
76
|
+
size="md"
|
|
77
|
+
color="black"
|
|
78
|
+
text="Complete"
|
|
79
|
+
fontFamily="serif"
|
|
80
|
+
tag="h2"
|
|
81
|
+
additionalClasses="font-bold"
|
|
82
|
+
/>
|
|
83
|
+
}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("renders badge with icon", () => {
|
|
89
|
+
const badge = screen.getByTestId("icon-badge");
|
|
90
|
+
expect(badge).toBeInTheDocument();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("has correct text", () => {
|
|
94
|
+
expect(screen.getByTestId("icon-badge")).toHaveTextContent("Complete");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("has correct background color", () => {
|
|
98
|
+
const badge = screen.getByTestId("icon-badge");
|
|
99
|
+
expect(badge).toHaveClass("bg-teal-100");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("has correct border color", () => {
|
|
103
|
+
const badge = screen.getByTestId("icon-badge");
|
|
104
|
+
expect(badge).toHaveClass("border-teal-700");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("has correct icon", () => {
|
|
108
|
+
const icon = screen.getByTestId("badge-icon");
|
|
109
|
+
expect(icon).toBeInTheDocument();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("<Badge /> with pill style", () => {
|
|
115
|
+
beforeEach(() => {
|
|
116
|
+
render(
|
|
117
|
+
<Badge
|
|
118
|
+
type="href"
|
|
119
|
+
to="#"
|
|
120
|
+
color="blue"
|
|
121
|
+
borderColor="none"
|
|
122
|
+
hoverColor="blue"
|
|
123
|
+
testId="pill-badge"
|
|
124
|
+
tagStyle={false}
|
|
125
|
+
cursorPointer={false}
|
|
126
|
+
icon={<FontAwesomeIcon icon={faCheck} />}
|
|
127
|
+
mobileIcon={<FontAwesomeIcon icon={faCheck} />}
|
|
128
|
+
mobileIconLabel="Complete"
|
|
129
|
+
text={
|
|
130
|
+
<>
|
|
131
|
+
<Text
|
|
132
|
+
size="md"
|
|
133
|
+
color="primary"
|
|
134
|
+
fontFamily="serif"
|
|
135
|
+
text="Contact Us"
|
|
136
|
+
tag="h2"
|
|
137
|
+
additionalClasses="pl-2 pb-0 font-bold"
|
|
138
|
+
/>
|
|
139
|
+
<Text
|
|
140
|
+
size="md"
|
|
141
|
+
color="primary"
|
|
142
|
+
fontFamily="serif"
|
|
143
|
+
text="1-800-800-8000"
|
|
144
|
+
tag="p"
|
|
145
|
+
additionalClasses="pl-2 pt-0"
|
|
146
|
+
/>
|
|
147
|
+
</>
|
|
148
|
+
}
|
|
149
|
+
image={
|
|
150
|
+
<Image
|
|
151
|
+
src="../../../assets/contact-image.png"
|
|
152
|
+
alt=""
|
|
153
|
+
background={false}
|
|
154
|
+
additionalClasses="flex justify-center w-12 h-12 max-md:hidden"
|
|
155
|
+
/>
|
|
156
|
+
}
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("renders badge with pill style", () => {
|
|
162
|
+
const pill = screen.getByTestId("pill-badge");
|
|
163
|
+
expect(pill).toBeInTheDocument();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("has correct text", () => {
|
|
167
|
+
expect(screen.getByTestId("badge-text")).toHaveTextContent("Contact Us");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("has correct text", () => {
|
|
171
|
+
expect(screen.getByTestId("badge-text")).toHaveTextContent(
|
|
172
|
+
"1-800-800-8000"
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("has correct background color", () => {
|
|
177
|
+
const pill = screen.getByTestId("pill-badge");
|
|
178
|
+
expect(pill).toHaveClass("bg-blue-200");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("has correct image", () => {
|
|
182
|
+
const pillImage = screen.getByTestId("image");
|
|
183
|
+
expect(pillImage).toBeInTheDocument();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Link } from "react-router-dom";
|
|
3
|
+
import { BadgeTypes } from "./Badge.types";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
getHoverClasses,
|
|
7
|
+
getIconClasses,
|
|
8
|
+
getColorClassNames,
|
|
9
|
+
getBadgeClasses,
|
|
10
|
+
getPillStyleClasses,
|
|
11
|
+
getBadgeSizeClasses,
|
|
12
|
+
getTagClasses,
|
|
13
|
+
} from "./badgeClassNames";
|
|
14
|
+
|
|
15
|
+
const Badge: React.FC<BadgeTypes> = ({
|
|
16
|
+
onClick,
|
|
17
|
+
color = "blue",
|
|
18
|
+
badgeSize,
|
|
19
|
+
cursorPointer = true,
|
|
20
|
+
type = "span",
|
|
21
|
+
to,
|
|
22
|
+
href,
|
|
23
|
+
testId,
|
|
24
|
+
hoverColor = "blue",
|
|
25
|
+
borderColor,
|
|
26
|
+
fontColor = "black",
|
|
27
|
+
hasMobileStyle,
|
|
28
|
+
mobileIcon,
|
|
29
|
+
mobileIconLabel,
|
|
30
|
+
additionalClasses,
|
|
31
|
+
icon,
|
|
32
|
+
iconOrder = "first",
|
|
33
|
+
image,
|
|
34
|
+
tagStyle,
|
|
35
|
+
tagStyleIconColor,
|
|
36
|
+
text,
|
|
37
|
+
}) => {
|
|
38
|
+
let badgeColorClasses = getColorClassNames(color, borderColor, fontColor);
|
|
39
|
+
let badgeSizeClasses = getBadgeSizeClasses(badgeSize);
|
|
40
|
+
let hoverClasses = getHoverClasses(hoverColor, cursorPointer);
|
|
41
|
+
let iconClasses = getIconClasses(iconOrder, tagStyle, tagStyleIconColor);
|
|
42
|
+
|
|
43
|
+
let badgeClasses = getBadgeClasses({
|
|
44
|
+
badgeColorClasses,
|
|
45
|
+
hoverClasses,
|
|
46
|
+
badgeSizeClasses,
|
|
47
|
+
additionalClasses,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
let pillClasses = getPillStyleClasses({
|
|
51
|
+
badgeColorClasses,
|
|
52
|
+
hoverClasses,
|
|
53
|
+
additionalClasses,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
let tagClasses = getTagClasses({
|
|
57
|
+
badgeColorClasses,
|
|
58
|
+
hoverClasses,
|
|
59
|
+
additionalClasses,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const handleClick = (
|
|
63
|
+
e: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>
|
|
64
|
+
) => {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
onClick?.(e);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const baseProps = {
|
|
70
|
+
className: image
|
|
71
|
+
? pillClasses.trim()
|
|
72
|
+
: tagStyle
|
|
73
|
+
? tagClasses.trim()
|
|
74
|
+
: badgeClasses.trim(),
|
|
75
|
+
onClick: handleClick,
|
|
76
|
+
type: type,
|
|
77
|
+
"data-testid": testId,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
switch (type) {
|
|
81
|
+
case "href":
|
|
82
|
+
return (
|
|
83
|
+
<a {...baseProps} href={href}>
|
|
84
|
+
{renderContent()}
|
|
85
|
+
</a>
|
|
86
|
+
);
|
|
87
|
+
case "to":
|
|
88
|
+
if (to) {
|
|
89
|
+
return (
|
|
90
|
+
<Link {...baseProps} to={to}>
|
|
91
|
+
{renderContent()}
|
|
92
|
+
</Link>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
case "span":
|
|
97
|
+
return <span {...baseProps}>{renderContent()}</span>;
|
|
98
|
+
default:
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function renderContent() {
|
|
103
|
+
return (
|
|
104
|
+
<>
|
|
105
|
+
{image && <span>{image}</span>}
|
|
106
|
+
{icon && (
|
|
107
|
+
<span
|
|
108
|
+
className={`${iconClasses} max-md:hidden`}
|
|
109
|
+
data-testid="badge-icon"
|
|
110
|
+
>
|
|
111
|
+
<>{icon}</>
|
|
112
|
+
</span>
|
|
113
|
+
)}
|
|
114
|
+
{mobileIcon && hasMobileStyle && (
|
|
115
|
+
<span
|
|
116
|
+
className={`${iconClasses} hidden max-md:flex max-md:p-0`}
|
|
117
|
+
data-testid="mobile-badge-icon"
|
|
118
|
+
aria-hidden="false"
|
|
119
|
+
aria-label={mobileIconLabel}
|
|
120
|
+
>
|
|
121
|
+
<>{mobileIcon}</>
|
|
122
|
+
</span>
|
|
123
|
+
)}
|
|
124
|
+
<div
|
|
125
|
+
className={` ${hasMobileStyle ? "max-md:hidden" : ""} ${
|
|
126
|
+
tagStyle ? "px-3" : ""
|
|
127
|
+
}`}
|
|
128
|
+
data-testid="badge-text"
|
|
129
|
+
>
|
|
130
|
+
{text}
|
|
131
|
+
</div>
|
|
132
|
+
</>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export default Badge;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { ElementType } from "react";
|
|
2
|
+
|
|
3
|
+
export interface BadgeTypes {
|
|
4
|
+
onClick?: (
|
|
5
|
+
e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>
|
|
6
|
+
) => void;
|
|
7
|
+
text?: React.ReactNode;
|
|
8
|
+
cursorPointer?: boolean;
|
|
9
|
+
type: "href" | "to" | "span";
|
|
10
|
+
badgeSize?: string | undefined;
|
|
11
|
+
image?: React.ReactNode;
|
|
12
|
+
color?: string | undefined;
|
|
13
|
+
fontColor?: string | undefined;
|
|
14
|
+
borderColor?: string | undefined;
|
|
15
|
+
to?: string;
|
|
16
|
+
href?: string;
|
|
17
|
+
hoverColor: string | undefined;
|
|
18
|
+
additionalClasses?: string;
|
|
19
|
+
hasMobileStyle?: boolean;
|
|
20
|
+
mobileIcon?: JSX.Element | Element | null;
|
|
21
|
+
mobileIconLabel?: string;
|
|
22
|
+
children?: React.ReactNode;
|
|
23
|
+
icon?: JSX.Element | Element | null;
|
|
24
|
+
iconOrder?: "first" | "last";
|
|
25
|
+
testId?: string;
|
|
26
|
+
tagStyle?: boolean;
|
|
27
|
+
tagStyleIconColor?: string;
|
|
28
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import classNames from "classNames";
|
|
2
|
+
|
|
3
|
+
export const getHoverClasses = (
|
|
4
|
+
hoverColor: string | undefined,
|
|
5
|
+
cursorPointer: boolean | undefined
|
|
6
|
+
) => {
|
|
7
|
+
return classNames(
|
|
8
|
+
{
|
|
9
|
+
"hover:bg-red-800 hover:text-white": hoverColor === "red",
|
|
10
|
+
"hover:bg-teal-800 hover:text-white": hoverColor === "green",
|
|
11
|
+
"hover:bg-blue-800 hover:text-white": hoverColor === "blue",
|
|
12
|
+
"hover:bg-orange-700 hover:text-white": hoverColor === "orange",
|
|
13
|
+
"hover:bg-purple-700 hover:text-white": hoverColor === "purple",
|
|
14
|
+
"hover:bg-slate-950 hover:text-white": hoverColor === "black",
|
|
15
|
+
|
|
16
|
+
"": hoverColor === "none",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"cursor-pointer": cursorPointer === true,
|
|
20
|
+
"": cursorPointer === false,
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const getIconClasses = (
|
|
26
|
+
iconOrder: string | undefined,
|
|
27
|
+
tagStyle: boolean | undefined,
|
|
28
|
+
tagStyleIconColor: string | undefined
|
|
29
|
+
) => {
|
|
30
|
+
return classNames({
|
|
31
|
+
"flex items-center order-first pr-2":
|
|
32
|
+
iconOrder === "first" && tagStyle === false,
|
|
33
|
+
"flex items-center order-last pl-2":
|
|
34
|
+
iconOrder === "last" && tagStyle === false,
|
|
35
|
+
"text-white bg-red-500 flex justify-center items-center w-8 h-8 rounded-full max-md:text-black max-md:bg-transparent":
|
|
36
|
+
tagStyle === true && tagStyleIconColor === "red",
|
|
37
|
+
"text-white bg-blue-600 flex justify-center items-center w-8 h-8 rounded-full max-md:text-black max-md:bg-transparent":
|
|
38
|
+
tagStyle === true && tagStyleIconColor === "blue",
|
|
39
|
+
"text-white bg-teal-700 flex justify-center items-center w-8 h-8 rounded-full max-md:text-black max-md:bg-transparent":
|
|
40
|
+
tagStyle === true && tagStyleIconColor === "green",
|
|
41
|
+
"text-white bg-orange-700 flex justify-center items-center w-8 h-8 rounded-full max-md:text-black max-md:bg-transparent":
|
|
42
|
+
tagStyle === true && tagStyleIconColor === "orange",
|
|
43
|
+
"text-white bg-purple-700 flex justify-center items-center w-8 h-8 rounded-full max-md:text-black max-md:bg-transparent":
|
|
44
|
+
tagStyle === true && tagStyleIconColor === "purple",
|
|
45
|
+
"text-white bg-slate-950 flex justify-center items-center w-8 h-8 rounded-full max-md:text-black max-md:bg-transparent":
|
|
46
|
+
tagStyle === true && tagStyleIconColor === "black",
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const getBadgeSizeClasses = (badgeSize: string | undefined) => {
|
|
51
|
+
return classNames({
|
|
52
|
+
"badge-sm px-4 py-2": badgeSize === "small",
|
|
53
|
+
"badge-md px-4 py-3": badgeSize === "medium",
|
|
54
|
+
"badge-lg px-6 py-3": badgeSize === "large",
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const getColorClassNames = (
|
|
59
|
+
color: string | undefined,
|
|
60
|
+
borderColor: string | undefined,
|
|
61
|
+
fontColor: string | undefined
|
|
62
|
+
) => {
|
|
63
|
+
return classNames(
|
|
64
|
+
{
|
|
65
|
+
"bg-blue-200": color === "blue",
|
|
66
|
+
"bg-red-200": color === "red",
|
|
67
|
+
"bg-teal-100": color === "green",
|
|
68
|
+
"bg-orange-200": color === "orange",
|
|
69
|
+
"bg-purple-200": color === "purple",
|
|
70
|
+
"bg-slate-950": color === "black",
|
|
71
|
+
"bg-white": color === "white",
|
|
72
|
+
"bg-transparent border-black": color === "clear",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"border-blue-600": borderColor === "blue",
|
|
76
|
+
"border-teal-700": borderColor === "green",
|
|
77
|
+
"border-red-500": borderColor === "red",
|
|
78
|
+
"border-orange-500": color === "orange",
|
|
79
|
+
"border-slate-950": borderColor === "black",
|
|
80
|
+
"border-purple-500": color === "purple",
|
|
81
|
+
"border-transparent": borderColor === "none",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"text-white": fontColor === "white" && color !== "clear",
|
|
85
|
+
"text-black": fontColor === "black",
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
interface BadgeClassProps {
|
|
91
|
+
badgeColorClasses: string;
|
|
92
|
+
hoverClasses: string;
|
|
93
|
+
additionalClasses?: string;
|
|
94
|
+
badgeSizeClasses?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
interface PillStyleClassProps {
|
|
98
|
+
badgeColorClasses: string;
|
|
99
|
+
hoverClasses: string;
|
|
100
|
+
additionalClasses?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface TagProps {
|
|
104
|
+
badgeColorClasses: string;
|
|
105
|
+
hoverClasses: string;
|
|
106
|
+
additionalClasses?: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const getBadgeClasses = ({
|
|
110
|
+
badgeColorClasses,
|
|
111
|
+
hoverClasses,
|
|
112
|
+
additionalClasses,
|
|
113
|
+
badgeSizeClasses,
|
|
114
|
+
}: BadgeClassProps) => {
|
|
115
|
+
return classNames(
|
|
116
|
+
"badge border-2 rounded-full flex justify-center items-center",
|
|
117
|
+
badgeColorClasses,
|
|
118
|
+
hoverClasses,
|
|
119
|
+
additionalClasses,
|
|
120
|
+
badgeSizeClasses
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const getPillStyleClasses = ({
|
|
125
|
+
badgeColorClasses,
|
|
126
|
+
hoverClasses,
|
|
127
|
+
additionalClasses,
|
|
128
|
+
hasMobileStyle,
|
|
129
|
+
}: PillStyleClassProps & { hasMobileStyle?: boolean }) => {
|
|
130
|
+
return classNames(
|
|
131
|
+
"flex justify-center items-center w-full border-2 p-2 rounded-full",
|
|
132
|
+
hasMobileStyle ? "max-md:w-12 max-md:h-12 max-md:p-4" : "",
|
|
133
|
+
badgeColorClasses,
|
|
134
|
+
hoverClasses,
|
|
135
|
+
additionalClasses
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const getTagClasses = ({
|
|
140
|
+
badgeColorClasses,
|
|
141
|
+
hoverClasses,
|
|
142
|
+
additionalClasses,
|
|
143
|
+
hasMobileStyle,
|
|
144
|
+
}: TagProps & { hasMobileStyle?: boolean }) => {
|
|
145
|
+
return classNames(
|
|
146
|
+
"flex justify-between items-center w-fit border-2 rounded-full",
|
|
147
|
+
hasMobileStyle ? "max-md:w-12 max-md:h-6 max-md:p-2" : "",
|
|
148
|
+
badgeColorClasses,
|
|
149
|
+
hoverClasses,
|
|
150
|
+
additionalClasses
|
|
151
|
+
);
|
|
152
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Meta, StoryFn } from "@storybook/react";
|
|
2
|
+
import Card from "./Card";
|
|
3
|
+
import type { CardTypes } from ".";
|
|
4
|
+
import {
|
|
5
|
+
DUMMYPRODUCTDATA,
|
|
6
|
+
DUMMYCOMPASSPRODUCTDATA,
|
|
7
|
+
} from "./DUMMYPRODUCTDATA.json";
|
|
8
|
+
import HorizontalCardTemplate from "./templates/HorizontalCardTemplate";
|
|
9
|
+
import VerticalCardTemplate from "./templates/VerticalCardTemplate";
|
|
10
|
+
import CompassCardTemplate from "./templates/CompassCardTemplate";
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
title: "Components/Card",
|
|
14
|
+
component: Card,
|
|
15
|
+
argTypes: {
|
|
16
|
+
cardBorderRadius: {
|
|
17
|
+
control: "select",
|
|
18
|
+
options: ["cornered", "semiRounded", "rounded"],
|
|
19
|
+
description: "The border radius of the card.",
|
|
20
|
+
},
|
|
21
|
+
cardBackgroundColor: {
|
|
22
|
+
control: "select",
|
|
23
|
+
options: ["light blue", "light green", "gray", "white"],
|
|
24
|
+
description: "The background color of the card.",
|
|
25
|
+
},
|
|
26
|
+
cardBorderColor: {
|
|
27
|
+
control: "select",
|
|
28
|
+
options: ["blue", "green", "black", "none"],
|
|
29
|
+
description: "The color of the card border.",
|
|
30
|
+
},
|
|
31
|
+
cardBoxShadow: {
|
|
32
|
+
control: "boolean",
|
|
33
|
+
description: "Whether the card has box shadow or not.",
|
|
34
|
+
},
|
|
35
|
+
children: {
|
|
36
|
+
control: {
|
|
37
|
+
type: "none",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
containerClasses: {
|
|
41
|
+
control: {
|
|
42
|
+
type: "none",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
key: {
|
|
46
|
+
control: {
|
|
47
|
+
type: "none",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
tags: ["autodocs"],
|
|
52
|
+
parameters: {
|
|
53
|
+
layout: "centered",
|
|
54
|
+
},
|
|
55
|
+
} as Meta;
|
|
56
|
+
|
|
57
|
+
const Template: StoryFn<CardTypes> = (args) => <Card {...args} />;
|
|
58
|
+
|
|
59
|
+
export const Default = Template.bind({});
|
|
60
|
+
Default.args = {
|
|
61
|
+
containerClasses: "flex w-full max-sm:w-1/2 max-sm:flex-col",
|
|
62
|
+
key: DUMMYPRODUCTDATA[0].id,
|
|
63
|
+
cardBorderRadius: "semiRounded",
|
|
64
|
+
cardBorderColor: "blue",
|
|
65
|
+
cardBackgroundColor: "light blue",
|
|
66
|
+
cardBoxShadow: false,
|
|
67
|
+
children: <HorizontalCardTemplate data={DUMMYPRODUCTDATA[0]} />,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const VerticalCard = Template.bind({});
|
|
71
|
+
VerticalCard.args = {
|
|
72
|
+
containerClasses: "w-1/2 max-sm:w-1/2overflow-hidden rounded-md",
|
|
73
|
+
key: DUMMYPRODUCTDATA[0].id,
|
|
74
|
+
cardBorderRadius: "semiRounded",
|
|
75
|
+
cardBorderColor: "green",
|
|
76
|
+
cardBackgroundColor: "light green",
|
|
77
|
+
cardBoxShadow: true,
|
|
78
|
+
children: <VerticalCardTemplate data={DUMMYPRODUCTDATA[1]} />,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const CompassCard = Template.bind({});
|
|
82
|
+
CompassCard.args = {
|
|
83
|
+
containerClasses:
|
|
84
|
+
"w-1/2 max-sm:w-1/2 overflow-hidden rounded-md transition ease-in-out delay-150 hover:-translate-y-1 hover:scale-110 duration-300",
|
|
85
|
+
key: DUMMYCOMPASSPRODUCTDATA[0].id,
|
|
86
|
+
cardBorderRadius: "cornered",
|
|
87
|
+
cardBorderColor: "green",
|
|
88
|
+
cardBackgroundColor: "green",
|
|
89
|
+
cardBoxShadow: true,
|
|
90
|
+
children: <CompassCardTemplate data={DUMMYCOMPASSPRODUCTDATA[0]} />,
|
|
91
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, beforeEach, test } from "vitest";
|
|
3
|
+
import Card from "./Card";
|
|
4
|
+
import { DUMMYCARDTESTDATA } from "./DUMMYPRODUCTDATA.json";
|
|
5
|
+
import CompassCardTemplate from "./templates/CompassCardTemplate";
|
|
6
|
+
|
|
7
|
+
describe("<Card />", () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
render(
|
|
10
|
+
<Card
|
|
11
|
+
key={DUMMYCARDTESTDATA[0].id}
|
|
12
|
+
cardBorderRadius="cornered"
|
|
13
|
+
cardBorderColor="green"
|
|
14
|
+
cardBackgroundColor="none"
|
|
15
|
+
cardBoxShadow={true}
|
|
16
|
+
containerClasses="w-1/2 max-sm:w-1/2"
|
|
17
|
+
children={<CompassCardTemplate data={DUMMYCARDTESTDATA[0]} />}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("renders card", () => {
|
|
23
|
+
const card = screen.getByTestId("card-container");
|
|
24
|
+
expect(card).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("renders correct card text", () => {
|
|
28
|
+
const card = screen.getByTestId("card-container");
|
|
29
|
+
expect(card).toHaveTextContent(
|
|
30
|
+
"Compass Sales Lenovo TP X13 Yoga G3 Laptop"
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("renders correct card image", () => {
|
|
35
|
+
const card = screen.getByTestId("image");
|
|
36
|
+
expect(card).toHaveAttribute("src", "./assets/compass-card-image.png");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("renders correct card background color for image", () => {
|
|
40
|
+
const card = screen.getByTestId("card-image-container");
|
|
41
|
+
expect(card).toHaveClass("bg-teal-500");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("renders correct card border color", () => {
|
|
45
|
+
const card = screen.getByTestId("card-container");
|
|
46
|
+
expect(card).toHaveClass("border-teal-500");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("renders correct card background color for text", () => {
|
|
50
|
+
const card = screen.getByTestId("card-text-container");
|
|
51
|
+
expect(card).toHaveClass("bg-slate-50");
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { CardTypes } from "./Card.types";
|
|
3
|
+
import { getCardStyleClasses } from "./cardClassNames";
|
|
4
|
+
|
|
5
|
+
const Card: React.FC<CardTypes> = ({
|
|
6
|
+
children,
|
|
7
|
+
containerClasses,
|
|
8
|
+
cardBackgroundColor,
|
|
9
|
+
cardBorderColor,
|
|
10
|
+
cardBorderRadius,
|
|
11
|
+
cardBoxShadow,
|
|
12
|
+
}) => {
|
|
13
|
+
let cardStyleClasses = getCardStyleClasses(
|
|
14
|
+
cardBorderRadius,
|
|
15
|
+
cardBorderColor,
|
|
16
|
+
cardBackgroundColor,
|
|
17
|
+
cardBoxShadow
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
className={`${containerClasses} ${cardStyleClasses}`}
|
|
23
|
+
data-testid="card-container"
|
|
24
|
+
>
|
|
25
|
+
{children}
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default Card;
|