Skip to content

Commit f6487de

Browse files
authored
Merge pull request #68 from SOPT-all/feat/related-component/#54
[feat/#54] 주목할 만한 작품 컴포넌트 구현
2 parents cb91d39 + 4ace4a5 commit f6487de

File tree

3 files changed

+237
-0
lines changed

3 files changed

+237
-0
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import { typographyVars } from "@/shared/styles/typography.css";
2+
import { style } from "@vanilla-extract/css";
3+
import { recipe } from "@vanilla-extract/recipes";
4+
import { color } from "@/shared/styles/tokens/color.css";
5+
import { components } from "@/shared/styles/layer.css";
6+
7+
export const section = style({
8+
"@layer": {
9+
[components]: {
10+
display: "flex",
11+
flexDirection: "column",
12+
padding: "0rem 1.6rem",
13+
},
14+
},
15+
});
16+
17+
export const headerText = recipe({
18+
base: {
19+
"@layer": {
20+
[components]: {
21+
textAlign: "left",
22+
},
23+
},
24+
},
25+
variants: {
26+
type: {
27+
title: {
28+
"@layer": {
29+
[components]: {
30+
...typographyVars.heading3,
31+
color: color.black[100],
32+
marginBottom: "0.4rem",
33+
},
34+
},
35+
},
36+
caption: {
37+
"@layer": {
38+
[components]: {
39+
...typographyVars.caption2,
40+
color: color.gray[100],
41+
marginBottom: "2rem",
42+
},
43+
},
44+
},
45+
},
46+
},
47+
defaultVariants: {
48+
type: "title",
49+
},
50+
});
51+
52+
export const scrollContainer = style({
53+
"@layer": {
54+
[components]: {
55+
display: "flex",
56+
columnGap: "0.8rem",
57+
overflowX: "auto",
58+
overflowY: "hidden",
59+
marginRight: "-1.6rem",
60+
paddingRight: "1.6rem",
61+
},
62+
},
63+
});
64+
65+
export const card = style({
66+
"@layer": {
67+
[components]: {
68+
display: "flex",
69+
flexDirection: "column",
70+
rowGap: "1.2rem",
71+
width: "12.8rem",
72+
flexShrink: 0,
73+
},
74+
},
75+
});
76+
77+
export const thumbnailWrapper = style({
78+
"@layer": {
79+
[components]: {
80+
borderRadius: "4px",
81+
overflow: "hidden",
82+
width: "100%",
83+
aspectRatio: "1 / 1",
84+
position: "relative",
85+
},
86+
},
87+
});
88+
89+
export const cardTitle = style({
90+
"@layer": {
91+
[components]: {
92+
...typographyVars.caption1,
93+
},
94+
},
95+
});
96+
97+
export const thumbnailImage = style({
98+
"@layer": {
99+
[components]: {
100+
width: "100%",
101+
height: "100%",
102+
objectFit: "cover",
103+
},
104+
},
105+
});
106+
107+
export const badge = recipe({
108+
base: {
109+
"@layer": {
110+
[components]: {
111+
position: "absolute",
112+
padding: "0.2rem 0.4rem",
113+
borderRadius: "4px",
114+
...typographyVars.caption2,
115+
},
116+
},
117+
},
118+
variants: {
119+
tone: {
120+
ad: {
121+
"@layer": {
122+
[components]: {
123+
backgroundColor: color.white[300],
124+
color: color.gray[100],
125+
},
126+
},
127+
},
128+
bundle: {
129+
"@layer": {
130+
[components]: {
131+
backgroundColor: color.brand[100],
132+
color: color.white[300],
133+
},
134+
},
135+
},
136+
},
137+
position: {
138+
topRight: {
139+
"@layer": {
140+
[components]: {
141+
top: "0.4rem",
142+
right: "0.4rem",
143+
},
144+
},
145+
},
146+
bottomLeft: {
147+
"@layer": {
148+
[components]: {
149+
bottom: "0.4rem",
150+
left: "0.4rem",
151+
},
152+
},
153+
},
154+
},
155+
},
156+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import ProductImage from "@/assets/img/product-01.png";
2+
3+
interface RelatedProductItem {
4+
id: number;
5+
title: string;
6+
imageUrl: string;
7+
isAd: boolean;
8+
isBundleShipping: boolean;
9+
}
10+
11+
export const relatedProducts: RelatedProductItem[] = [
12+
{
13+
id: 1,
14+
title: "[IDUS단독]음성을 전하는 카세트 앨범📻 음성 편지",
15+
imageUrl: ProductImage,
16+
isAd: true,
17+
isBundleShipping: false,
18+
},
19+
{
20+
id: 2,
21+
title: "[IDUS단독]음성을 전하는 카세트 앨범📻 음성 편지",
22+
imageUrl: ProductImage,
23+
isAd: false,
24+
isBundleShipping: true,
25+
},
26+
{
27+
id: 3,
28+
title: "[IDUS단독]음성을 전하는 카세트 앨범📻 음성 편지",
29+
imageUrl: ProductImage,
30+
isAd: false,
31+
isBundleShipping: false,
32+
},
33+
];
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import * as styles from "./related-product.css";
2+
import { relatedProducts } from "./related-product.mock";
3+
4+
export const RelatedProduct = () => {
5+
return (
6+
<section className={styles.section}>
7+
<h2 className={styles.headerText({ type: "title" })}>주목할 만한 작품</h2>
8+
<p className={styles.headerText({ type: "caption" })}>
9+
같은 작가의 작품은 묶음배송이 가능해요.
10+
</p>
11+
<div className={styles.scrollContainer}>
12+
{relatedProducts.map(
13+
({ id, title, imageUrl, isAd, isBundleShipping }) => (
14+
<article key={id} className={styles.card}>
15+
<div className={styles.thumbnailWrapper}>
16+
<img
17+
src={imageUrl}
18+
alt={title}
19+
className={styles.thumbnailImage}
20+
/>
21+
22+
{isAd && (
23+
<span
24+
className={styles.badge({
25+
tone: "ad",
26+
position: "topRight",
27+
})}>
28+
광고
29+
</span>
30+
)}
31+
{isBundleShipping && (
32+
<span
33+
className={styles.badge({
34+
tone: "bundle",
35+
position: "bottomLeft",
36+
})}>
37+
묶음배송
38+
</span>
39+
)}
40+
</div>
41+
<p className={styles.cardTitle}>{title}</p>
42+
</article>
43+
)
44+
)}
45+
</div>
46+
</section>
47+
);
48+
};

0 commit comments

Comments
 (0)