오른쪽 Navbar 상단위에 유저 정보를 클릭시 로그인, 회원가입 드랍다운이 가능하도록 구현하였다.
Ant design + tailwindcss를 사용하였으며, 코드는 다음과 같다.
navbar.tsx
import styled from "@emotion/styled";
import { Modal } from "antd";
import { ReactNode } from "react";
import Line from "../../../common/liine/line";
interface BaseModalProps {
children: ReactNode;
isModalOpen: boolean;
title: string;
onCancel: () => void;
}
const AuthModal = styled(Modal)`
.ant-modal-title {
font-size: 15epx;
text-align: center;
}
`;
function Footer(): JSX.Element {
return (
<>
<div className="flex justify-center">
<button className="w-full h-12 text-white bg-pink-700 rounded-lg border-none">
계속
</button>
</div>
</>
);
}
export default function AuthLayout({
children,
title,
isModalOpen,
onCancel,
}: BaseModalProps): JSX.Element {
return (
<>
<AuthModal
title={title}
open={isModalOpen}
centered={true}
width={530}
footer={Footer}
onCancel={onCancel}
>
<Line />
<h2 className="text-xl font-semibold mt-5">
에어비엔비에 오신걸 환영합니다.
</h2>
{children}
</AuthModal>
</>
);
}
user.tsx
import { useState } from "react";
import LoginModal from "../../units/modals/auth/login_modal";
import SignupModal from "../../units/modals/auth/signup_modal";
import Search from "./search";
import User from "./user";
export default function Navbar(): JSX.Element {
const [loginModalOpend, setLoginModalOpend] = useState(false);
const [signupModalOpend, setSignupModalOpend] = useState(false);
const handleSignup = (): void => {
setSignupModalOpend((prev) => !prev);
};
const handleLogin = (): void => {
setLoginModalOpend((prev) => !prev);
};
return (
<>
<nav className="w-full h-40 bg-white font-semibold pt-4">
<div className="flex justify-between items-center">
<h2 className="text-red-500 text-2xl">airbnb</h2>
<User handleSignup={handleSignup} handleLogin={handleLogin} />
</div>
<Search />
</nav>
{loginModalOpend ? (
<LoginModal
loginModalOpend={loginModalOpend}
handleLogin={handleLogin}
/>
) : (
""
)}
{signupModalOpend ? (
<SignupModal
signupModalOpend={signupModalOpend}
handleSignup={handleSignup}
/>
) : (
""
)}
</>
);
}
실제 결과
<모달 구현>
layout.tsx
import { faBars } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React from "react";
import { Dropdown, Space, Typography } from "antd";
import type { MenuProps } from "antd";
interface UserProps {
handleSignup: () => void;
handleLogin: () => void;
}
export default function User({
handleSignup,
handleLogin,
}: UserProps): JSX.Element {
const items: MenuProps["items"] = [
{
key: "1",
label: "로그인",
style: { height: "50%", backgroundColor: "white", color: "black" },
onClick: () => {
handleLogin();
},
},
{
key: "2",
label: "회원가입",
style: {
height: "50%",
backgroundColor: "white",
color: "black",
},
onClick: () => {
handleSignup();
},
},
];
return (
<>
<Dropdown
menu={{
items,
selectable: true,
defaultSelectedKeys: ["1"],
style: { width: "220px", height: "100px" },
}}
>
<Typography.Link>
<Space>
<button className="w-24 h-12 flex justify-between items-center border rounded-full pl-3 pr-3">
<FontAwesomeIcon icon={faBars} />
<image className="w-1/2 h-3/4 flex justify-center items-center bg-black rounded-full text-white text-sm">
U
</image>
</button>
</Space>
</Typography.Link>
</Dropdown>
</>
);
}
signup_modal.tsx
import { Input } from "antd";
import AuthLayout from "./layout";
interface SignupProps {
signupModalOpend: boolean;
handleSignup: () => void;
}
export default function SignupModal({
signupModalOpend,
handleSignup,
}: SignupProps): JSX.Element {
return (
<>
<AuthLayout
title="로그인 또는 회원가입"
isModalOpen={signupModalOpend}
onCancel={handleSignup}
>
<form className="space-y-3 mt-5">
<Input placeholder="이메일" className="h-10" />
<Input placeholder="이름" className="h-10" />
<Input placeholder="휴대폰번호" className="h-10" />
<Input.Password placeholder="패스워드" className="h-10" />
<Input.Password placeholder="패스워드 확인" className="h-10" />
</form>
</AuthLayout>
</>
);
}
login_modal.tsx
import { Input } from "antd";
import AuthLayout from "./layout";
interface LoginProps {
loginModalOpend: boolean;
handleLogin: () => void;
}
export default function LoginModal({
loginModalOpend,
handleLogin,
}: LoginProps): JSX.Element {
return (
<>
<AuthLayout
title="로그인 또는 회원가입"
isModalOpen={loginModalOpend}
onCancel={handleLogin}
>
<form className="space-y-3 mt-4">
<Input placeholder="이메일" className="h-10" />
<Input.Password placeholder="패스워드" className="h-10" />
</form>
</AuthLayout>
</>
);
}
결과
'Next js' 카테고리의 다른 글
[에어비엔비] #2 Room Detail 페이지 스타일링 (0) | 2024.04.05 |
---|---|
[에어비엔비 클론코딩] #1 Home Page 스타일링 (0) | 2024.03.24 |
[Next js] SyntaxError: Named export 'useInsertionEffect' not found. (0) | 2024.01.02 |
[Next js] useRouter, useEffect data fetching (0) | 2023.10.09 |
[Next js] localhost 진입 불가능할 때 해결 방법 (0) | 2023.09.09 |