atproto explorer

add nsid redirect in records

handle.invalid 3d3ca0fc f2c5de3b

verified
+28 -8
+27 -7
src/components/json.tsx
··· 1 - import { A, useParams } from "@solidjs/router"; 1 + import { isDid, isNsid, Nsid } from "@atcute/lexicons/syntax"; 2 + import { A, useNavigate, useParams } from "@solidjs/router"; 2 3 import { createEffect, createSignal, ErrorBoundary, For, Show } from "solid-js"; 4 + import { resolveLexiconAuthority } from "../utils/api"; 5 + import { ATURI_RE } from "../utils/types/at-uri"; 3 6 import { hideMedia } from "../views/settings"; 4 7 import { pds } from "./navbar"; 5 8 import Tooltip from "./tooltip"; ··· 11 14 mimeType: string; 12 15 } 13 16 14 - const ATURI_RE = 15 - /^at:\/\/([a-zA-Z0-9._:%-]+)(?:\/([a-zA-Z0-9-.]+)(?:\/([a-zA-Z0-9._~:@!$&%')(*+,;=-]+))?)?(?:#(\/[a-zA-Z0-9._~:@!$&%')(*+,;=\-[\]/\\]*))?$/; 17 + const JSONString = ({ data }: { data: string }) => { 18 + const navigate = useNavigate(); 16 19 17 - const DID_RE = /^did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]$/; 18 - 19 - const JSONString = ({ data }: { data: string }) => { 20 20 const isURL = 21 21 URL.canParse ?? 22 22 ((url, base) => { ··· 28 28 } 29 29 }); 30 30 31 + const handleClick = async (lex: string) => { 32 + try { 33 + const [nsid, anchor] = lex.split("#"); 34 + const authority = await resolveLexiconAuthority(nsid as Nsid); 35 + 36 + const hash = anchor ? `#schema:${anchor}` : "#schema"; 37 + navigate(`/at://${authority}/com.atproto.lexicon.schema/${nsid}${hash}`); 38 + } catch (err) { 39 + console.error("Failed to resolve lexicon authority:", err); 40 + } 41 + }; 42 + 31 43 return ( 32 44 <span> 33 45 " ··· 38 50 <A class="text-blue-400 hover:underline active:underline" href={`/${part}`}> 39 51 {part} 40 52 </A> 41 - : DID_RE.test(part) ? 53 + : isDid(part) ? 42 54 <A class="text-blue-400 hover:underline active:underline" href={`/at://${part}`}> 43 55 {part} 44 56 </A> 57 + : isNsid(part.split("#")[0]) ? 58 + <button 59 + type="button" 60 + onClick={() => handleClick(part)} 61 + class="cursor-pointer text-blue-400 hover:underline active:underline" 62 + > 63 + {part} 64 + </button> 45 65 : ( 46 66 isURL(part) && 47 67 ["http:", "https:", "web+at:"].includes(new URL(part).protocol) &&
+1 -1
src/utils/types/at-uri.ts
··· 11 11 12 12 const RECORD_KEY_RE = /^(?!\.{1,2}$)[a-zA-Z0-9_~.:-]{1,512}$/; 13 13 14 - const ATURI_RE = 14 + export const ATURI_RE = 15 15 /^at:\/\/([a-zA-Z0-9._:%-]+)(?:\/([a-zA-Z0-9-.]+)(?:\/([a-zA-Z0-9._~:@!$&%')(*+,;=-]+))?)?(?:#(\/[a-zA-Z0-9._~:@!$&%')(*+,;=\-[\]/\\]*))?$/; 16 16 17 17 const isDid = (input: unknown): input is Did => {