Skip to content

Commit b1858b4

Browse files
authored
Merge pull request #78 from geulDa/feat/#59/postcard-page-layout
✨Feat: postcard page layout
2 parents 55878cb + b57dc05 commit b1858b4

File tree

10 files changed

+191
-22
lines changed

10 files changed

+191
-22
lines changed

public/assets/card.png

94.5 KB
Loading

public/assets/card2.png

12.4 KB
Loading

src/pages/main/HiddenReward.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use client';
2-
import Image from 'next/image';
31
import { useRouter } from 'next/router';
42

53
const HiddenReward = () => {
@@ -13,7 +11,11 @@ const HiddenReward = () => {
1311
flex flex-col justify-center items-center text-center
1412
overflow-hidden
1513
'
16-
onClick={() => console.log('히든 리워드 클릭: 다음 페이지 이동')}
14+
onClick={() =>
15+
router.push({
16+
pathname: '/main/PostCard',
17+
})
18+
}
1719
>
1820
<h1 className=' text-black mb-[4.5rem] text-headline-lg-serif '>
1921
Congrats!

src/pages/main/Node.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { Header } from '@/shared/components';
2-
import AddressCopy from '@/shared/components/button/AddressCopy';
3-
import LocationCard from '@/shared/components/container/LocationCard';
1+
import { AddressCopy, Header, LocationCard } from '@/shared/components';
42
import { Icon } from '@/shared/icons';
53
import { cn } from '@/shared/lib';
64
import { getLocation } from '@/shared/utils/handleGetLocation';
@@ -10,7 +8,7 @@ import { useRouter } from 'next/router';
108
const Board = () => {
119
const router = useRouter();
1210
const { label } = router.query;
13-
const isStamp = true;
11+
const isStamp = false;
1412

1513
return (
1614
<div className='relative w-full h-[100vh] overflow-auto px-[2.4rem]'>
@@ -27,19 +25,25 @@ const Board = () => {
2725
width={354}
2826
height={436}
2927
className={cn(
30-
'w-full h-auto object-cover block rounded-[1.6rem] transition-all duration-300',
28+
'w-full h-auto object-cover block rounded-[16px] transition-all duration-300',
3129
!isStamp && 'blur-xs brightness-90',
3230
)}
3331
/>
3432

3533
<button
3634
className={cn('absolute bottom-0 right-0', isStamp && 'p-[2.5rem]')}
37-
onClick={() =>
38-
getLocation(
39-
(pos) => console.log('📍 현재 위치:', pos.coords),
40-
(err) => console.error('⚠️ 위치 에러:', err.message),
41-
//TODO : 리워드 페이지로 이동 , 위치 에러일경우 모달창
42-
)
35+
onClick={
36+
!isStamp
37+
? () => {
38+
getLocation(
39+
(pos) => console.log('📍 현재 위치:', pos.coords),
40+
(err) => console.error('⚠️ 위치 에러:', err.message),
41+
);
42+
router.push({
43+
pathname: '/main/HiddenReward',
44+
});
45+
}
46+
: undefined
4347
}
4448
>
4549
<Icon

src/pages/main/PostCard.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Icon } from '@/shared/icons';
2+
import { BottomNav, FlipCard, LocationCard } from '@/shared/components';
3+
import { handleSave, handleShare } from '@/shared/utils/postcardActions';
4+
5+
const PostCard = () => {
6+
const label = '가톨릭대'; // 임시
7+
8+
return (
9+
<div
10+
className='
11+
relative w-full h-[100vh] px-[2.4rem]
12+
bg-gradient-to-b from-pink-100 to-white
13+
flex flex-col justify-start items-center
14+
overflow-x-auto overflow-y-hidden mb-[7rem]
15+
'
16+
>
17+
<h1 className='text-headline-md-serif mt-[8rem] mb-[8rem] text-center'>
18+
{label}의 엽서 획득!
19+
</h1>
20+
21+
<FlipCard
22+
frontSrc='/assets/card.png'
23+
backSrc='/assets/card2.png'
24+
width={354}
25+
height={220}
26+
/>
27+
28+
{/* 아이콘 버튼 (저장 / 공유) */}
29+
<div className='w-full flex justify-end mb-[7rem]'>
30+
<button
31+
className='flex items-center justify-center w-[4.8rem] h-[4.8rem]'
32+
onClick={handleSave}
33+
>
34+
<Icon name='Save' color='gray-400' size={28} />
35+
</button>
36+
<button
37+
className='flex items-center justify-center w-[4.8rem] h-[4.8rem]'
38+
onClick={handleShare}
39+
>
40+
<Icon name='Export' color='gray-400' size={28} />
41+
</button>
42+
</div>
43+
44+
<LocationCard
45+
name={label}
46+
address='경기도 부천시 가톨릭대길 43'
47+
description='가톨릭대학교의 캠퍼스에서 얻을 수 있는 특별한 엽서입니다.'
48+
variant='gray'
49+
size='large'
50+
/>
51+
52+
<BottomNav />
53+
</div>
54+
);
55+
};
56+
57+
export default PostCard;

src/pages/main/index.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { cn } from '@/shared/lib';
2-
import StampBoard from './components/stampBoard/StampBoard';
3-
import { ControlBar } from '@/shared/components';
2+
import { BottomNav, ControlBar } from '@/shared/components';
43
import Image from 'next/image';
54
import { useRouter } from 'next/router';
6-
import { BottomNav } from '@/shared/components/tab/BottomNav';
5+
import StampBoard from '@/pages/main/components/stampBoard/StampBoard';
76

87
export default function MainPage() {
98
const router = useRouter();
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
'use client';
2+
import { useState } from 'react';
3+
import Image from 'next/image';
4+
5+
interface FlipCardProps {
6+
frontSrc: string;
7+
backSrc: string;
8+
width?: number;
9+
height?: number;
10+
}
11+
12+
const FlipCard = ({
13+
frontSrc,
14+
backSrc,
15+
width = 354,
16+
height = 220,
17+
}: FlipCardProps) => {
18+
const [isFlipped, setIsFlipped] = useState(false);
19+
20+
return (
21+
<div
22+
className='relative flex justify-center items-center cursor-pointer'
23+
style={{ width, height }}
24+
onClick={() => setIsFlipped((prev) => !prev)}
25+
>
26+
<div className={`flip-card ${isFlipped ? 'flipped' : ''}`}>
27+
<div className='flip-card-inner'>
28+
{/* 앞면 */}
29+
<div className='flip-card-front'>
30+
<Image
31+
src={frontSrc}
32+
alt='앞면'
33+
width={width}
34+
height={height}
35+
className='object-cover '
36+
/>
37+
</div>
38+
{/* 뒷면 */}
39+
<div className='flip-card-back'>
40+
<Image
41+
src={backSrc}
42+
alt='뒷면'
43+
width={width}
44+
height={height}
45+
className='object-cover'
46+
/>
47+
</div>
48+
</div>
49+
</div>
50+
</div>
51+
);
52+
};
53+
54+
export default FlipCard;

src/shared/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export { default as EventCard } from './container/EventCard';
99
export { default as AddressCopy } from './button/AddressCopy';
1010
export { default as CommonButton } from './button/CommonButton';
1111
export { BottomNav } from './tab/BottomNav';
12+
export { default as FlipCard } from './flipCard/FlipCard';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// 공유
2+
export const handleShare = () => {
3+
if (navigator.share) {
4+
navigator.share({
5+
title: '엽서 공유',
6+
text: '가톨릭대 엽서 🎴',
7+
url: window.location.href,
8+
});
9+
} else {
10+
alert('이 브라우저에서는 공유 기능을 지원하지 않습니다.');
11+
}
12+
};
13+
14+
// 저장
15+
export const handleSave = () => {
16+
const imageUrl = '/assets/Card.svg';
17+
const link = document.createElement('a');
18+
link.href = imageUrl;
19+
link.download = 'Card.svg';
20+
link.click();
21+
};

src/styles/globals.css

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,11 @@ html, body {
200200
@utility text-body-sm { font-size:1rem; line-height: 1.6rem; font-weight: 400; letter-spacing: 0.04em; font-family: var(--font-sans); }
201201

202202
/* JEN Serif */
203-
@utility text-display-serif { font-size:3.6rem; line-height: 4.6rem; font-weight: 400; letter-spacing: 0.6em; font-family: var(--font-serif); }
204-
@utility text-headline-lg-serif { font-size:3.2rem; line-height: 4rem; font-weight: 400; letter-spacing: 0.2em; font-family: var(--font-serif); }
205-
@utility text-headline-md-serif { font-size:2.4rem; line-height: 3.2rem; font-weight: 400; letter-spacing: 0.2em; font-family: var(--font-serif); }
206-
@utility text-headline-sm-serif { font-size:2rem; line-height: 2.4rem; font-weight: 400; letter-spacing: 1.2rem; font-family: var(--font-serif); }
207-
@utility text-label-serif { font-size:1.4rem; line-height: 2rem; font-weight: 400; letter-spacing: 0.4rem; font-family: var(--font-serif); }
203+
@utility text-display-serif { font-size:3.6rem; line-height: 4.6rem; font-weight: 400; letter-spacing: 0.06em; font-family: var(--font-serif); }
204+
@utility text-headline-lg-serif { font-size:3.2rem; line-height: 4rem; font-weight: 400; letter-spacing: 0.02em; font-family: var(--font-serif); }
205+
@utility text-headline-md-serif { font-size:2.4rem; line-height: 3.2rem; font-weight: 400; letter-spacing: 0.02em; font-family: var(--font-serif); }
206+
@utility text-headline-sm-serif { font-size:2rem; line-height: 2.4rem; font-weight: 400; letter-spacing: 0.12rem; font-family: var(--font-serif); }
207+
@utility text-label-serif { font-size:1.4rem; line-height: 2rem; font-weight: 400; letter-spacing: 0.04rem; font-family: var(--font-serif); }
208208

209209

210210
/* Layout */
@@ -221,3 +221,34 @@ html, body {
221221

222222
.no-scrollbar::-webkit-scrollbar { display: none; }
223223
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
224+
225+
.flip-card {
226+
perspective: 1000px;
227+
width: 354px;
228+
height: 220px;
229+
}
230+
231+
.flip-card-inner {
232+
position: relative;
233+
width: 100%;
234+
height: 100%;
235+
transition: transform 0.8s ease;
236+
transform-style: preserve-3d;
237+
}
238+
239+
.flip-card.flipped .flip-card-inner {
240+
transform: rotateY(180deg) ;
241+
}
242+
243+
.flip-card-front,
244+
.flip-card-back {
245+
position: absolute;
246+
width: 100%;
247+
height: 100%;
248+
backface-visibility: hidden;
249+
}
250+
251+
.flip-card-back {
252+
transform: rotateY(180deg);
253+
254+
}

0 commit comments

Comments
 (0)