Skip to content

Commit fe0d235

Browse files
authored
Merge pull request #40 from DaleStudy/37
Icon 컴포넌트
2 parents 0f64b90 + 6e88817 commit fe0d235

File tree

17 files changed

+399
-9
lines changed

17 files changed

+399
-9
lines changed

bun.lock

Lines changed: 52 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"dependencies": {
1919
"axe-playwright": "^2.0.3",
2020
"chromatic": "^11.25.1",
21+
"lucide-react": "^0.474.0",
2122
"react": "^19.0.0",
2223
"react-dom": "^19.0.0"
2324
},
@@ -52,6 +53,7 @@
5253
"typescript": "^5.7.3",
5354
"typescript-eslint": "^8.22.0",
5455
"vite": "^6.0.11",
56+
"vite-plugin-svgr": "^4.3.0",
5557
"vitest": "^3.0.4"
5658
},
5759
"eslintConfig": {

src/assets/Discord.svg

Lines changed: 1 addition & 0 deletions
Loading

src/assets/GitHub.svg

Lines changed: 1 addition & 0 deletions
Loading

src/assets/LinkedIn.svg

Lines changed: 1 addition & 0 deletions
Loading

src/assets/Medium.svg

Lines changed: 1 addition & 0 deletions
Loading

src/assets/YouTube.svg

Lines changed: 1 addition & 0 deletions
Loading

src/assets/react.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import { vstack } from "../../../styled-system/patterns";
3+
import { Heading } from "../Heading/Heading";
4+
import { Text } from "../Text/Text";
5+
import { Icon } from "./Icon";
6+
7+
export default {
8+
component: Icon,
9+
parameters: {
10+
layout: "centered",
11+
},
12+
args: {
13+
name: "user",
14+
},
15+
} satisfies Meta<typeof Icon>;
16+
17+
export const Basic: StoryObj<typeof Icon> = {
18+
args: {
19+
tone: "accent",
20+
muted: true,
21+
size: "xl",
22+
},
23+
};
24+
25+
export const Sizes: StoryObj<typeof Icon> = {
26+
render: (args) => {
27+
return (
28+
<div className={vstack({ gap: "6" })}>
29+
<Icon {...args} size="xs" />
30+
<Icon {...args} size="sm" />
31+
<Icon {...args} size="md" />
32+
<Icon {...args} size="lg" />
33+
<Icon {...args} size="xl" />
34+
</div>
35+
);
36+
},
37+
argTypes: {
38+
size: {
39+
control: false,
40+
},
41+
},
42+
args: {
43+
tone: "accent",
44+
muted: true,
45+
},
46+
};
47+
48+
export const Tones: StoryObj<typeof Icon> = {
49+
render: (args) => {
50+
return (
51+
<div className={vstack({ gap: "6" })}>
52+
<Icon {...args} tone="neutral" />
53+
<Icon {...args} tone="accent" />
54+
<Icon {...args} tone="danger" />
55+
<Icon {...args} tone="warning" />
56+
</div>
57+
);
58+
},
59+
argTypes: {
60+
tone: {
61+
control: false,
62+
},
63+
},
64+
args: {
65+
muted: true,
66+
},
67+
};
68+
69+
export const Contrasts: StoryObj<typeof Icon> = {
70+
render: (args) => {
71+
return (
72+
<div className={vstack({ gap: "6" })}>
73+
<Text {...args} muted>
74+
낮은 <Icon name="moon" /> 명암비
75+
</Text>
76+
<Text {...args}>
77+
높은 <Icon name="sun" /> 명암비
78+
</Text>
79+
</div>
80+
);
81+
},
82+
argTypes: {
83+
name: {
84+
control: false,
85+
},
86+
muted: {
87+
control: false,
88+
},
89+
},
90+
};
91+
92+
export const WithHeading: StoryObj<typeof Icon> = {
93+
render: (args) => {
94+
return (
95+
<Heading level={2}>
96+
<Icon {...args} name="user" />
97+
프로필
98+
</Heading>
99+
);
100+
},
101+
argTypes: {
102+
name: {
103+
control: false,
104+
},
105+
},
106+
};

src/components/Icon/Icon.test.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { composeStories } from "@storybook/react";
2+
import { render } from "@testing-library/react";
3+
import { expect, test } from "vitest";
4+
import * as stories from "./Icon.stories";
5+
6+
const { Basic } = composeStories(stories);
7+
8+
test("renders an svg element", () => {
9+
const { container } = render(<Basic />);
10+
11+
expect(container.querySelector("svg")).toBeInTheDocument();
12+
});
13+
14+
test.each([
15+
["xs", "w_1em h_1em"],
16+
["sm", "w_1.25em h_1.25em"],
17+
["md", "w_1.5em h_1.5em"],
18+
["lg", "w_1.875em h_1.875em"],
19+
["xl", "w_2.25em h_2.25em"],
20+
] as const)('applies the correct class for size="%s"', (size, className) => {
21+
const { container } = render(<Basic size={size} />);
22+
23+
expect(container.querySelector("svg")).toHaveClass(className);
24+
});
25+
26+
test.each([
27+
["neutral", "c_text"],
28+
["accent", "c_text.accent"],
29+
["danger", "c_text.danger"],
30+
["warning", "c_text.warning"],
31+
] as const)('applies the correct class for tone="%s"', (tone, className) => {
32+
const { container } = render(<Basic tone={tone} muted={false} />);
33+
34+
expect(container.querySelector("svg")).toHaveClass(className);
35+
});
36+
37+
test.each([
38+
[false, "c_text"],
39+
[true, "c_text.muted"],
40+
] as const)("applies the correct class for muted={%s}", (muted, className) => {
41+
const { container } = render(<Basic tone="neutral" muted={muted} />);
42+
43+
expect(container.querySelector("svg")).toHaveClass(className);
44+
});

0 commit comments

Comments
 (0)