atproto explorer
0
fork

Configure Feed

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

add blob list

+89
+2
src/index.tsx
··· 11 11 import { RepoView } from "./views/repo.tsx"; 12 12 import { CollectionView } from "./views/collection.tsx"; 13 13 import { RecordView } from "./views/record.tsx"; 14 + import { BlobView } from "./views/blob.tsx"; 14 15 15 16 render( 16 17 () => ( ··· 19 20 <Route path="/login" component={Login} /> 20 21 <Route path="/:pds" component={PdsView} /> 21 22 <Route path="/:pds/:repo" component={RepoView} /> 23 + <Route path="/:pds/:repo/blobs" component={BlobView} /> 22 24 <Route path="/:pds/:repo/:collection" component={CollectionView} /> 23 25 <Route path="/:pds/:repo/:collection/:rkey" component={RecordView} /> 24 26 </Router>
+82
src/views/blob.tsx
··· 1 + import { createSignal, onMount, Show, type Component } from "solid-js"; 2 + import { CredentialManager, XRPC } from "@atcute/client"; 3 + import { A, query, useParams } from "@solidjs/router"; 4 + import { setNotice, setPDS } from "../main.jsx"; 5 + import { resolvePDS } from "../utils/api.js"; 6 + import { resolveHandle } from "@atcute/oauth-browser-client"; 7 + 8 + const BlobView: Component = () => { 9 + const params = useParams(); 10 + const [cursor, setCursor] = createSignal<string>(); 11 + const [blobs, setBlobs] = createSignal<string[]>(); 12 + let rpc: XRPC; 13 + let did: string; 14 + let pds: string; 15 + 16 + onMount(async () => { 17 + setNotice("Loading..."); 18 + setPDS(params.pds); 19 + pds = 20 + params.pds.startsWith("localhost") ? 21 + `http://${params.pds}` 22 + : `https://${params.pds}`; 23 + did = 24 + params.repo.startsWith("did:") ? 25 + params.repo 26 + : await resolveHandle(params.repo); 27 + if (params.pds === "at") pds = await resolvePDS(did); 28 + rpc = new XRPC({ handler: new CredentialManager({ service: pds }) }); 29 + await fetchBlobs(); 30 + setNotice(""); 31 + }); 32 + 33 + const fetchBlobs = async () => { 34 + const res = await listBlobs(did, cursor()); 35 + setCursor(res.data.cids.length < 100 ? undefined : res.data.cursor); 36 + setBlobs(blobs()?.concat(res.data.cids) ?? res.data.cids); 37 + setNotice(""); 38 + }; 39 + 40 + const listBlobs = query( 41 + (did: string, cursor: string | undefined) => 42 + rpc.get("com.atproto.sync.listBlobs", { 43 + params: { 44 + did: did as any, 45 + limit: 1000, 46 + cursor: cursor, 47 + }, 48 + }), 49 + "listBlobs", 50 + ); 51 + 52 + return ( 53 + <div class="flex flex-col items-center"> 54 + <Show when={blobs()}> 55 + <div class="flex flex-col font-mono"> 56 + {blobs()!.map((cid) => { 57 + return ( 58 + <A 59 + href={`${pds}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}`} 60 + target="_blank" 61 + class="hover:bg-neutral-300 dark:hover:bg-neutral-700" 62 + > 63 + <span class="text-lightblue-500">{cid}</span> 64 + </A> 65 + ); 66 + })} 67 + </div> 68 + </Show> 69 + <Show when={cursor()}> 70 + <button 71 + type="button" 72 + onclick={() => fetchBlobs()} 73 + class="dark:bg-dark-700 dark:hover:bg-dark-800 mt-1 rounded-lg border border-gray-400 bg-white px-2.5 py-1.5 text-sm font-bold hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-300" 74 + > 75 + Load More 76 + </button> 77 + </Show> 78 + </div> 79 + ); 80 + }; 81 + 82 + export { BlobView };
+5
src/views/repo.tsx
··· 51 51 </A> 52 52 )} 53 53 </For> 54 + <div class="mt-1 font-sans text-lg"> 55 + <A href="blobs" class="text-lightblue-500 hover:underline"> 56 + List blobs 57 + </A> 58 + </div> 54 59 </div> 55 60 <Show when={repo()}> 56 61 <div class="flex flex-col gap-y-1 break-words">