diff --git a/src/assets/notFound/404.svg b/src/assets/notFound/404.svg new file mode 100644 index 000000000..ddc01c0f0 --- /dev/null +++ b/src/assets/notFound/404.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/Layout/Container/FitContainer.tsx b/src/components/Layout/Container/FitContainer.tsx index 0b38f0f95..70e24663b 100644 --- a/src/components/Layout/Container/FitContainer.tsx +++ b/src/components/Layout/Container/FitContainer.tsx @@ -3,8 +3,8 @@ import { Outlet } from 'react-router-dom'; const FitContainer = () => { return ( -
-
+
+
diff --git a/src/components/Layout/Container/FullContainer.tsx b/src/components/Layout/Container/FullContainer.tsx index fa9fad4da..1a05b05e3 100644 --- a/src/components/Layout/Container/FullContainer.tsx +++ b/src/components/Layout/Container/FullContainer.tsx @@ -3,7 +3,7 @@ import { Outlet } from 'react-router-dom'; const FullContainer = () => { return ( -
+
); diff --git a/src/components/Layout/MainLayout.tsx b/src/components/Layout/MainLayout.tsx index a8050afba..b12bdd1c0 100644 --- a/src/components/Layout/MainLayout.tsx +++ b/src/components/Layout/MainLayout.tsx @@ -10,7 +10,7 @@ const MainLayout = () => { const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); return ( -
+
diff --git a/src/pages/NotFound/NotFound.tsx b/src/pages/NotFound/NotFound.tsx new file mode 100644 index 000000000..8c242ff48 --- /dev/null +++ b/src/pages/NotFound/NotFound.tsx @@ -0,0 +1,60 @@ +import React, { useReducer, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Container, Link, Stack, Typography } from '@mui/material'; +import Svg404Component from './SvgComponent/Svg404Component'; + +interface NotFoundProps { + from: string; +} + +const NotFound = ({ from }: NotFoundProps) => { + const [point, setPoint] = useState({ top: window.innerHeight / 2.5, left: window.innerWidth / 3 }); + const [torchTrigger, torchTriggerReducer] = useReducer((prev) => !prev, true); + + const navigate = useNavigate(); + + const handleKeyClick = () => { + torchTriggerReducer(); + }; + + return ( +
{ + setPoint({ top: e.pageY, left: e.pageX }); + }} + > + + + + {from} Not Found + + + + {`> THE ${from} YOU ARE LOOKING FOR MIGHT HAVE BEEN REMOVED, \n HAD ITS NAME CHANGED OR IS TEMPORARILY UNAVAILABLE.`} + + + {`> PLEASE TRY TO `} + {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} + navigate(-1)}> + [GO BACK] + + {` OR `} + + [RETURN TO THE HOMEPAGE] + + {` .`} + + {`> GOOD LUCK.`} + + + + + {torchTrigger &&
} + + +
+ ); +}; + +export default NotFound; diff --git a/src/pages/NotFound/SvgComponent/Svg404Component.tsx b/src/pages/NotFound/SvgComponent/Svg404Component.tsx new file mode 100644 index 000000000..d2cbbcfd6 --- /dev/null +++ b/src/pages/NotFound/SvgComponent/Svg404Component.tsx @@ -0,0 +1,80 @@ +import React from 'react'; + +interface Svg404Component { + point: { top: number; left: number }; + handleKeyClick: () => void; +} + +/* NOTE src/assets/notFound/404.svg에서 추가적인 이벤트 처리한 컴포넌트 */ +const Svg404Component = ({ point, handleKeyClick }: Svg404Component) => { + return ( + + + + + + window.innerWidth * (3 / 4) ? 157 + point.left / (window.innerWidth / 4) : 159} + cy={41 + point.top / (window.innerHeight / 4)} + rx="3.5" + ry="4" + fill="#131316" + /> + + window.innerWidth * (3 / 4) ? 183 + point.left / (window.innerWidth / 4) : 185} + cy={41 + point.top / (window.innerHeight / 4)} + rx="3.5" + ry="4" + fill="#131316" + /> + + + + + + + + + + + + + + + + ); +}; + +export default Svg404Component; diff --git a/src/pages/Profile/Profile.tsx b/src/pages/Profile/Profile.tsx index c6a5f1838..3702f6967 100644 --- a/src/pages/Profile/Profile.tsx +++ b/src/pages/Profile/Profile.tsx @@ -26,7 +26,7 @@ const Profile = () => { const [tab, setTab] = useState(0); return ( -
+
diff --git a/src/pages/SignUp/SignUp.tsx b/src/pages/SignUp/SignUp.tsx index 5dbbd7755..ad36540ec 100644 --- a/src/pages/SignUp/SignUp.tsx +++ b/src/pages/SignUp/SignUp.tsx @@ -24,7 +24,7 @@ const SignUp = () => { }; return ( - + diff --git a/src/pages/board/BoardList/BoardList.tsx b/src/pages/board/BoardList/BoardList.tsx index 46c20eac1..6a4d775e7 100644 --- a/src/pages/board/BoardList/BoardList.tsx +++ b/src/pages/board/BoardList/BoardList.tsx @@ -10,6 +10,7 @@ import { useGetNoticePostListQuery, useGetPostListQuery } from '@api/postApi'; import usePagination from '@hooks/usePagination'; import tableViewState from '@recoil/view.recoil'; import { categoryNameToId } from '@utils/converter'; +import NotFound from '@pages/NotFound/NotFound'; import OutlinedButton from '@components/Button/OutlinedButton'; import TableViewSwitchButton from '@components/Table/Button/TableViewSwitchButton'; import GridTable from '@components/Table/GridTable'; @@ -49,7 +50,7 @@ const BoardList = () => { const categoryId = categoryName ? categoryNameToId(categoryName) : null; if (!categoryId) { - return null; + return ; } const navigate = useNavigate(); diff --git a/src/pages/board/BoardView/BoardView.tsx b/src/pages/board/BoardView/BoardView.tsx index ff61f526d..cbd5ac042 100644 --- a/src/pages/board/BoardView/BoardView.tsx +++ b/src/pages/board/BoardView/BoardView.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from 'react'; import { useLocation, useParams } from 'react-router-dom'; import { useGetEachPostQuery } from '@api/postApi'; +import NotFound from '@pages/NotFound/NotFound'; import SecretPostModal from './Modal/SecretPostModal'; import AdjacentPostNavSection from './Section/AdjacentPostNavSection'; import BannerSection from './Section/BannerSection'; @@ -19,7 +20,7 @@ const BoardView = () => { const [secretPostModalOpen, setSecretPostModalOpen] = useState(false); const [password, setPassword] = useState(); - const { data: postInfo, isSuccess } = useGetEachPostQuery(postId, isSecret, password); + const { data: postInfo, isSuccess, isError } = useGetEachPostQuery(postId, isSecret, password); useEffect(() => { if (!isSuccess) return; @@ -33,6 +34,10 @@ const BoardView = () => { setSecretPostModalOpen(true); }, [isSecret]); + if (isError) { + return ; + } + return (
{postInfo && ( diff --git a/src/pages/login/Login.tsx b/src/pages/login/Login.tsx index 9f7c32b79..821d93b63 100644 --- a/src/pages/login/Login.tsx +++ b/src/pages/login/Login.tsx @@ -29,7 +29,7 @@ const Login = () => { }; return ( - + diff --git a/src/pages/login/SearchAccount.tsx b/src/pages/login/SearchAccount.tsx index 1725258ee..0fa8cff1a 100644 --- a/src/pages/login/SearchAccount.tsx +++ b/src/pages/login/SearchAccount.tsx @@ -19,7 +19,7 @@ const SignUp = () => { setCurrentStep(newTab); }; return ( -
+
diff --git a/src/router/useMainRouter.tsx b/src/router/useMainRouter.tsx index 8a225310e..af5430d35 100644 --- a/src/router/useMainRouter.tsx +++ b/src/router/useMainRouter.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { useRoutes } from 'react-router-dom'; import Game from '@pages/Game/Game'; import Library from '@pages/Library/Library'; +import NotFound from '@pages/NotFound/NotFound'; import Profile from '@pages/Profile/Profile'; import SignUp from '@pages/SignUp/SignUp'; import Study from '@pages/Study/Study'; @@ -35,6 +36,10 @@ const useMainRouter = () => index: true, element: , }, + { + path: '*', + element: , + }, { path: 'signUp', element: , diff --git a/src/tailwind.css b/src/tailwind.css index fc936deff..75d83641d 100644 --- a/src/tailwind.css +++ b/src/tailwind.css @@ -19,3 +19,8 @@ color: #fff; } } + +.torch { + @apply fixed mb-0 ml-[-250px] mr-0 mt-[-250px] h-[500px] w-[500px] rounded-[50%] opacity-100 shadow-[0_0_0_9999em_#000000f7] after:block after:h-full after:w-full after:rounded-[50%] after:shadow-[inset_0_0_40px_2px_#000,0_0_20px_4px_rgba(13,13,10,0.2)] after:content-['']; + background: rgba(0, 0, 0, 0.3); +} diff --git a/tailwind.config.js b/tailwind.config.js index f7c815858..a59598de0 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -36,6 +36,28 @@ module.exports = { backgroundImage: { galaxy: "url('/public/img/background_galaxy.png')", }, + keyframes: { + typing: { + '0%': { + width: '0%', + visibility: 'hidden', + }, + '100%': { + width: '100%', + }, + }, + blink: { + '50%': { + borderColor: 'transparent', + }, + '100%': { + borderColor: 'white', + }, + }, + }, + animation: { + typing: 'typing 2s steps(25), blink', + }, }, }, plugins: [],