an app to share curated trails
sidetrail.app
1"use client";
2
3import * as Dialog from "@radix-ui/react-dialog";
4import { useFormStatus } from "react-dom";
5import { useLoginModal } from "@/app/LoginModalContext";
6import { login } from "@/auth/actions";
7import "./LoginModal.css";
8import "./login/LoginForm.css";
9
10function ModalFormContent({ returnUrl }: { returnUrl: string }) {
11 const { pending } = useFormStatus();
12 const { closeLoginModal } = useLoginModal();
13
14 return (
15 <Dialog.Content
16 className="LoginModal"
17 onEscapeKeyDown={(e) => pending && e.preventDefault()}
18 onPointerDownOutside={(e) => pending && e.preventDefault()}
19 onCloseAutoFocus={(e) => e.preventDefault()}
20 >
21 <div className="LoginModal-content">
22 <Dialog.Close asChild disabled={pending}>
23 <button
24 className="LoginModal-close"
25 aria-label="Close"
26 disabled={pending}
27 onClick={() => !pending && closeLoginModal()}
28 >
29 ×
30 </button>
31 </Dialog.Close>
32 <Dialog.Title className="LoginModal-title">sidetrail</Dialog.Title>
33 <Dialog.Description className="LoginModal-subtitle">
34 sign in with your{" "}
35 <a href="https://internethandle.org/#start" target="_blank" rel="noopener noreferrer">
36 internet handle
37 </a>
38 </Dialog.Description>
39 <div className="LoginForm">
40 <input
41 type="text"
42 name="loginHint"
43 placeholder="alice.bsky.social"
44 className="LoginForm-input"
45 required
46 autoFocus
47 readOnly={pending}
48 />
49 <input type="hidden" name="returnUrl" value={returnUrl} />
50 <button type="submit" className="LoginForm-button" disabled={pending}>
51 {pending ? "signing in..." : "continue"}
52 </button>
53 </div>
54 </div>
55 </Dialog.Content>
56 );
57}
58
59export function LoginModal() {
60 const { isOpen, closeLoginModal } = useLoginModal();
61 const returnUrl = typeof window !== "undefined" ? window.location.pathname : "/";
62
63 const handleOpenChange = (open: boolean) => {
64 if (!open) {
65 closeLoginModal();
66 }
67 };
68
69 return (
70 <Dialog.Root open={isOpen} onOpenChange={handleOpenChange}>
71 <Dialog.Portal>
72 <Dialog.Overlay className="LoginModal-backdrop" />
73 <form action={login}>
74 <ModalFormContent returnUrl={returnUrl} />
75 </form>
76 </Dialog.Portal>
77 </Dialog.Root>
78 );
79}