Skip to content

Commit e6acf1e

Browse files
authored
Merge pull request #165 from prgrms-web-devcourse-final-project/refactor/164-AnimatedLayout
[refactor] AnimatedLayout 컴포넌트화
2 parents 2f63d48 + 94bedcc commit e6acf1e

File tree

2 files changed

+86
-75
lines changed

2 files changed

+86
-75
lines changed

src/App.tsx

Lines changed: 32 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ import YouTubeAudioPlayer from './components/YouTubeAudioPlayer';
2323

2424
// TODO: 테스트용 나중에 지우기
2525
import TestLoginModal from '@/components/testLogin/TestLoginModal';
26-
import { AnimatePresence, motion } from 'framer-motion';
27-
import { twMerge } from 'tailwind-merge';
26+
2827
import { useSheetStore } from './store/sheetStore';
28+
import AnimatedLayout from '@/layouts/AnimatedLayout';
2929

3030
function App() {
3131
const location = useLocation();
@@ -50,86 +50,43 @@ function App() {
5050
}); // 앱이 처음 실행될 때 API 로드
5151
}, []);
5252

53-
const getAnimation = () => {
54-
// location.pathname 등으로 분기하여 애니메이션 설정 반환
55-
if (
56-
location.pathname === '/signup' ||
57-
location.pathname === '/post' ||
58-
location.pathname === '/mypage/edit' ||
59-
location.pathname === '/mypage/blocklist' ||
60-
location.pathname.includes('user')
61-
) {
62-
return {
63-
initial: { x: '100%' },
64-
animate: { x: 0 },
65-
exit: { x: '100%' },
66-
transition: { duration: 0.3 },
67-
style: { zIndex: 1 },
68-
};
69-
} else {
70-
// 기본 애니메이션 설정
71-
return {
72-
initial: { opacity: 0 },
73-
animate: { opacity: 1 },
74-
exit: { opacity: 0 },
75-
transition: { duration: 0.3 },
76-
};
77-
}
78-
};
79-
8053
return (
8154
<>
8255
{/* 테스트용 나중에 지우기 */}
8356
<TestLoginModal />
84-
<AnimatePresence mode="sync">
85-
<motion.div
86-
key={location.pathname}
87-
{...getAnimation()}
88-
className={twMerge('absolute left-1/2 -translate-x-1/2 w-full max-w-[600px] z-10')}
89-
>
90-
<Routes location={location}>
91-
<Route path="/" element={<Layout />}>
92-
<Route
93-
index
94-
element={isAuthenticated ? <Navigate to="/home" replace /> : <Landing />}
95-
/>
57+
<AnimatedLayout>
58+
<Routes location={location}>
59+
<Route path="/" element={<Layout />}>
60+
<Route
61+
index
62+
element={isAuthenticated ? <Navigate to="/home" replace /> : <Landing />}
63+
/>
9664

97-
<Route
98-
path="/login"
99-
element={isAuthenticated ? <Navigate to="/home" replace /> : <Login />}
100-
/>
101-
<Route
102-
path="/signup"
103-
element={isAuthenticated ? <Navigate to="/home" replace /> : <SignUp />}
104-
/>
65+
<Route
66+
path="/login"
67+
element={isAuthenticated ? <Navigate to="/home" replace /> : <Login />}
68+
/>
69+
<Route
70+
path="/signup"
71+
element={isAuthenticated ? <Navigate to="/home" replace /> : <SignUp />}
72+
/>
10573

106-
{/* test용 */}
107-
{/* PrivateRoute 적용 */}
108-
<Route element={<PrivateRoute />}>
109-
<Route path="/home" element={<Home />} />
110-
<Route path="/chat" element={<Chat />} />
111-
<Route path="/post" element={<Post />} />
112-
<Route path="/post/:postId/edit" element={<Post />} />
113-
<Route path="/chatroom" element={<ChatRoom />} />
114-
<Route path="/mypage" element={<UserProfile isMyPage={true} />} />
115-
<Route path="/mypage/edit" element={<EditProfile />} />
116-
<Route path="/mypage/blocklist" element={<BlockList />} />
117-
<Route path="/user/:userId" element={<UserProfile isMyPage={false} />} />
118-
</Route>
119-
<Route path="*" element={<NotFound />} />
74+
{/* PrivateRoute 적용 */}
75+
<Route element={<PrivateRoute />}>
76+
<Route path="/home" element={<Home />} />
77+
<Route path="/chat" element={<Chat />} />
78+
<Route path="/post" element={<Post />} />
79+
<Route path="/post/:postId/edit" element={<Post />} />
80+
<Route path="/chatroom" element={<ChatRoom />} />
81+
<Route path="/mypage" element={<UserProfile isMyPage={true} />} />
82+
<Route path="/mypage/edit" element={<EditProfile />} />
83+
<Route path="/mypage/blocklist" element={<BlockList />} />
84+
<Route path="/user/:userId" element={<UserProfile isMyPage={false} />} />
12085
</Route>
121-
</Routes>
122-
</motion.div>
123-
</AnimatePresence>
124-
{/* 양옆에 배경을 만드는 Grid 컨테이너 */}
125-
<div className="absolute top-0 left-0 right-0 bottom-0 grid grid-cols-[1fr_auto_1fr]">
126-
{/* 왼쪽 배경 */}
127-
<div className="w-full h-full bg-white z-50"></div>
128-
{/* 실제 내용이 들어가는 부분 */}
129-
<div className="relative w-[600px]"></div>
130-
{/* 오른쪽 배경 */}
131-
<div className="w-full h-full bg-white z-50"></div>
132-
</div>
86+
<Route path="*" element={<NotFound />} />
87+
</Route>
88+
</Routes>
89+
</AnimatedLayout>
13390
<Modal />
13491
{isChatLoadingSheetOpen && <ChatConnectLoadingSheet />}
13592
<YouTubeAudioPlayer playerId="1" />

src/layouts/AnimatedLayout.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { AnimatePresence, motion } from 'framer-motion';
2+
import { twMerge } from 'tailwind-merge';
3+
4+
function AnimatedLayout({ children }: { children: React.ReactNode }) {
5+
const getAnimation = () => {
6+
// location.pathname 등으로 분기하여 애니메이션 설정 반환
7+
if (
8+
location.pathname === '/signup' ||
9+
location.pathname === '/post' ||
10+
location.pathname === '/mypage/edit' ||
11+
location.pathname === '/mypage/blocklist' ||
12+
location.pathname.includes('user')
13+
) {
14+
return {
15+
initial: { x: '100%' },
16+
animate: { x: 0 },
17+
exit: { x: '100%' },
18+
transition: { duration: 0.3 },
19+
style: { zIndex: 1 },
20+
};
21+
} else {
22+
// 기본 애니메이션 설정
23+
return {
24+
initial: { opacity: 0 },
25+
animate: { opacity: 1 },
26+
exit: { opacity: 0 },
27+
transition: { duration: 0.3 },
28+
};
29+
}
30+
};
31+
return (
32+
<>
33+
<AnimatePresence mode="sync">
34+
<motion.div
35+
key={location.pathname}
36+
{...getAnimation()}
37+
className={twMerge('absolute left-1/2 -translate-x-1/2 w-full max-w-[600px] z-10')}
38+
>
39+
{children}
40+
</motion.div>
41+
</AnimatePresence>
42+
{/* 양옆에 배경을 만드는 Grid 컨테이너 */}
43+
<div className="absolute top-0 left-0 right-0 bottom-0 grid grid-cols-[1fr_auto_1fr]">
44+
{/* 왼쪽 배경 */}
45+
<div className="w-full h-full bg-white z-50"></div>
46+
{/* 실제 내용이 들어가는 부분 */}
47+
<div className="relative w-[600px]"></div>
48+
{/* 오른쪽 배경 */}
49+
<div className="w-full h-full bg-white z-50"></div>
50+
</div>
51+
</>
52+
);
53+
}
54+
export default AnimatedLayout;

0 commit comments

Comments
 (0)