Skip to content

Commit 3b6a75e

Browse files
authored
Merge pull request #81 from codeit-maso/feature/Yun
🎨 style: edit 페이지 분리 / 애니메이션 추가 / 뒤로가기 버튼 추가 / 스켈레톤 ui 적용
2 parents 7328fe1 + 0fa90c6 commit 3b6a75e

File tree

9 files changed

+187
-28
lines changed

9 files changed

+187
-28
lines changed

src/App.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ export default function App() {
1515
<Route path="/" element={<Home />} />
1616
<Route path="/list" element={<RecipientList />} />
1717
<Route path="/post" element={<CreateRecipient />} />
18-
<Route path="/post/:id" element={<Recipient />} />
18+
<Route path="/post/:id" element={<Recipient showDelete={false} />} />
19+
<Route
20+
path="/post/:id/edit"
21+
element={<Recipient showDelete={true} />}
22+
/>
1923
<Route path="/post/:id/message" element={<MessageForm />} />
2024
</Routes>
2125
</>

src/assets/styles/base.scss

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,6 @@ html {
2727
font-size: 62.5%;
2828
}
2929

30-
a {
31-
color: inherit;
32-
text-decoration: none;
33-
}
34-
3530
button {
3631
cursor: pointer;
3732
}

src/components/Card/Card.jsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default function Card({
2424
empty = false,
2525
onDelete,
2626
onClick,
27+
showDelete,
2728
}) {
2829
const navigate = useNavigate();
2930
const sanitizedHTML = DOMPurify.sanitize(children);
@@ -41,11 +42,11 @@ export default function Card({
4142

4243
return (
4344
<article
44-
className={`${styles.card} ${empty ? styles['card--empty'] : ''}`}
45-
onClick={() => !empty && onClick?.(id)}
45+
className={`${styles.card} ${empty ? styles['card--empty'] : ''} ${showDelete ? styles['card--show'] : ''}`}
46+
onClick={() => (empty ? clickPost() : onClick?.(id))}
4647
>
4748
{empty ? (
48-
<div onClick={clickPost}>
49+
<div>
4950
<img src={plus} alt="추가하기" />
5051
</div>
5152
) : (
@@ -64,11 +65,13 @@ export default function Card({
6465
<Badge relation={relationship} />
6566
</div>
6667
</div>
67-
<div className={styles['card__delete-button']}>
68-
<button onClick={clickDelete}>
69-
<img src={deleteIcon} alt="쓰레기통 아이콘" />
70-
</button>
71-
</div>
68+
{showDelete && (
69+
<div className={styles['card__delete-button']}>
70+
<button onClick={clickDelete}>
71+
<img src={deleteIcon} alt="쓰레기통 아이콘" />
72+
</button>
73+
</div>
74+
)}
7275
</header>
7376
<div className={styles['card__body']}>
7477
<div className={styles['card__content']}>

src/components/Card/Card.module.scss

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.08);
1111
background: $white;
1212
gap: 16px;
13+
transition: transform 0.2s ease;
14+
cursor: pointer;
15+
16+
&:hover {
17+
transform: scale(0.95);
18+
}
1319

1420
&.card--empty {
1521
display: flex;
@@ -23,6 +29,10 @@
2329
}
2430
}
2531

32+
&.card--show {
33+
cursor: default;
34+
}
35+
2636
&__header {
2737
display: flex;
2838
gap: 14px;
@@ -91,6 +101,11 @@
91101
word-break: break-word;
92102
@include font-18-regular;
93103
color: $gray-600;
104+
ul,
105+
li,
106+
a {
107+
all: revert;
108+
}
94109
}
95110
}
96111

@@ -100,6 +115,18 @@
100115
}
101116
}
102117

118+
@keyframes click-pop {
119+
0% {
120+
transform: scale(1);
121+
}
122+
50% {
123+
transform: scale(1.03); // 살짝 커졌다가
124+
}
125+
100% {
126+
transform: scale(1); // 다시 원래대로
127+
}
128+
}
129+
103130
@media (max-width: 1248px) {
104131
.card {
105132
width: inherit;

src/components/layout/Header/Header.module.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
border: 1px solid $gray-300;
2727
border-radius: 6px;
2828
white-space: nowrap;
29+
color: inherit;
30+
text-decoration: none;
2931
}
3032

3133
@media (min-width: 361px) and (max-width: 768px) {

src/pages/CreateRecipient/CreateRecipient.jsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ export default function CreateRecipient() {
1616
const [selectedType, setSelectedType] = useState('color');
1717
const [selectedColor, setSelectedColor] = useState('beige');
1818
const [selectedImage, setSelectedImage] = useState(-1);
19+
const [imageLoading, setImageLoading] = useState([]);
1920
const navigate = useNavigate();
2021

2122
useEffect(() => {
2223
const fetch = async () => {
2324
try {
2425
const result = await getBackgroundImage();
2526
setData(result);
27+
setImageLoading(new Array(result.length).fill(true));
2628
} catch (error) {
2729
console.error('데이터 로딩 실패:', error);
2830
}
@@ -52,6 +54,14 @@ export default function CreateRecipient() {
5254
setSelectedImage(index);
5355
}
5456

57+
function handleImageLoad(index) {
58+
setImageLoading((prev) => {
59+
const updated = [...prev];
60+
updated[index] = false;
61+
return updated;
62+
});
63+
}
64+
5565
async function handleButtonClick() {
5666
try {
5767
const id = await postRecipient({
@@ -113,6 +123,7 @@ export default function CreateRecipient() {
113123
이미지
114124
</button>
115125
</div>
126+
116127
{selectedType === 'color' && (
117128
<ul className={styles['create-page__color-list']}>
118129
{colors.map((color) => (
@@ -149,10 +160,17 @@ export default function CreateRecipient() {
149160
}`}
150161
onClick={() => handleImageClick(index)}
151162
>
163+
{imageLoading[index] && (
164+
<div className={styles['create-page__skeleton']} />
165+
)}
152166
<img
153167
src={url}
154168
alt={`배경이미지${index + 1}`}
155-
className={styles['create-page__background-img']}
169+
className={`
170+
${styles['create-page__background-img']}
171+
${imageLoading[index] ? styles['create-page__background-img--hidden'] : ''}
172+
`}
173+
onLoad={() => handleImageLoad(index)}
156174
/>
157175
{selectedImage === index && (
158176
<img
@@ -176,7 +194,6 @@ export default function CreateRecipient() {
176194
생성하기
177195
</Button>
178196
</div>
179-
180197
</div>
181198
);
182199
}

src/pages/CreateRecipient/CreateRecipient.module.scss

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@
6464
list-style: none;
6565
flex-shrink: 0;
6666
cursor: pointer;
67+
transition:
68+
transform 0.3s ease,
69+
box-shadow 0.3s ease;
70+
71+
&:hover {
72+
transform: scale(1.05);
73+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
74+
}
6775
}
6876

6977
.create-page__color--selected {
@@ -111,6 +119,14 @@
111119
overflow: hidden;
112120
flex-shrink: 0;
113121
cursor: pointer;
122+
transition:
123+
transform 0.3s ease,
124+
box-shadow 0.3s ease;
125+
126+
&:hover {
127+
transform: scale(1.05);
128+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
129+
}
114130

115131
.create-page__background-img {
116132
position: absolute;
@@ -137,6 +153,30 @@
137153
}
138154
}
139155

156+
.create-page__skeleton {
157+
width: 100%;
158+
height: 100%;
159+
background-color: #e0e0e0;
160+
animation: skeleton-loading 1.2s infinite ease-in-out;
161+
border-radius: 8px;
162+
}
163+
164+
@keyframes skeleton-loading {
165+
0% {
166+
background-color: #e0e0e0;
167+
}
168+
50% {
169+
background-color: #f0f0f0;
170+
}
171+
100% {
172+
background-color: #e0e0e0;
173+
}
174+
}
175+
176+
.create-page__background-img--hidden {
177+
display: none;
178+
}
179+
140180
@media (max-width: 1024px) {
141181
.create-page {
142182
position: relative;

src/pages/Recipient/Recipient.jsx

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Button from '../../components/common/Button';
1010
import Modal from '../../components/Modal/Modal.jsx';
1111
import styles from './Recipient.module.scss';
1212

13-
export default function Recipient() {
13+
export default function Recipient({ showDelete }) {
1414
const { id } = useParams();
1515
const [postData, setPostData] = useState(null);
1616
const [messages, setMessages] = useState([]);
@@ -107,6 +107,14 @@ export default function Recipient() {
107107
}
108108
}
109109

110+
function handleGoBack() {
111+
navigate(-1);
112+
}
113+
114+
function handleEditClick(id) {
115+
navigate(`/post/${id}/edit`);
116+
}
117+
110118
function handleOpenModal(id) {
111119
setSelectedCardId(id);
112120
}
@@ -126,24 +134,36 @@ export default function Recipient() {
126134
<>
127135
<HeaderService recipient={postData} />
128136
<div
129-
className={`${styles['post-container']} ${!postData.backgroundImageURL ? styles[`background--${postData.backgroundColor}`] : ''}`}
137+
className={`${styles['post-container']} ${!postData.backgroundImageURL ? styles[`background--${postData.backgroundColor}`] : ''} ${showDelete ? styles[`background--gray`] : ''}`}
130138
style={
131-
postData.backgroundImageURL
139+
postData.backgroundImageURL && !showDelete
132140
? { backgroundImage: `url(${postData.backgroundImageURL})` }
133141
: {}
134142
}
135143
>
136144
<div className={styles['button-container']}>
137-
<Button
138-
className={styles['delete-button']}
139-
type="delete"
140-
onClick={() => handleDeleteRecipient(id)}
141-
>
142-
삭제하기
143-
</Button>
145+
<div className={styles['back-button-wrapper']}>
146+
<button className={styles['back-button']} onClick={handleGoBack}>
147+
← 뒤로가기
148+
</button>
149+
</div>
150+
151+
<div className={styles['action-button-wrapper']}>
152+
{showDelete ? (
153+
<Button type="delete" onClick={() => handleDeleteRecipient(id)}>
154+
페이지 삭제하기
155+
</Button>
156+
) : (
157+
<Button type="delete" onClick={() => handleEditClick(id)}>
158+
편집하기
159+
</Button>
160+
)}
161+
</div>
144162
</div>
145163
<div className={styles['card-container']}>
146-
<Card recipientId={id} empty={true} />
164+
{!showDelete && (
165+
<Card recipientId={id} empty={true} showDelete={showDelete} />
166+
)}
147167
{messages.map((msg) => (
148168
<Card
149169
key={msg.id}
@@ -156,6 +176,7 @@ export default function Recipient() {
156176
onDelete={handleDeleteMessage}
157177
onClick={() => handleOpenModal(msg.id)}
158178
font={msg.font}
179+
showDelete={showDelete}
159180
>
160181
{msg.content}
161182
</Card>

0 commit comments

Comments
 (0)