diff --git a/client/Hooks/index.ts b/client/Hooks/index.ts index 717abb63..8e8c50a0 100644 --- a/client/Hooks/index.ts +++ b/client/Hooks/index.ts @@ -6,4 +6,4 @@ export { default as useRestoreSrollPos } from "./useRestoreScrollPos"; export { default as useScrollIntoElement } from "./useScrollIntoElement"; export { default as useVerticalScrollHandler } from "./useVerticalScrollHandler"; export { default as useInput } from "./useInput"; -export { default as useModals } from "./useModals"; +export { default as useOverlay } from "./useOverlay"; diff --git a/client/Hooks/useModals.ts b/client/Hooks/useModals.ts deleted file mode 100644 index 3214d6bb..00000000 --- a/client/Hooks/useModals.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { useModalDispatchContext } from "@contexts/modalContex"; - -const useModals = () => { - const { open, close } = useModalDispatchContext(); - - const openModal: typeof open = (Component, props) => { - open(Component, props); - }; - - const closeModal: typeof close = (Component) => { - close(Component); - }; - - return { - openModal, - closeModal, - }; -}; - -export default useModals; diff --git a/client/Hooks/useOverlay.ts b/client/Hooks/useOverlay.ts new file mode 100644 index 00000000..9231acb5 --- /dev/null +++ b/client/Hooks/useOverlay.ts @@ -0,0 +1,20 @@ +import { useOverlayDispatchContext } from "@contexts/overlayContex"; + +const useOverlay = () => { + const { open, close } = useOverlayDispatchContext(); + + const openOverlay: typeof open = (Component, props) => { + open(Component, props); + }; + + const closeOverlay: typeof close = (Component) => { + close(Component); + }; + + return { + openOverlay, + closeOverlay, + }; +}; + +export default useOverlay; diff --git a/client/app/layout.tsx b/client/app/layout.tsx index 5277d5ba..6f49268c 100644 --- a/client/app/layout.tsx +++ b/client/app/layout.tsx @@ -4,7 +4,7 @@ import "react-toastify/dist/ReactToastify.css"; import Header from "@components/Header"; import Providers from "@components/Providers"; -import { Modals } from "@components/shared/Modals"; +import Overlays from "@components/shared/Overlays"; import MyToastContainer from "@components/shared/MyToastContainer"; import { PropsWithChildren } from "react"; import ProgressBar from "@components/shared/ProgressBar"; @@ -31,7 +31,7 @@ const RootLayout = ({ children }: PropsWithChildren) => {
{children} - +
diff --git a/client/components/Header/AuthButton.tsx b/client/components/Header/AuthButton.tsx index c407232a..c9895e6c 100644 --- a/client/components/Header/AuthButton.tsx +++ b/client/components/Header/AuthButton.tsx @@ -3,15 +3,15 @@ import styles from "./styles.module.scss"; import { toast } from "react-toastify"; import { MESSAGE } from "@constants"; import { useLogOut } from "@hooks/query"; -import useModals from "@hooks/useModals"; -import { MODALS } from "@components/shared/Modals/Modals"; +import { useOverlay } from "@hooks"; +import { OVERLAYS } from "@components/shared/Overlays/Overlays"; interface AuthButtonProps { isLoggedIn: boolean; } const AuthButton = ({ isLoggedIn }: AuthButtonProps) => { - const { openModal } = useModals(); + const { openOverlay } = useOverlay(); const { mutate: logoutMutate } = useLogOut({ onSuccess: () => toast.success(MESSAGE.LOGOUT_SUCCESS), @@ -21,7 +21,7 @@ const AuthButton = ({ isLoggedIn }: AuthButtonProps) => { if (isLoggedIn) { logoutMutate(); } else { - openModal(MODALS.LOGIN); + openOverlay(OVERLAYS.AUTH_MODAL, { type: "LOGIN" }); } }; diff --git a/client/components/Header/MobileMenuToggleButton.tsx b/client/components/Header/MobileMenuToggleButton.tsx index 06bd8190..feccd61a 100644 --- a/client/components/Header/MobileMenuToggleButton.tsx +++ b/client/components/Header/MobileMenuToggleButton.tsx @@ -1,19 +1,21 @@ import React from "react"; import { HiMenu } from "react-icons/hi"; import styles from "./styles.module.scss"; -import MobileMenu from "./MobileMenu"; -import { useBooleanState } from "@hooks"; +import { useOverlay } from "@hooks"; +import { OVERLAYS } from "@components/shared/Overlays/Overlays"; const MobileMenuToggleButton = () => { - const [isOpen, , close, toggleState] = useBooleanState(false); + const { openOverlay } = useOverlay(); return ( - <> - - - + ); }; diff --git a/client/components/Header/styles.module.scss b/client/components/Header/styles.module.scss index f2d92f42..423dc174 100644 --- a/client/components/Header/styles.module.scss +++ b/client/components/Header/styles.module.scss @@ -154,55 +154,6 @@ } } -.MobileMenu { - gap: 32px; - background-color: var(--slight-layer2); - transition-duration: 500ms; - opacity: 0.95; - .Navigator { - display: flex; - flex-direction: column; - align-items: center; - gap: 2.5rem; - font-size: 25px; - font-weight: 700; - button { - border: none; - background: none; - font-size: 25px; - font-weight: 700; - color: var(--bg-element2); - } - } - - .current { - text-decoration-color: var(--primary1); - text-underline-offset: 8px; - text-decoration-line: underline; - text-decoration-thickness: 4px; - } - - .closeArea { - width: 100%; - height: 120px; - display: flex; - align-items: center; - justify-content: flex-end; - button { - border: none; - background: none; - width: 50px; - height: 50px; - margin-right: 5%; - svg { - width: 45px; - height: 45px; - fill: var(--bg-element2); - } - } - } -} - .themeSVG { animation-name: rotateAnimation; animation-duration: 0.5s; diff --git a/client/components/Providers.tsx b/client/components/Providers.tsx index e19d0106..9c3bcf40 100644 --- a/client/components/Providers.tsx +++ b/client/components/Providers.tsx @@ -3,7 +3,7 @@ import React, { PropsWithChildren, useState } from "react"; import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; -import { ModalProvider } from "@contexts/modalContex"; +import { OverlayProvider } from "@contexts/overlayContex"; import { ThemeProvider } from "@contexts/themeContext"; function Providers({ children }: PropsWithChildren) { @@ -12,7 +12,7 @@ function Providers({ children }: PropsWithChildren) { return ( - {children} + {children} diff --git a/client/components/post/TableOfContents/TOCButton.tsx b/client/components/post/TableOfContents/TOCButton.tsx index b159e8e8..89b33f5c 100644 --- a/client/components/post/TableOfContents/TOCButton.tsx +++ b/client/components/post/TableOfContents/TOCButton.tsx @@ -6,10 +6,10 @@ import HideByScrollDown from "@components/shared/HideByScrollDown"; const MARGIN_RIGHT_FOR_HIDE = "-50px"; const TOCButton = () => { - const [openModal, setOpenModal] = useState(false); + const [openOverlay, setopenOverlay] = useState(false); const handleClickButton = () => { - setOpenModal(true); + setopenOverlay(true); }; return ( @@ -24,7 +24,7 @@ const TOCButton = () => { > TOC - + ); }; diff --git a/client/components/postForm/SeriesSelector/SeriesCreateModalOpenButton.tsx b/client/components/postForm/SeriesSelector/SeriesCreateModalOpenButton.tsx index 6e335f16..c91cffac 100644 --- a/client/components/postForm/SeriesSelector/SeriesCreateModalOpenButton.tsx +++ b/client/components/postForm/SeriesSelector/SeriesCreateModalOpenButton.tsx @@ -1,20 +1,18 @@ -import { useModals } from "@hooks"; +import { useOverlay } from "@hooks"; import React from "react"; import styles from "./styles.module.scss"; -import { MODALS } from "@components/shared/Modals/Modals"; +import { OVERLAYS } from "@components/shared/Overlays/Overlays"; const SeriesCreateModalOpenButton = () => { - const { openModal } = useModals(); + const { openOverlay } = useOverlay(); return ( - <> - - + ); }; diff --git a/client/components/shared/ModalView/ModalView.tsx b/client/components/shared/ModalView/ModalView.tsx index 171258f1..75e0d8c3 100644 --- a/client/components/shared/ModalView/ModalView.tsx +++ b/client/components/shared/ModalView/ModalView.tsx @@ -1,16 +1,32 @@ import React, { type PropsWithChildren } from "react"; import styles from "./styles.module.scss"; import CloseIcon from "@components/Icon/close"; +import classNames from "classnames"; interface Props { title: string; + isClose?: boolean; onClose: () => void; } -const ModalView = ({ children, title, onClose }: PropsWithChildren) => { +const ModalView = ({ + children, + title, + onClose, + isClose, +}: PropsWithChildren) => { return (
-
-
+
+

{title}

- - - + ); }; -export default LoginModal; +export default LoginForm; diff --git a/client/components/shared/Modals/SignUpModal/SignUpModal.tsx b/client/components/shared/Overlays/AuthModal/SignUpForm.tsx similarity index 84% rename from client/components/shared/Modals/SignUpModal/SignUpModal.tsx rename to client/components/shared/Overlays/AuthModal/SignUpForm.tsx index 228190d0..1003e89d 100644 --- a/client/components/shared/Modals/SignUpModal/SignUpModal.tsx +++ b/client/components/shared/Overlays/AuthModal/SignUpForm.tsx @@ -1,18 +1,15 @@ import React, { FormEventHandler } from "react"; -import styles from "./styles.module.scss"; import { useInput } from "@hooks"; -import { StateUpdater } from "@Types/utils"; -import { SocialLoginArea } from "@components/shared/SocialLoginArea"; +import styles from "./styles.module.scss"; import { useSignUp } from "@hooks/query"; import { toast } from "react-toastify"; import { MESSAGE } from "@constants"; -import ModalView from "@components/shared/ModalView"; interface Props { onClose: () => void; } -const SignUpModal = ({ onClose }: Props) => { +const SignUpForm = ({ onClose }: Props) => { const [email, , onChangeEmail] = useInput(""); const [password, , onChangePassword] = useInput(""); const [passwordCheck, , onChangePasswordCheck] = useInput(""); @@ -39,7 +36,7 @@ const SignUpModal = ({ onClose }: Props) => { }; return ( - + <>
{ />
- -
+ ); }; -export default SignUpModal; +export default SignUpForm; diff --git a/client/components/shared/Overlays/AuthModal/index.ts b/client/components/shared/Overlays/AuthModal/index.ts new file mode 100644 index 00000000..c2802948 --- /dev/null +++ b/client/components/shared/Overlays/AuthModal/index.ts @@ -0,0 +1 @@ +export { default } from "./AuthModal"; diff --git a/client/components/shared/Modals/LoginModal/styles.module.scss b/client/components/shared/Overlays/AuthModal/styles.module.scss similarity index 79% rename from client/components/shared/Modals/LoginModal/styles.module.scss rename to client/components/shared/Overlays/AuthModal/styles.module.scss index cd328633..268aaf6f 100644 --- a/client/components/shared/Modals/LoginModal/styles.module.scss +++ b/client/components/shared/Overlays/AuthModal/styles.module.scss @@ -31,11 +31,3 @@ color: var(--primary1); } } - -.Overlay { - background-color: rgba(0, 0, 0, 0.6); - width: 100%; - height: 100%; - position: absolute; - cursor: pointer; -} diff --git a/client/components/Header/MobileMenu.tsx b/client/components/shared/Overlays/MobileMenu/MobileMenu.tsx similarity index 63% rename from client/components/Header/MobileMenu.tsx rename to client/components/shared/Overlays/MobileMenu/MobileMenu.tsx index 60ac9d8d..8af5362f 100644 --- a/client/components/Header/MobileMenu.tsx +++ b/client/components/shared/Overlays/MobileMenu/MobileMenu.tsx @@ -1,38 +1,48 @@ import { PAGE } from "@constants"; import Link from "next/link"; -import React from "react"; +import React, { useState } from "react"; import styles from "./styles.module.scss"; import { IoClose } from "react-icons/io5"; import { usePathname } from "next/navigation"; -import LeftSlideLayer from "@components/shared/LeftSlideLayer"; import FontAppliedElement from "@components/shared/FontAppliedElement"; import classnames from "classnames"; -import { useModals } from "@hooks"; -import { MODALS } from "@components/shared/Modals/Modals"; +import { useOverlay } from "@hooks"; +import { OVERLAYS } from "@components/shared/Overlays/Overlays"; interface Props { isOpen: boolean; - handleClose: () => void; + onClose: () => void; + onExit: (time: number) => void; } -const MobileMenu = ({ isOpen, handleClose }: Props) => { +const MobileMenu = ({ onClose, onExit }: Props) => { + const [isClose, setIsClose] = useState(false); const pathname = usePathname(); - const { openModal } = useModals(); + const { openOverlay } = useOverlay(); + + const closeWithAnimation = () => { + setIsClose(true); + onExit(500); + }; const handleClickLoginButton = () => { - handleClose(); - openModal(MODALS.LOGIN); + onClose(); + openOverlay(OVERLAYS.AUTH_MODAL, { type: "LOGIN" }); }; const handleClickSignUpButton = () => { - handleClose(); - openModal(MODALS.SIGNUP); + onClose(); + openOverlay(OVERLAYS.AUTH_MODAL, { type: "SIGN_UP" }); }; return ( - +
-
@@ -47,7 +57,7 @@ const MobileMenu = ({ isOpen, handleClose }: Props) => { { ))} - +
); }; diff --git a/client/components/shared/Overlays/MobileMenu/index.ts b/client/components/shared/Overlays/MobileMenu/index.ts new file mode 100644 index 00000000..0bbcf018 --- /dev/null +++ b/client/components/shared/Overlays/MobileMenu/index.ts @@ -0,0 +1 @@ +export { default } from "./MobileMenu"; diff --git a/client/components/shared/Overlays/MobileMenu/styles.module.scss b/client/components/shared/Overlays/MobileMenu/styles.module.scss new file mode 100644 index 00000000..f1be7ca0 --- /dev/null +++ b/client/components/shared/Overlays/MobileMenu/styles.module.scss @@ -0,0 +1,77 @@ +.MobileMenu { + animation: slide-from-right 0.5s forwards; + overflow: hidden; + position: fixed; + top: 0; + width: 100vw; + height: 100vh; + z-index: 101; + gap: 32px; + background-color: var(--slight-layer2); + transition-duration: 500ms; + opacity: 0.95; + .Navigator { + display: flex; + flex-direction: column; + align-items: center; + gap: 2.5rem; + font-size: 25px; + font-weight: 700; + button { + border: none; + background: none; + font-size: 25px; + font-weight: 700; + color: var(--bg-element2); + } + } + + .current { + text-decoration-color: var(--primary1); + text-underline-offset: 8px; + text-decoration-line: underline; + text-decoration-thickness: 4px; + } + + .closeArea { + width: 100%; + height: 120px; + display: flex; + align-items: center; + justify-content: flex-end; + button { + border: none; + background: none; + width: 50px; + height: 50px; + margin-right: 5%; + svg { + width: 45px; + height: 45px; + fill: var(--bg-element2); + } + } + } +} + +.closeAnimation { + animation: slide-to-right 0.5s forwards; +} + +@keyframes slide-from-right { + 0% { + left: 100%; + } + 100% { + left: 0; + } +} + +@keyframes slide-to-right { + 0% { + left: 0%; + } + 100% { + left: 100%; + } +} diff --git a/client/components/shared/Overlays/Overlays.tsx b/client/components/shared/Overlays/Overlays.tsx new file mode 100644 index 00000000..557ffae6 --- /dev/null +++ b/client/components/shared/Overlays/Overlays.tsx @@ -0,0 +1,55 @@ +"use client"; + +import { useOverlayStateContext } from "@contexts/overlayContex"; +import { useOverlay } from "@hooks"; +import React from "react"; +import dynamic from "next/dynamic"; + +const AuthModal = dynamic(() => import("./AuthModal"), { + ssr: false, +}); + +const SeriesFormModal = dynamic(() => import("./SeriesFormModal"), { + ssr: false, +}); + +const MobileMenuModal = dynamic(() => import("./MobileMenu"), { + ssr: false, +}); + +export const OVERLAYS = { + AUTH_MODAL: AuthModal, + SERIES_FORM_MODAL: SeriesFormModal, + MOBILE_MENU: MobileMenuModal, +}; + +const Overlays = () => { + const openedOverlays = useOverlayStateContext(); + const { closeOverlay } = useOverlay(); + return ( + <> + {openedOverlays.map(({ Component, props }, idx) => { + const onClose = () => { + closeOverlay(Component); + }; + + const onExit = (time: number) => { + setTimeout(() => { + onClose(); + }, time); + }; + + return ( + + ); + })} + + ); +}; + +export default Overlays; diff --git a/client/components/shared/Modals/SeriesFormModal/SeriesFormModal.tsx b/client/components/shared/Overlays/SeriesFormModal/SeriesFormModal.tsx similarity index 100% rename from client/components/shared/Modals/SeriesFormModal/SeriesFormModal.tsx rename to client/components/shared/Overlays/SeriesFormModal/SeriesFormModal.tsx diff --git a/client/components/shared/Modals/SeriesFormModal/index.ts b/client/components/shared/Overlays/SeriesFormModal/index.ts similarity index 100% rename from client/components/shared/Modals/SeriesFormModal/index.ts rename to client/components/shared/Overlays/SeriesFormModal/index.ts diff --git a/client/components/shared/Modals/SeriesFormModal/styles.module.scss b/client/components/shared/Overlays/SeriesFormModal/styles.module.scss similarity index 100% rename from client/components/shared/Modals/SeriesFormModal/styles.module.scss rename to client/components/shared/Overlays/SeriesFormModal/styles.module.scss diff --git a/client/components/shared/Overlays/index.ts b/client/components/shared/Overlays/index.ts new file mode 100644 index 00000000..04a8f97d --- /dev/null +++ b/client/components/shared/Overlays/index.ts @@ -0,0 +1 @@ +export { default } from "./Overlays"; diff --git a/client/contexts/modalContex.tsx b/client/contexts/modalContex.tsx deleted file mode 100644 index c9aa6999..00000000 --- a/client/contexts/modalContex.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { - createContext, - useContext, - type ComponentProps, - type PropsWithChildren, - type FunctionComponent, - useState, - useMemo, -} from "react"; - -interface ModalContext> { - Component: T; - props: ComponentProps; - open: (Component: T, props?: ComponentProps) => void; - close: (Component: T) => void; -} - -type ModalDispatchContextType = Pick, "close" | "open">; - -type ModalStateContextType = Pick, "Component" | "props">[]; - -const ModalDispatchContext = createContext( - null -); - -const ModalStateContext = createContext(null); - -export const ModalProvider = ({ children }: PropsWithChildren) => { - const [openedModals, setOpenedModals] = useState([]); - - const open = >( - Component: ModalContext["Component"], - props?: ModalContext["props"] - ) => { - setOpenedModals((modals) => { - return [...modals, { Component, props }]; - }); - }; - - const close = >( - Component: ModalContext["Component"] - ) => { - setOpenedModals((modals) => { - return modals.filter((modal) => modal.Component !== Component); - }); - }; - - const dispatch = useMemo(() => ({ open, close }), []); - - return ( - - - {children} - - - ); -}; - -export const useModalDispatchContext = () => { - const context = useContext(ModalDispatchContext); - if (!context) - throw new Error("ModalDispatchContext used Before Initialization"); - return context; -}; - -export const useModalStateContext = () => { - const context = useContext(ModalStateContext); - if (!context) throw new Error("ModalStateContext used Before Initialization"); - return context; -}; diff --git a/client/contexts/overlayContex.tsx b/client/contexts/overlayContex.tsx new file mode 100644 index 00000000..e50dab52 --- /dev/null +++ b/client/contexts/overlayContex.tsx @@ -0,0 +1,76 @@ +import { + createContext, + useContext, + type ComponentProps, + type PropsWithChildren, + type FunctionComponent, + useState, + useMemo, +} from "react"; + +interface OverlayContext> { + Component: T; + props: ComponentProps; + open: (Component: T, props?: ComponentProps) => void; + close: (Component: T) => void; +} + +type OverlayDispatchContextType = Pick, "close" | "open">; + +type OverlayStateContextType = Pick< + OverlayContext, + "Component" | "props" +>[]; + +const OverlayDispatchContext = createContext( + null +); + +const OverlayStateContext = createContext(null); + +export const OverlayProvider = ({ children }: PropsWithChildren) => { + const [openedOverlays, setOpenedOverlays] = useState( + [] + ); + + const open = >( + Component: OverlayContext["Component"], + props?: OverlayContext["props"] + ) => { + setOpenedOverlays((Overlays) => { + return [...Overlays, { Component, props }]; + }); + }; + + const close = >( + Component: OverlayContext["Component"] + ) => { + setOpenedOverlays((Overlays) => { + return Overlays.filter((Overlay) => Overlay.Component !== Component); + }); + }; + + const dispatch = useMemo(() => ({ open, close }), []); + + return ( + + + {children} + + + ); +}; + +export const useOverlayDispatchContext = () => { + const context = useContext(OverlayDispatchContext); + if (!context) + throw new Error("OverlayDispatchContext used Before Initialization"); + return context; +}; + +export const useOverlayStateContext = () => { + const context = useContext(OverlayStateContext); + if (!context) + throw new Error("OverlayStateContext used Before Initialization"); + return context; +}; diff --git a/server/build/config/express.js b/server/build/config/express.js index 410e0c88..a72aba04 100644 --- a/server/build/config/express.js +++ b/server/build/config/express.js @@ -53,9 +53,6 @@ function default_1() { app.use(passport_1.default.initialize()); app.use(passport_1.default.session()); app.set("trust proxy", 1); - app.use("/test", (req, res, next) => { - res.send("github action deploy test44"); - }); _routes_1.default.forEach(({ url, router }) => { app.use(url, router); }); diff --git a/server/src/config/express.ts b/server/src/config/express.ts index 66afb295..9d9df033 100644 --- a/server/src/config/express.ts +++ b/server/src/config/express.ts @@ -47,10 +47,6 @@ export default async function () { app.use(passport.session()); app.set("trust proxy", 1); - app.use("/test", (req, res, next) => { - res.send("github action deploy test44"); - }); - ROUTER_LIST.forEach(({ url, router }) => { app.use(url, router); }); diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index b0213c30..00000000 --- a/yarn.lock +++ /dev/null @@ -1,28 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@playwright/test@^1.31.2": - version "1.31.2" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.31.2.tgz#426d8545143a97a6fed250a2a27aa1c8e5e2548e" - integrity sha512-BYVutxDI4JeZKV1+ups6dt5WiqKhjBtIYowyZIJ3kBDmJgsuPKsqqKNIMFbUePLSCmp2cZu+BDL427RcNKTRYw== - dependencies: - "@types/node" "*" - playwright-core "1.31.2" - optionalDependencies: - fsevents "2.3.2" - -"@types/node@*": - version "18.15.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014" - integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw== - -fsevents@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -playwright-core@1.31.2: - version "1.31.2" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.31.2.tgz#debf4b215d14cb619adb7e511c164d068075b2ed" - integrity sha512-a1dFgCNQw4vCsG7bnojZjDnPewZcw7tZUNFN0ZkcLYKj+mPmXvg4MpaaKZ5SgqPsOmqIf2YsVRkgqiRDxD+fDQ==