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; +}