alternative tangled frontend (extremely wip)
1import {
2 LucideAtSign,
3 LucideCircleUserRound,
4 LucideInfo,
5 LucideLogIn,
6} from "lucide-react";
7import { useState } from "react";
8import { Button } from "@/components/Animated/Button";
9import { UnderlineLink } from "@/components/Animated/UnderlinedLink";
10import { Loading } from "@/components/Icons/Loading";
11import { useOAuthClient } from "@/lib/oauth";
12
13export const SignIn = () => {
14 const [handle, setHandle] = useState("");
15 const isValidHandle = handle.includes(".");
16 const client = useOAuthClient();
17
18 if (!client) return <Loading />;
19
20 const handleOAuthContinue = () => {
21 localStorage.setItem("handle", handle);
22 const doOAuth = async () => {
23 try {
24 await client.signIn(handle, {
25 ui_locales: "en",
26 signal: new AbortController().signal,
27 });
28
29 console.log("Never executed");
30 } catch (err) {
31 console.log(
32 'The user aborted the authorization process by navigating "back"',
33 );
34 }
35 };
36
37 doOAuth().catch((e: unknown) => {
38 console.error(
39 "Something went wrong while trying to do OAuth handover.",
40 );
41 console.error(e);
42 });
43 };
44
45 const loginIcon = <LucideLogIn height={16} width={16} />;
46
47 return (
48 <div className="bg-surface0 border-surface1 m-36 flex max-w-1/4 flex-col items-center rounded-md border-1 px-6 py-4">
49 <LucideCircleUserRound
50 height={24}
51 width={24}
52 className="mt-4 mb-1"
53 />
54 <h2 className="text-xl font-semibold tracking-wide">Sign In</h2>
55 <p className="text-subtext m-4">
56 Continue with an{" "}
57 <UnderlineLink
58 href="https://atproto.com"
59 underlineColor="bg-accent"
60 className="text-accent"
61 >
62 Atmosphere
63 </UnderlineLink>{" "}
64 account
65 </p>
66 <div className="w-full">
67 <div className="flex items-center gap-0.5">
68 <p className="p-0.5">Handle</p>
69 <div className="group relative">
70 <LucideInfo
71 className="text-accent cursor-pointer"
72 height={14}
73 width={14}
74 />
75 <div className="bg-surface1 pointer-events-none absolute bottom-full left-1/2 mb-2 w-64 -translate-x-1/2 rounded-lg px-3 py-2 text-sm opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100">
76 If you have a Bluesky, Blacksky, Tangled, or any
77 other ATProto account, you can use that account's
78 handle.
79 <div className="border-t-surface1 absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent" />
80 </div>
81 </div>
82 </div>
83 <div className="border-surface1 group has-[:focus]:border-accent flex items-center overflow-hidden rounded-sm border transition-all">
84 <LucideAtSign
85 className="text-subtext group-has-[:focus]:text-accent h-full w-max px-2 transition-all"
86 height={16}
87 width={16}
88 />
89 <div className="bg-surface1 group-has-[:focus]:bg-accent w-px self-stretch transition-all" />
90 <input
91 placeholder="akshay.tngl.sh"
92 className="peer w-full rounded-tr-sm rounded-br-sm p-1 py-2 pl-2 transition-all focus:outline-0"
93 onChange={(e) => setHandle(e.target.value)}
94 />
95 </div>
96 </div>
97 <Button
98 label="Continue"
99 icon={loginIcon}
100 iconPosition="right"
101 className="hover:bg-accent/90 hover:text-crust hover:disabled:bg-surface1 hover:disabled:text-text bg-accent text-crust disabled:bg-surface1 disabled:text-text m-2 mt-6 mb-2 flex w-full cursor-pointer items-center justify-center gap-2 rounded-sm p-2 transition-all disabled:cursor-not-allowed"
102 disabled={!isValidHandle}
103 labelClassName=""
104 iconClassName=""
105 underlineClassName="bg-crust"
106 onClick={handleOAuthContinue}
107 iconTransitions={{ duration: 0.2, ease: "easeInOut" }}
108 iconVariants={{
109 active: {
110 x: [0, 5, -5, 0],
111 opacity: [1, 0, 0, 1],
112 },
113 }}
114 />
115 </div>
116 );
117};