Skip to content

Commit 853eb1e

Browse files
authored
✨ feat: 리스트 페이지의 캐러셀 및 카드 구현, + variable.scss 폰트 속성 추가
✨ feat: 리스트 페이지의 캐러셀 및 카드 구현, + variable.scss 폰트 속성 추가
2 parents 7ca0611 + 1160437 commit 853eb1e

15 files changed

Lines changed: 428 additions & 2 deletions

src/App.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import './assets/styles/base.scss';
22
import { Route, Routes } from 'react-router-dom';
33
import Header from './components/layout/Header/Header';
4-
import Home from './pages/Home/Home';
54
import RecipientList from './pages/RecipientList/RecipientList';
5+
import Home from './pages/Home/Home';
66
import CreateRecipient from './pages/CreateRecipient/CreateRecipient';
77
import Recipient from './pages/Recipient/Recipient';
88
import MessageForm from './pages/MessageForm/MessageForm';

src/api/getRecipients.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import api from './api';
2+
3+
export default async function getRecipients() {
4+
const res = await api.get('/13-5/recipients/');
5+
return res.data;
6+
}

src/assets/images/next.svg

Lines changed: 3 additions & 0 deletions
Loading

src/assets/styles/base.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,9 @@ a {
3535
button {
3636
cursor: pointer;
3737
}
38+
39+
h1,
40+
h2,
41+
h3 {
42+
all: unset;
43+
}

src/assets/styles/variables.scss

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,68 +62,96 @@ $font-weight-bold: 700;
6262
@mixin font-28-bold {
6363
font-size: $font-size-28;
6464
font-weight: $font-weight-bold;
65+
line-height: 4.2rem;
66+
letter-spacing: -0.01em;
6567
}
6668

6769
@mixin font-24-bold {
6870
font-size: $font-size-24;
6971
font-weight: $font-weight-bold;
72+
line-height: 3.6rem;
73+
letter-spacing: -0.01em;
7074
}
7175

7276
@mixin font-24-regular {
7377
font-size: $font-size-24;
7478
font-weight: $font-weight-regular;
79+
line-height: 3.6rem;
80+
letter-spacing: -0.01em;
7581
}
7682

7783
@mixin font-20-bold {
7884
font-size: $font-size-20;
7985
font-weight: $font-weight-bold;
86+
line-height: 3rem;
87+
letter-spacing: -0.01em;
8088
}
8189
@mixin font-20-regular {
8290
font-size: $font-size-20;
8391
font-weight: $font-weight-regular;
92+
line-height: 3rem;
93+
letter-spacing: -0.01em;
8494
}
8595

8696
@mixin font-18-bold {
8797
font-size: $font-size-18;
8898
font-weight: $font-weight-bold;
99+
line-height: 2.8rem;
100+
letter-spacing: -0.01em;
89101
}
90102

91103
@mixin font-18-regular {
92104
font-size: $font-size-18;
93105
font-weight: $font-weight-regular;
106+
line-height: 2.8rem;
107+
letter-spacing: -0.01em;
94108
}
95109

96110
@mixin font-16-bold {
97111
font-size: $font-size-16;
98112
font-weight: $font-weight-bold;
113+
line-height: 2.6rem;
114+
letter-spacing: -0.01em;
99115
}
100116

101117
@mixin font-16-regular {
102118
font-size: $font-size-16;
103119
font-weight: $font-weight-regular;
120+
line-height: 2.6rem;
121+
letter-spacing: -0.01em;
104122
}
105123

106124
@mixin font-15-regular {
107125
font-size: $font-size-15;
108126
font-weight: $font-weight-regular;
127+
line-height: 2.2rem;
128+
letter-spacing: -0.01em;
109129
}
110130

111131
@mixin font-15-bold {
112132
font-size: $font-size-15;
113133
font-weight: $font-weight-bold;
134+
line-height: 2.2rem;
135+
letter-spacing: -0.01em;
114136
}
115137

116138
@mixin font-14-regular {
117139
font-size: $font-size-14;
118140
font-weight: $font-weight-regular;
141+
line-height: 2rem;
142+
letter-spacing: -0.005em;
119143
}
120144

121145
@mixin font-14-bold {
122146
font-size: $font-size-14;
123147
font-weight: $font-weight-bold;
148+
line-height: 2rem;
149+
letter-spacing: -0.005em;
124150
}
125151

126152
@mixin font-12-regular {
127153
font-size: $font-size-12;
128154
font-weight: $font-weight-regular;
155+
line-height: 1.8rem;
156+
letter-spacing: -0.005em;
129157
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { useState, useEffect } from 'react';
2+
import styles from './Carousel.module.scss';
3+
import RecipientCard from './RecipientCard';
4+
5+
export default function Carousel({ recipients }) {
6+
const [index, setIndex] = useState(0);
7+
const [offsetX, setOffsetX] = useState({}); // x좌표
8+
9+
// 작동과정: button onclick --> settingIndex() --> setIndex --> useEffect( setOffsetX(),[index] ): x좌표 상태 업데이트: 캐러셀 이동
10+
useEffect(() => {
11+
setOffsetX({
12+
transform: `translateX(-${index * 295}px)`,
13+
});
14+
}, [index]);
15+
16+
function settingIndex(direction) {
17+
if (direction === 'next') {
18+
setIndex((prev) => (prev + 1) % 8);
19+
} else if (direction === 'back') {
20+
setIndex((prev) => prev - 1);
21+
}
22+
}
23+
24+
//shadow.....
25+
function makeShadow() {
26+
const shadows = [];
27+
for (let i = 0; i < 7; i++) {
28+
shadows.push(<div key={i} className={styles.shadow}></div>);
29+
}
30+
return shadows;
31+
}
32+
33+
return (
34+
<div className={styles.carousel}>
35+
<div className={styles['carousel__cardset-wrapper']}>
36+
<div className={styles['carousel__cardset']} style={offsetX}>
37+
{recipients.map((it) => (
38+
<RecipientCard Recipient={it} key={it.id}></RecipientCard>
39+
))}
40+
</div>
41+
</div>
42+
{index > 0 && ( // 시작점 이후부터
43+
<button
44+
onClick={() => settingIndex('back')}
45+
className={`${styles['carousel__direction-button']} ${styles.back}`}
46+
></button>
47+
)}
48+
{index !== 4 && ( // 캐러셀 끝에 도달하기 전까지
49+
<button
50+
onClick={() => settingIndex('next')}
51+
className={`${styles['carousel__direction-button']}`}
52+
></button>
53+
)}
54+
</div>
55+
);
56+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
@use '../../assets/styles/variables.scss' as *;
2+
3+
//캐러셀 레이아웃
4+
.carousel {
5+
position: relative;
6+
}
7+
.carousel__cardset-wrapper {
8+
overflow: hidden;
9+
width: 1200px;
10+
padding: 16px 20px;
11+
}
12+
.carousel__cardset {
13+
display: flex;
14+
gap: 20px;
15+
transition: transform 0.5s ease-in-out;
16+
}
17+
18+
.carousel::before,
19+
.carousel::after {
20+
content: '';
21+
position: absolute;
22+
top: 0;
23+
width: 18px;
24+
height: 100%;
25+
z-index: 1;
26+
pointer-events: none;
27+
}
28+
.carousel::before {
29+
left: 0;
30+
background: linear-gradient(
31+
to right,
32+
rgba(255, 255, 255, 1) 0px,
33+
rgba(255, 255, 255, 0.8) 5px,
34+
transparent
35+
);
36+
}
37+
.carousel::after {
38+
right: 0;
39+
background: linear-gradient(
40+
to left,
41+
rgba(255, 255, 255, 1) 0px,
42+
rgba(255, 255, 255, 0.8) 5px,
43+
transparent
44+
);
45+
}
46+
47+
//캐러셀 버튼
48+
.carousel__direction-button {
49+
display: flex;
50+
justify-content: space-between;
51+
gap: 1120px;
52+
position: absolute;
53+
top: 50%;
54+
left: 100%;
55+
width: 40px;
56+
height: 40px;
57+
margin-left: -40px;
58+
z-index: 9999;
59+
border: solid 1px $gray-300;
60+
border-radius: 50%;
61+
background-color: rgba(255, 255, 255, 0.9);
62+
background-image: url(../../assets/images/next.svg);
63+
background-position: center;
64+
background-repeat: no-repeat;
65+
background-size: 40% 40%;
66+
transform: translateY(-50%);
67+
68+
-webkit-filter: drop-shadow(0px 4px 8px #00000014);
69+
filter: drop-shadow(0px 4px 8px #00000014);
70+
-webkit-backdrop-filter: blur(4px);
71+
backdrop-filter: blur(4px);
72+
73+
&.back {
74+
transform: scaleX(-1) translateY(-50%);
75+
left: 40px;
76+
}
77+
}
78+
79+
//<<태블릿, 모바일에서: 스크롤 스타일 None 적용하기>>
80+
// -ms-overflow-style: none;
81+
// .carousel__cardset::-webkit-scrollbar {
82+
// display: none;
83+
// }
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import styles from './RecentMessages.module.scss';
2+
3+
//카드 내부 요소 컴포넌트(동그라미 배열-최신메세지)
4+
export default function RecentMessages({ messages, count }) {
5+
return (
6+
<div className={styles['card__recent-messages']}>
7+
{messages.map((message) => (
8+
<img
9+
src={message.profileImageURL}
10+
className={styles.img}
11+
key={message.id}
12+
/>
13+
))}
14+
{count > 3 ? <div className={styles.count}>+{count - 3}</div> : null}
15+
</div>
16+
);
17+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
@use '../../assets/styles/variables.scss' as *;
2+
3+
.card__recent-messages {
4+
display: flex;
5+
margin: 12px 0 12px 13px;
6+
}
7+
.img {
8+
width: 28px;
9+
height: 28px;
10+
margin-left: -13px;
11+
border-radius: 30px;
12+
border: solid 1.5px white;
13+
}
14+
.count {
15+
@include font-12-regular;
16+
display: grid;
17+
place-items: center;
18+
width: 33px;
19+
height: 28px;
20+
margin-left: -13px;
21+
border-radius: 30px;
22+
background-color: white;
23+
color: $gray-500;
24+
line-height: 18px;
25+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import styles from './RecipientCard.module.scss';
2+
import RecentMessages from './recentMessages';
3+
import TopReactions from './TopReactions';
4+
5+
//캐러셀 내부 요소 - 카드 컴포넌트
6+
export default function RecipientCard({ Recipient }) {
7+
const {
8+
name,
9+
recentMessages,
10+
messageCount,
11+
topReactions,
12+
backgroundColor,
13+
backgroundImageURL,
14+
createdAt,
15+
} = Recipient;
16+
17+
return (
18+
<div
19+
className={`${styles.card} ${backgroundImageURL ? '' : styles[backgroundColor]}`}
20+
style={
21+
backgroundImageURL
22+
? {
23+
backgroundImage: `linear-gradient(#00000073, #00000073), url(${backgroundImageURL})`,
24+
color: 'white',
25+
}
26+
: {}
27+
}
28+
>
29+
<h3>{`To. ${name}`}</h3>
30+
<RecentMessages
31+
messages={recentMessages}
32+
count={messageCount}
33+
></RecentMessages>
34+
<div className={styles['writer-count']}>
35+
<span className={styles.count}>{messageCount}</span>
36+
<span>명이 작성했어요!</span>
37+
</div>
38+
<div className={styles['card__centerline']}></div>
39+
<TopReactions reactions={topReactions}></TopReactions>
40+
</div>
41+
);
42+
}

0 commit comments

Comments
 (0)