atproto explorer pdsls.dev
atproto tool
at main 3.1 kB view raw
1import { Handle } from "@atcute/lexicons"; 2import { createSignal, Show } from "solid-js"; 3import { resolveHandle } from "../../utils/api"; 4import { Button } from "../button.jsx"; 5import { TextInput } from "../text-input.jsx"; 6import { editorInstance } from "./state"; 7 8export const HandleInput = (props: { onClose: () => void }) => { 9 const [resolving, setResolving] = createSignal(false); 10 const [error, setError] = createSignal(""); 11 let handleFormRef!: HTMLFormElement; 12 13 const resolveDid = async (e: SubmitEvent) => { 14 e.preventDefault(); 15 const formData = new FormData(handleFormRef); 16 const handleValue = formData.get("handle")?.toString().trim(); 17 18 if (!handleValue) { 19 setError("Please enter a handle"); 20 return; 21 } 22 23 setResolving(true); 24 setError(""); 25 try { 26 const did = await resolveHandle(handleValue as Handle); 27 editorInstance.view.dispatch({ 28 changes: { 29 from: editorInstance.view.state.selection.main.head, 30 insert: `"${did}"`, 31 }, 32 }); 33 props.onClose(); 34 handleFormRef.reset(); 35 } catch (err: any) { 36 setError(err.message || "Failed to resolve handle"); 37 } finally { 38 setResolving(false); 39 } 40 }; 41 42 return ( 43 <div class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-70 left-[50%] w-[20rem] -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 dark:border-neutral-700 starting:opacity-0"> 44 <h2 class="mb-2 font-semibold">Insert DID from handle</h2> 45 <form ref={handleFormRef} onSubmit={resolveDid} class="flex flex-col gap-2 text-sm"> 46 <div class="flex flex-col gap-1"> 47 <label for="handle-input" class="select-none"> 48 Handle 49 </label> 50 <TextInput id="handle-input" name="handle" placeholder="user.bsky.social" /> 51 </div> 52 <p class="text-xs text-neutral-600 dark:text-neutral-400"> 53 DID will be pasted after the cursor 54 </p> 55 <Show when={error()}> 56 <span class="text-red-500 dark:text-red-400">Error: {error()}</span> 57 </Show> 58 <div class="flex justify-between gap-2"> 59 <Button 60 type="button" 61 onClick={() => { 62 props.onClose(); 63 handleFormRef.reset(); 64 setError(""); 65 }} 66 > 67 Cancel 68 </Button> 69 <Show when={resolving()}> 70 <div class="flex items-center gap-1"> 71 <span class="iconify lucide--loader-circle animate-spin"></span> 72 <span>Resolving</span> 73 </div> 74 </Show> 75 <Show when={!resolving()}> 76 <Button 77 type="submit" 78 class="dark:shadow-dark-700 flex items-center gap-1 rounded-lg bg-blue-500 px-2 py-1.5 text-xs text-white shadow-xs select-none hover:bg-blue-600 active:bg-blue-700 dark:bg-blue-600 dark:hover:bg-blue-500 dark:active:bg-blue-400" 79 > 80 Insert 81 </Button> 82 </Show> 83 </div> 84 </form> 85 </div> 86 ); 87};