diff --git a/src/components/Splash.tsx b/src/components/Splash.tsx
new file mode 100644
index 00000000..4dc73d74
--- /dev/null
+++ b/src/components/Splash.tsx
@@ -0,0 +1,93 @@
+import { useEffect, useState } from 'react';
+
+export default function Splash() {
+ const [fadeSvg, setFadeSvg] = useState(false);
+ const [fadeOut, setFadeOut] = useState(false);
+ const [hide, setHide] = useState(false);
+
+ useEffect(() => {
+ document.body.style.overflow = 'hidden';
+
+ const svgTimer = setTimeout(() => setFadeSvg(true), 1500); // SVG 먼저 페이드아웃
+ const splashTimer = setTimeout(() => setFadeOut(true), 2000); // 배경은 그다음
+ const hideTimer = setTimeout(() => {
+ setHide(true);
+ document.body.style.overflow = '';
+ }, 2500); // 전체 컴포넌트 제거
+
+ return () => {
+ clearTimeout(svgTimer);
+ clearTimeout(splashTimer);
+ clearTimeout(hideTimer);
+ document.body.style.overflow = '';
+ };
+ }, []);
+
+ if (hide) return null;
+
+ return (
+
+
+ {/* SVG 로고 */}
+
+
+
+ );
+}
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index d3faac62..2e49ffb4 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -1,6 +1,6 @@
import '@/styles/globals.css';
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import { HydrationBoundary, QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { SpeedInsights } from '@vercel/speed-insights/next';
@@ -12,6 +12,7 @@ import { Toaster } from 'sonner';
import ErrorBoundary from '@/components/common/ErrorBoundary';
import Gnb from '@/components/common/Gnb';
import { LoadingOverlay } from '@/components/common/LoadingOverlay';
+import Splash from '@/components/Splash';
import { useInitUser } from '@/hooks/useInitUser';
import type { AppProps } from 'next/app';
@@ -34,6 +35,15 @@ export default function App({ Component, pageProps }: AppProps) {
const isLanding = pathname === '/';
const is404 = pathname === '/404';
+ const [showSplash, setShowSplash] = useState(isLanding);
+
+ useEffect(() => {
+ if (isLanding) {
+ const timer = setTimeout(() => setShowSplash(false), 2500); // 2초 보여주기
+ return () => clearTimeout(timer);
+ }
+ }, [isLanding]);
+
return (
<>
@@ -51,6 +61,7 @@ export default function App({ Component, pageProps }: AppProps) {
},
}}
/>
+ {showSplash && }
{!hideHeader && }
diff --git a/src/styles/globals.css b/src/styles/globals.css
index 1cd90b0d..26ad5eed 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -180,3 +180,20 @@
font-weight: 400;
}
}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+.animate-fadeIn {
+ animation: fadeIn 0.8s ease-out forwards;
+}
+
+html {
+ scrollbar-gutter: stable;
+}