-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
45e799c
commit 352cb00
Showing
146 changed files
with
40,334 additions
and
8,187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import { type FieldConfig, conform } from "@conform-to/react"; | ||
import { Form, Link, useNavigation, useSearchParams } from "@remix-run/react"; | ||
import type { Form as ConformForm } from "~/utils/types"; | ||
|
||
type LoginFormProps = { | ||
accountIdentifier: FieldConfig<any>; | ||
password: FieldConfig<any>; | ||
redirectTo?: string; | ||
form: ConformForm; | ||
}; | ||
|
||
export default function LoginForm({ | ||
accountIdentifier, | ||
password, | ||
redirectTo, | ||
form, | ||
}: LoginFormProps) { | ||
const navigation = useNavigation(); | ||
const [searchParams] = useSearchParams(); | ||
|
||
return ( | ||
<Form method="post" className="space-y-6" {...form.props}> | ||
<div> | ||
<label | ||
htmlFor={accountIdentifier.id} | ||
className="block text-sm font-medium text-gray-700" | ||
> | ||
Email or Username | ||
</label> | ||
<div className="mt-1"> | ||
<input | ||
autoFocus={true} | ||
aria-invalid={accountIdentifier.error ? true : undefined} | ||
aria-describedby={accountIdentifier.errorId} | ||
className="w-full rounded border border-gray-500 px-2 py-1 text-lg" | ||
{...conform.input(accountIdentifier, { type: "text" })} | ||
/> | ||
{accountIdentifier.error ? ( | ||
<div | ||
className="mt-1 w-auto rounded bg-red-200 px-2 py-4 text-red-600 shadow-md" | ||
id={accountIdentifier.errorId} | ||
role="alert" | ||
> | ||
{accountIdentifier.error} | ||
</div> | ||
) : null} | ||
</div> | ||
</div> | ||
|
||
<div> | ||
<label | ||
htmlFor={password.id} | ||
className="block text-sm font-medium text-gray-700" | ||
> | ||
Password | ||
</label> | ||
<div className="mt-1"> | ||
<input | ||
aria-invalid={password.error ? true : undefined} | ||
aria-describedby={password.errorId} | ||
className="w-full rounded border border-gray-500 px-2 py-1 text-lg" | ||
{...conform.input(password, { type: "password" })} | ||
/> | ||
{password.error ? ( | ||
<div | ||
className="mt-1 w-auto rounded bg-red-200 px-2 py-4 text-red-600 shadow-md" | ||
id={password.errorId} | ||
role="alert" | ||
> | ||
{password.error} | ||
</div> | ||
) : null} | ||
</div> | ||
</div> | ||
|
||
<input type="hidden" name="redirectTo" value={redirectTo} /> | ||
<button | ||
type="submit" | ||
className="w-full rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600 focus:bg-blue-400" | ||
disabled={ | ||
navigation.state === "submitting" || navigation.state === "loading" | ||
} | ||
aria-disabled={ | ||
navigation.state === "submitting" || navigation.state === "loading" | ||
} | ||
> | ||
Log in | ||
</button> | ||
<div className="flex items-center justify-between"> | ||
<div className="flex items-center"> | ||
<input | ||
id="remember" | ||
name="remember" | ||
type="checkbox" | ||
className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" | ||
/> | ||
<label | ||
htmlFor="remember" | ||
className="ml-2 block text-sm text-gray-900" | ||
> | ||
Remember me | ||
</label> | ||
</div> | ||
<div className="text-center text-sm text-gray-500"> | ||
Don't have an account?{" "} | ||
<Link | ||
prefetch="intent" | ||
className="text-blue-500 underline" | ||
to={{ | ||
pathname: "/join", | ||
search: searchParams.toString(), | ||
}} | ||
> | ||
Sign up | ||
</Link> | ||
</div> | ||
</div> | ||
</Form> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import LoginForm from "./LoginForm"; | ||
|
||
export default LoginForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { unstable_createRemixStub as createRemixStub } from "@remix-run/testing"; | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import RegisterForm from "./RegisterForm"; | ||
|
||
const meta: Meta<typeof RegisterForm> = { | ||
title: "components/Form/RegisterForm", | ||
component: RegisterForm, | ||
decorators: [ | ||
(Story) => { | ||
const RemixStub = createRemixStub([{ path: "/", element: <Story /> }]); | ||
return <RemixStub />; | ||
}, | ||
], | ||
tags: ["autodocs"], | ||
args: { | ||
email: { | ||
id: "email", | ||
name: "email", | ||
errorId: "email-error", | ||
defaultValue: "[email protected]", | ||
}, | ||
username: { | ||
id: "username", | ||
name: "username", | ||
errorId: "username-error", | ||
defaultValue: "petereck123", | ||
}, | ||
password: { | ||
id: "password", | ||
name: "password", | ||
errorId: "password-error", | ||
defaultValue: "password123", | ||
}, | ||
confirmPassword: { | ||
id: "email", | ||
name: "email", | ||
errorId: "email-error", | ||
defaultValue: "password123", | ||
}, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Primary: Story = { | ||
render: () => ( | ||
<RegisterForm | ||
email={meta.args?.email!} | ||
username={meta.args?.username!} | ||
password={meta.args?.password!} | ||
confirmPassword={meta.args?.confirmPassword!} | ||
searchParams={meta.args?.searchParams!} | ||
form={meta.args?.form!} | ||
/> | ||
), | ||
}; |
Oops, something went wrong.