atmosphere explorer pds.ls
tool typescript atproto
437
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v1.2.3 87 lines 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};