/** * ResolverUI component * * Main landing page for the wisp client with handle/DID input form. */ import { useState, useEffect } from 'react'; import { useATProtoResolver } from '../hooks/useATProtoResolver'; import { useSitesFetcher } from '../hooks/useManifestFetcher'; import { InlineLoading } from './LoadingState'; import { InlineError } from './ErrorDisplay'; export interface ResolverUIProps { initialHandle?: string; onLoad?: (handle: string, siteRkey: string, siteName: string) => void; } export function ResolverUI({ initialHandle = '', onLoad }: ResolverUIProps) { const [handleInput, setHandleInput] = useState(initialHandle); const [debouncedInput, setDebouncedInput] = useState(initialHandle); const [selectedSite, setSelectedSite] = useState<{ rkey: string; name: string } | null>(null); // Debounce input to avoid excessive resolution requests useEffect(() => { const timer = setTimeout(() => { setDebouncedInput(handleInput.trim()); }, 500); return () => clearTimeout(timer); }, [handleInput]); // Resolve handle/DID const resolverState = useATProtoResolver(debouncedInput || null); // Fetch available sites when resolution completes const sitesState = useSitesFetcher( resolverState.data?.pdsUrl || null, resolverState.data?.did || null ); // Handle form submission const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!handleInput.trim()) { return; } if (!resolverState.data || resolverState.error) { return; } if (!sitesState.data || sitesState.data.length === 0) { return; } // Use selected site, or first site if none selected const siteInfo = selectedSite || { rkey: sitesState.data[0].rkey, name: sitesState.data[0].site, }; const handle = resolverState.data.handle || handleInput.trim(); // Trigger load callback with rkey (for fetching) and name (for URL) onLoad?.(handle, siteInfo.rkey, siteInfo.name); }; // Handle input change const handleInputChange = (value: string) => { setHandleInput(value); setSelectedSite(null); }; // Handle site selection const handleSiteSelect = (rkey: string, name: string) => { setSelectedSite({ rkey, name }); }; // Check if can submit const canSubmit = handleInput.trim() && resolverState.data && !resolverState.loading && !resolverState.error && sitesState.data && sitesState.data.length > 0; return (
Browse websites from the PDS (unofficial)
For more information on wisp.place sites, see {' '} wisp.place . This explorer is unaffiliated.