diff --git a/src/components/common/RoundButton/RoundButton.tsx b/src/components/common/RoundButton/RoundButton.tsx index 74206f36..3aadf54c 100644 --- a/src/components/common/RoundButton/RoundButton.tsx +++ b/src/components/common/RoundButton/RoundButton.tsx @@ -1,15 +1,14 @@ import { DetailedHTMLProps, HTMLAttributes, ReactElement } from 'react'; -import * as S from './RoundButton.style'; +import * as S from './style'; interface ButtonProps extends DetailedHTMLProps, HTMLButtonElement> { children: string | ReactElement; - isReverse?: boolean; } -function RoundButton({ children, isReverse = false, ...props }: ButtonProps) { +function RoundButton({ children, ...props }: ButtonProps) { return ( - + {children} ); diff --git a/src/components/common/RoundButton/RoundButton.style.tsx b/src/components/common/RoundButton/style.ts similarity index 64% rename from src/components/common/RoundButton/RoundButton.style.tsx rename to src/components/common/RoundButton/style.ts index 78dca264..49ef193f 100644 --- a/src/components/common/RoundButton/RoundButton.style.tsx +++ b/src/components/common/RoundButton/style.ts @@ -1,23 +1,24 @@ import styled from '@emotion/styled'; import { colors } from '@sopt-makers/colors'; -interface StyleProps { - isReverse?: boolean; -} - -export const Root = styled.button` +export const Root = styled.button` display: flex; align-items: center; - height: 50px; - padding: 10px 30px; + height: 60px; + padding: 12px 28px; border-radius: 99px; background: ${colors.gray10}; color: ${colors.gray950}; - font-size: 24px; + font-size: 22px; font-weight: 600; line-height: 150%; /* 36px */ letter-spacing: -0.48px; cursor: pointer; + + @media (max-width: 428px) { + padding: 8px 22px; + font-size: 18px; + } `; diff --git a/src/pages/404.tsx b/src/pages/404.tsx index 74e72c06..978c9273 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,49 +1,3 @@ -import styled from '@emotion/styled'; -import { colors } from '@sopt-makers/colors'; -import { useRouter } from 'next/router'; -import { Header } from '@src/components'; -import RoundButton from '@src/components/common/RoundButton'; +import { Page404 } from '@src/views/ErrorPage'; -function Wrong() { - const router = useRouter(); - - const handleButtonClick = () => { - router.push('/'); - }; - - return ( - <> -
- - 잘못된 경로예요 - - 홈으로 가기 - - - - ); -} - -export default Wrong; - -const Styled = { - Root: styled.section` - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 48px; - - width: 100%; - height: 100vh; - - & span { - color: ${colors.gray10}; - - font-size: 48px; - font-weight: 600; - line-height: 150%; /* 72px */ - letter-spacing: -0.96px; - } - `, -}; +export default Page404; diff --git a/src/pages/500.tsx b/src/pages/500.tsx new file mode 100644 index 00000000..1f58c6e7 --- /dev/null +++ b/src/pages/500.tsx @@ -0,0 +1,3 @@ +import { Page500 } from '@src/views/ErrorPage'; + +export default Page500; diff --git a/src/views/ErrorPage/ErrorPage.tsx b/src/views/ErrorPage/ErrorPage.tsx new file mode 100644 index 00000000..86869e16 --- /dev/null +++ b/src/views/ErrorPage/ErrorPage.tsx @@ -0,0 +1,45 @@ +import { useRouter } from 'next/router'; +import { Header } from '@src/components'; +import RoundButton from '@src/components/common/RoundButton'; +import ErrorCode from './components/ErrorCode'; +import ERROR_BUTTON from './constants/errorButton'; +import ERROR_MESSAGE from './constants/errorMessage'; +import * as S from './styles'; + +interface ErrorPageProps { + code: 404 | 500; +} + +function ErrorPage({ code }: ErrorPageProps) { + const router = useRouter(); + const CODE_KEY: 'CODE404' | 'CODE500' = `CODE${code}`; + + const handleButtonClick = () => { + code === 404 ? router.push('/') : router.back(); + }; + + return ( + <> +
+ + + + {ERROR_MESSAGE[CODE_KEY]} + {ERROR_BUTTON[CODE_KEY]} + + {code === 500 && ( + + 문의하기 + + )} + + + ); +} + +export const Page404 = () => ; +export const Page500 = () => ; diff --git a/src/views/ErrorPage/assets/ic_404_back.svg b/src/views/ErrorPage/assets/ic_404_back.svg new file mode 100644 index 00000000..99acab14 --- /dev/null +++ b/src/views/ErrorPage/assets/ic_404_back.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/views/ErrorPage/assets/ic_404_front.svg b/src/views/ErrorPage/assets/ic_404_front.svg new file mode 100644 index 00000000..3970b338 --- /dev/null +++ b/src/views/ErrorPage/assets/ic_404_front.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/views/ErrorPage/assets/ic_404_ghost.svg b/src/views/ErrorPage/assets/ic_404_ghost.svg new file mode 100644 index 00000000..ccd241fe --- /dev/null +++ b/src/views/ErrorPage/assets/ic_404_ghost.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/views/ErrorPage/assets/ic_404_ghost_dark.svg b/src/views/ErrorPage/assets/ic_404_ghost_dark.svg new file mode 100644 index 00000000..bcecc7c4 --- /dev/null +++ b/src/views/ErrorPage/assets/ic_404_ghost_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/views/ErrorPage/assets/ic_500_back.svg b/src/views/ErrorPage/assets/ic_500_back.svg new file mode 100644 index 00000000..363002b9 --- /dev/null +++ b/src/views/ErrorPage/assets/ic_500_back.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/views/ErrorPage/assets/ic_500_cone.svg b/src/views/ErrorPage/assets/ic_500_cone.svg new file mode 100644 index 00000000..ae051e24 --- /dev/null +++ b/src/views/ErrorPage/assets/ic_500_cone.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/views/ErrorPage/assets/ic_500_cone_dark.svg b/src/views/ErrorPage/assets/ic_500_cone_dark.svg new file mode 100644 index 00000000..95744684 --- /dev/null +++ b/src/views/ErrorPage/assets/ic_500_cone_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/views/ErrorPage/assets/ic_500_front.svg b/src/views/ErrorPage/assets/ic_500_front.svg new file mode 100644 index 00000000..389a120a --- /dev/null +++ b/src/views/ErrorPage/assets/ic_500_front.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/views/ErrorPage/assets/index.ts b/src/views/ErrorPage/assets/index.ts new file mode 100644 index 00000000..1d6ac8cc --- /dev/null +++ b/src/views/ErrorPage/assets/index.ts @@ -0,0 +1,10 @@ +import { ReactComponent as Ic404Front } from './ic_404_front.svg'; +import { ReactComponent as Ic404Back } from './ic_404_back.svg'; +import { ReactComponent as Ic404Ghost } from './ic_404_ghost.svg'; +import { ReactComponent as Ic404GhostDark } from './ic_404_ghost_dark.svg'; +import { ReactComponent as Ic500Front } from './ic_500_front.svg'; +import { ReactComponent as Ic500Back } from './ic_500_back.svg'; +import { ReactComponent as Ic500Cone } from './ic_500_cone.svg'; +import { ReactComponent as Ic500ConeDark } from './ic_500_cone_dark.svg'; + +export { Ic404Front, Ic404Back, Ic404Ghost, Ic404GhostDark, Ic500Cone, Ic500Back, Ic500Front, Ic500ConeDark }; diff --git a/src/views/ErrorPage/components/ErrorCode.style.ts b/src/views/ErrorPage/components/ErrorCode.style.ts new file mode 100644 index 00000000..ace7ce23 --- /dev/null +++ b/src/views/ErrorPage/components/ErrorCode.style.ts @@ -0,0 +1,16 @@ +import styled from '@emotion/styled'; +import { motion } from 'framer-motion'; + +export const ErrorCode = styled(motion.div)` + display: flex; + align-items: center; + gap: 6px; + + position: relative; +`; +export const ErrorIcon = styled(motion.div)` + display: flex; + justify-content: center; + position: absolute; + width: 100%; +`; diff --git a/src/views/ErrorPage/components/ErrorCode.tsx b/src/views/ErrorPage/components/ErrorCode.tsx new file mode 100644 index 00000000..bef01070 --- /dev/null +++ b/src/views/ErrorPage/components/ErrorCode.tsx @@ -0,0 +1,77 @@ +import { useIsMobile } from '@src/hooks/useDevice'; +import { + Ic404Back, + Ic404Front, + Ic404Ghost, + Ic404GhostDark, + Ic500Back, + Ic500Cone, + Ic500ConeDark, + Ic500Front, +} from '../assets'; +import * as S from './ErrorCode.style'; + +interface ErrorCodeProps { + code: 404 | 500; +} +export default function ErrorCode({ code }: ErrorCodeProps) { + const isMobile = useIsMobile('428px'); + const SIZE = { + height: 92, + icon: 150, + }; + + const codeVariant = { + initial: { gap: '6px' }, + whileHover: { gap: '159px' }, + }; + + const iconVariant = { + initial: { opacity: 0 }, + whileHover: { opacity: 1 }, + }; + + const animationProps = { + initial: 'initial', + whileHover: 'whileHover', + transition: { duration: 0.3 }, + }; + + return ( + + {code === 404 ? ( + <> + {!isMobile && ( + <> + + + + )} + {isMobile ? ( + + ) : ( + + + + )} + + ) : ( + <> + {!isMobile && ( + <> + + + + )} + {isMobile ? ( + + ) : ( + + + + )} + + )} + + ); +} diff --git a/src/views/ErrorPage/constants/errorButton.ts b/src/views/ErrorPage/constants/errorButton.ts new file mode 100644 index 00000000..d4621b84 --- /dev/null +++ b/src/views/ErrorPage/constants/errorButton.ts @@ -0,0 +1,6 @@ +const ERROR_BUTTON = { + CODE404 : '홈으로 가기', + CODE500 : '이전 페이지로 가기', +}; + +export default ERROR_BUTTON; diff --git a/src/views/ErrorPage/constants/errorMessage.ts b/src/views/ErrorPage/constants/errorMessage.ts new file mode 100644 index 00000000..ff593514 --- /dev/null +++ b/src/views/ErrorPage/constants/errorMessage.ts @@ -0,0 +1,6 @@ +const ERROR_MESSAGE = { + CODE404 : '존재하지 않는 페이지예요', + CODE500 : '알 수 없는 오류가 발생했어요', +}; + +export default ERROR_MESSAGE; diff --git a/src/views/ErrorPage/index.tsx b/src/views/ErrorPage/index.tsx new file mode 100644 index 00000000..2242b588 --- /dev/null +++ b/src/views/ErrorPage/index.tsx @@ -0,0 +1,3 @@ +import { Page404, Page500 } from './ErrorPage'; + +export { Page404, Page500 }; diff --git a/src/views/ErrorPage/styles.ts b/src/views/ErrorPage/styles.ts new file mode 100644 index 00000000..e59197c8 --- /dev/null +++ b/src/views/ErrorPage/styles.ts @@ -0,0 +1,51 @@ +import styled from '@emotion/styled'; +import Link from 'next/link'; + +export const Root = styled.main` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + position: relative; + + width: 100%; + height: 100vh; + min-height: 400px; + padding-bottom: 20vh; + + overflow: scroll; +`; +export const TopSection = styled.section` + display: flex; + flex-direction: column; + align-items: center; + gap: 34px; + + width: 100%; +`; +export const ErrorText = styled.p` + color: #fcfcfc; + + font-size: calc(24px + 1vw); + font-weight: 600; + line-height: 150%; + letter-spacing: -0.96px; +`; +export const ContactLink = styled(Link)` + position: absolute; + bottom: 17vh; + + color: #fff; + font-size: 24px; + font-weight: 600; + line-height: 150%; /* 36px */ + letter-spacing: -0.48px; + text-decoration-line: underline; + + cursor: pointer; + + @media (max-width: 428px) { + font-size: 18px; + } +`; diff --git a/src/views/MainPage/MainPage.tsx b/src/views/MainPage/MainPage.tsx index 26244846..59678d24 100644 --- a/src/views/MainPage/MainPage.tsx +++ b/src/views/MainPage/MainPage.tsx @@ -4,17 +4,10 @@ import IntroSection from '@src/views/MainPage/components/IntroSection'; import Banner from './components/Banner'; import Introduce from './components/Introduce'; import ScrollInteractiveLogo from './components/ScrollInteractiveLogo'; -import TopBanner from './components/TopBanner'; -import usePost from './hooks/usePost'; -import useCheckTime from '../../hooks/useCheckTime'; function MainPage() { - const isValid = useCheckTime(); // 모집 시작 여부 - usePost(); // 방문자 증가 - return ( - {isValid && }