grain.social is a photo sharing platform built on atproto.
at main 75 lines 1.7 kB view raw
1import { cn } from "@bigmoves/bff/components"; 2import type { JSX } from "preact"; 3import { Button } from "./Button.tsx"; 4import { Input } from "./Input.tsx"; 5 6export type LoginProps = 7 & JSX.HTMLAttributes<HTMLFormElement> 8 & Readonly<{ 9 inputPlaceholder?: string; 10 submitText?: string; 11 infoText?: string; 12 error?: string; 13 errorClass?: string; 14 infoClass?: string; 15 }>; 16 17export function Login( 18 { 19 inputPlaceholder = "Handle (e.g., user.bsky.social)", 20 submitText = "Login with Bluesky", 21 infoText = "", 22 error, 23 errorClass, 24 infoClass, 25 ...rest 26 }: LoginProps, 27): JSX.Element { 28 return ( 29 <form 30 id="login-form" 31 hx-post="/oauth/login" 32 hx-target="#login-form" 33 hx-swap="outerHTML" 34 {...rest} 35 class={cn( 36 "tw:mx-4 tw:sm:mx-0 tw:w-full tw:sm:max-w-[300px] tw:space-y-2", 37 rest.class, 38 )} 39 > 40 <div> 41 <label htmlFor="handle" class="tw:sr-only"> 42 Handle 43 </label> 44 <Input 45 id="handle" 46 class="bg-white text-zinc-900" 47 placeholder={inputPlaceholder} 48 name="handle" 49 /> 50 </div> 51 <Button 52 variant="primary" 53 id="submit" 54 type="submit" 55 class="tw:w-full" 56 > 57 {submitText} 58 </Button> 59 {infoText && ( 60 <div class={cn("tw:text-sm tw:text", infoClass)}> 61 {infoText} 62 </div> 63 )} 64 <div className="tw:h-4"> 65 {error 66 ? ( 67 <div className={cn("tw:text-sm tw:font-mono", errorClass)}> 68 {error} 69 </div> 70 ) 71 : null} 72 </div> 73 </form> 74 ); 75}