+7
package-lock.json
+7
package-lock.json
···
17
17
"@icons-pack/react-simple-icons": "^13.8.0",
18
18
"@neondatabase/serverless": "^1.0.2",
19
19
"@netlify/functions": "^4.2.7",
20
+
"actor-typeahead": "^0.1.2",
20
21
"cookie": "^1.0.2",
21
22
"jose": "^6.1.0",
22
23
"jszip": "^3.10.1",
···
3095
3096
"peerDependencies": {
3096
3097
"acorn": "^8"
3097
3098
}
3099
+
},
3100
+
"node_modules/actor-typeahead": {
3101
+
"version": "0.1.2",
3102
+
"resolved": "https://registry.npmjs.org/actor-typeahead/-/actor-typeahead-0.1.2.tgz",
3103
+
"integrity": "sha512-I97YqqNl7Kar0J/bIJvgY/KmHpssHcDElhfwVTLP7wRFlkxso2ZLBqiS2zol5A8UVUJbQK2JXYaqNpZXz8Uk2A==",
3104
+
"license": "MPL-2.0"
3098
3105
},
3099
3106
"node_modules/agent-base": {
3100
3107
"version": "7.1.4",
+1
package.json
+1
package.json
+19
src/index.css
+19
src/index.css
···
144
144
);
145
145
animation: svg-glow-right 3s ease-in-out infinite 0.5s; /* offset timing */
146
146
}
147
+
148
+
/* Actor typeahead */
149
+
actor-typeahead {
150
+
--color-background: rgb(249 250 251 / 1);
151
+
--color-border: rgb(6 182 212 / 0.5);
152
+
--color-shadow: rgb(88 28 135);
153
+
--color-hover: rgb(6 182 212 / 0.1);
154
+
--color-avatar-fallback: rgb(6 182 212 / 0.2);
155
+
--radius: 0.75rem;
156
+
--padding-menu: 0.5rem;
157
+
}
158
+
159
+
.dark actor-typeahead {
160
+
--color-background: rgb(15 23 42 / 1);
161
+
--color-border: rgb(126 34 206 / 0.3);
162
+
--color-shadow: rgb(0 0 0);
163
+
--color-hover: rgb(126 34 206 / 0.2);
164
+
--color-avatar-fallback: rgb(126 34 206 / 0.2);
165
+
}
+23
-20
src/pages/Login.tsx
+23
-20
src/pages/Login.tsx
···
1
-
import { useState } from "react";
1
+
import { useState, useRef } from "react";
2
+
import "actor-typeahead";
2
3
import { Heart, Upload, Search, ArrowRight } from "lucide-react";
3
4
import FireflyLogo from "../assets/at-firefly-logo.svg?react";
4
5
···
16
17
reducedMotion = false,
17
18
}: LoginPageProps) {
18
19
const [handle, setHandle] = useState("");
20
+
const inputRef = useRef<HTMLInputElement>(null);
19
21
20
22
const handleSubmit = (e: React.FormEvent) => {
21
23
e.preventDefault();
22
-
onSubmit(handle);
24
+
// Get the value directly from the input instead of state
25
+
const currentHandle = inputRef.current?.value || handle;
26
+
onSubmit(currentHandle);
23
27
};
24
28
25
29
return (
···
108
112
>
109
113
Your ATmosphere Handle
110
114
</label>
111
-
<input
112
-
id="atproto-handle"
113
-
type="text"
114
-
value={handle}
115
-
onChange={(e) => setHandle(e.target.value)}
116
-
placeholder="yourname.bsky.social"
117
-
className="w-full px-4 py-3 bg-purple-50/50 dark:bg-slate-900/50 border-2 border-cyan-500/50 dark:border-purple-500/30 rounded-xl text-purple-900 dark:text-cyan-100 placeholder-purple-750/80 dark:placeholder-cyan-250/80 focus:outline-none focus:ring-2 focus:ring-orange-500 dark:focus:ring-amber-400 focus:border-transparent transition-all"
118
-
aria-required="true"
119
-
aria-describedby="handle-description"
120
-
/>
121
-
{/*<p
122
-
id="handle-description"
123
-
className="text-xs text-slate-600 dark:text-slate-400 mt-2"
124
-
>
125
-
Enter your full ATmosphere handle (e.g.,
126
-
username.bsky.social or yourname.com)
127
-
</p>*/}
115
+
<actor-typeahead rows={5}>
116
+
<input
117
+
ref={inputRef}
118
+
id="atproto-handle"
119
+
type="text"
120
+
defaultValue={handle}
121
+
onInput={(e) =>
122
+
setHandle((e.target as HTMLInputElement).value)
123
+
}
124
+
placeholder="yourname.bsky.social"
125
+
className="w-full px-4 py-3 bg-purple-50/50 dark:bg-slate-900/50 border-2 border-cyan-500/50 dark:border-purple-500/30 rounded-xl text-purple-900 dark:text-cyan-100 placeholder-purple-750/80 dark:placeholder-cyan-250/80 focus:outline-none focus:ring-2 focus:ring-orange-500 dark:focus:ring-amber-400 focus:border-transparent transition-all"
126
+
aria-required="true"
127
+
aria-describedby="handle-description"
128
+
/>
129
+
</actor-typeahead>
128
130
</div>
129
131
130
132
<button
···
155
157
Secure OAuth Connection
156
158
</p>
157
159
<p className="text-xs mt-1">
158
-
We use official AT Protocol OAuth. We never see your
160
+
We use official AT Protocol OAuth. You will be directed
161
+
to your account to authorize access. We never see your
159
162
password and you can revoke access anytime.
160
163
</p>
161
164
</div>
+19
src/types/actor-typeahead.d.ts
+19
src/types/actor-typeahead.d.ts
···
1
+
import "react";
2
+
3
+
// uses npm install actor-typeahead
4
+
// from https://tangled.org/jakelazaroff.com/actor-typeahead <3
5
+
6
+
declare module "react" {
7
+
namespace JSX {
8
+
interface IntrinsicElements {
9
+
"actor-typeahead": React.DetailedHTMLProps<
10
+
{
11
+
host?: string;
12
+
rows?: number;
13
+
children?: React.ReactNode;
14
+
},
15
+
HTMLElement
16
+
>;
17
+
}
18
+
}
19
+
}