signup & login UI

This commit is contained in:
2025-02-08 22:09:30 +08:00
parent c0783ef4a5
commit 3fcddf2d20
4 changed files with 219 additions and 5 deletions

View File

@@ -0,0 +1,48 @@
import { Input, Checkbox, Button, Link } from "@heroui/react";
import { IconMail, IconLock } from "@tabler/icons-react";
export default function LoginView({ onSignup }: { onSignup: () => void }) {
return (
<div className="flex flex-col gap-6">
<div className="flex flex-col">
<p className="text-3xl">Welcome back!</p>
<p className="text-md opacity-50">
Let us know who you are, and we will let you in.
</p>
</div>
<div className="flex flex-col gap-2">
<Input endContent={<IconMail />} label="Email" />
<Input endContent={<IconLock />} label="Password" type="password" />
</div>
<div className="flex py-2 px-1 justify-between">
<Checkbox
classNames={{
label: "text-small",
}}
>
Remember me
</Checkbox>
<Link color="primary" href="#" size="sm">
Forgot password?
</Link>
</div>
<div className="flex flex-col gap-4 w-full">
<Button color="primary" className="w-full">
Login
</Button>
<div className="flex flex-row gap-2 w-full justify-center *:my-auto">
<p className="text-sm">Don't have an account?</p>
<Link
color="primary"
onPress={() => {
onSignup();
}}
className="text-sm"
>
Sign up
</Link>
</div>
</div>
</div>
);
}

View File

@@ -1,15 +1,26 @@
import { import {
Button, Button,
Link, Link,
Modal,
ModalBody,
ModalContent,
ModalHeader,
ModalFooter,
Navbar, Navbar,
NavbarBrand, NavbarBrand,
NavbarContent, NavbarContent,
NavbarItem, NavbarItem,
useDisclosure,
} from "@heroui/react"; } from "@heroui/react";
import { useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import SignupView from "./SignupView";
import LoginView from "./LoginView";
export default function NavigationBar() { export default function NavigationBar() {
const navigate = useNavigate(); const navigate = useNavigate();
const { isOpen, onOpen, onOpenChange } = useDisclosure();
const [isSignup, setIsSignup] = useState(false);
return ( return (
<Navbar className="border-b-[1px] border-neutral-500/25"> <Navbar className="border-b-[1px] border-neutral-500/25">
@@ -32,7 +43,8 @@ export default function NavigationBar() {
<NavbarItem className="hidden lg:flex"> <NavbarItem className="hidden lg:flex">
<Button <Button
onPress={() => { onPress={() => {
navigate("/login"); setIsSignup(false);
onOpen();
}} }}
variant="light" variant="light"
> >
@@ -42,7 +54,8 @@ export default function NavigationBar() {
<NavbarItem> <NavbarItem>
<Button <Button
onPress={() => { onPress={() => {
navigate("/signup"); setIsSignup(true);
onOpen();
}} }}
variant="bordered" variant="bordered"
> >
@@ -50,6 +63,32 @@ export default function NavigationBar() {
</Button> </Button>
</NavbarItem> </NavbarItem>
</NavbarContent> </NavbarContent>
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
<ModalContent>
{() => (
<>
<ModalHeader />
<ModalBody>
{isSignup ? (
<SignupView
onLogin={() => {
setIsSignup(false);
}}
email=""
/>
) : (
<LoginView
onSignup={() => {
setIsSignup(true);
}}
/>
)}
</ModalBody>
<ModalFooter />
</>
)}
</ModalContent>
</Modal>
</Navbar> </Navbar>
); );
} }

View File

@@ -0,0 +1,72 @@
import {
Input,
Button,
Link,
Select,
SelectItem,
DatePicker,
} from "@heroui/react";
import { IconMail, IconLock } from "@tabler/icons-react";
import { useState } from "react";
export default function SignupView({
onLogin,
email = "",
}: {
onLogin: () => void;
email: string;
}) {
const [emailValue, setEmailValue] = useState(email);
return (
<div className="flex flex-col gap-6">
<div className="flex flex-col">
<p className="text-3xl">Welcome!</p>
<p className="text-md opacity-50">Become a membership today!</p>
</div>
<div className="flex flex-col gap-2">
<div className="flex flex-row gap-2">
<Input label="First name" />
<Input label="Last name" />
</div>
<Input
endContent={<IconMail />}
label="Email"
type="email"
value={emailValue}
onValueChange={setEmailValue}
/>
<Input label="NRIC" />
<div className="flex flex-row gap-2">
<Select label="Gender">
<SelectItem>Male</SelectItem>
<SelectItem>Female</SelectItem>
</Select>
<DatePicker label="Date of birth" />
</div>
<Input endContent={<IconLock />} label="Password" type="password" />
<Input
endContent={<IconLock />}
label="Confirm password"
type="password"
/>
</div>
<div className="flex flex-col gap-4 w-full">
<Button color="primary" className="w-full">
Sign up
</Button>
<div className="flex flex-row gap-2 w-full justify-center *:my-auto">
<p className="text-sm">Already have an account?</p>
<Link
color="primary"
onPress={() => {
onLogin();
}}
className="text-sm"
>
Login
</Link>
</div>
</div>
</div>
);
}

View File

@@ -1,6 +1,23 @@
import { Button, Card, Input } from "@heroui/react"; import {
Button,
Card,
Input,
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
useDisclosure,
} from "@heroui/react";
import { useState } from "react";
import LoginView from "../components/LoginView";
import SignupView from "../components/SignupView";
export default function HomePage() { export default function HomePage() {
const { isOpen, onOpen, onOpenChange } = useDisclosure();
const [isSignup, setIsSignup] = useState(false);
const [emailValue, setEmailValue] = useState("");
return ( return (
<div className="absolute inset-0 w-full h-full flex flex-col justify-center bg-indigo-500/10 dark:bg-indigo-500/20"> <div className="absolute inset-0 w-full h-full flex flex-col justify-center bg-indigo-500/10 dark:bg-indigo-500/20">
<div className="relative m-auto w-max h-max flex flex-col gap-10 justify-center text-center *:mx-auto"> <div className="relative m-auto w-max h-max flex flex-col gap-10 justify-center text-center *:mx-auto">
@@ -16,13 +33,51 @@ export default function HomePage() {
</div> </div>
<div> <div>
<Card className="flex flex-row gap-2 p-2"> <Card className="flex flex-row gap-2 p-2">
<Input placeholder="Enter your email" size="lg" /> <Input
<Button color="primary" size="lg"> placeholder="Enter your email"
size="lg"
value={emailValue}
onValueChange={setEmailValue}
/>
<Button
color="primary"
size="lg"
onPress={() => {
setIsSignup(true);
onOpen();
}}
>
Sign up Sign up
</Button> </Button>
</Card> </Card>
</div> </div>
</div> </div>
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
<ModalContent>
{() => (
<>
<ModalHeader />
<ModalBody>
{isSignup ? (
<SignupView
onLogin={() => {
setIsSignup(false);
}}
email={emailValue}
/>
) : (
<LoginView
onSignup={() => {
setIsSignup(true);
}}
/>
)}
</ModalBody>
<ModalFooter />
</>
)}
</ModalContent>
</Modal>
</div> </div>
); );
} }