forked from pdsls.dev/pdsls
atproto explorer

Compare changes

Choose any two refs to compare.

Changed files
+44 -88
src
+3 -6
src/components/create.tsx
··· 172 172 ></span> 173 173 <span>{props.create ? "Creating" : "Editing"} record</span> 174 174 </div> 175 - <button 176 - onclick={() => setOpenDialog(false)} 177 - class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 178 - > 179 - <span class="iconify lucide--x"></span> 175 + <button onclick={() => setOpenDialog(false)} class="flex items-center"> 176 + <span class="iconify lucide--x text-lg hover:text-neutral-500 dark:hover:text-neutral-400"></span> 180 177 </button> 181 178 </div> 182 179 <form ref={formRef} class="flex flex-col gap-y-2"> ··· 189 186 <TextInput 190 187 id="collection" 191 188 name="collection" 192 - placeholder="Optional (default: $type)" 189 + placeholder="Optional (default: record type)" 193 190 class="w-[15rem]" 194 191 /> 195 192 </div>
+4
src/components/navbar.tsx
··· 5 5 import Tooltip from "./tooltip"; 6 6 7 7 export const [pds, setPDS] = createSignal<string>(); 8 + export const [cid, setCID] = createSignal<string>(); 8 9 export const [isLabeler, setIsLabeler] = createSignal(false); 9 10 10 11 const NavBar = (props: { params: Params }) => { ··· 59 60 copyContent={`at://${props.params.repo}${props.params.collection ? `/${props.params.collection}` : ""}${props.params.rkey ? `/${props.params.rkey}` : ""}`} 60 61 label="Copy AT URI" 61 62 /> 63 + </Show> 64 + <Show when={props.params.rkey && cid()}> 65 + <CopyMenu copyContent={cid()!} label="Copy CID" /> 62 66 </Show> 63 67 </DropdownMenu> 64 68 </MenuProvider>
+7 -53
src/components/search.tsx
··· 2 2 import { A, useLocation, useNavigate } from "@solidjs/router"; 3 3 import { createResource, createSignal, For, onCleanup, onMount, Show } from "solid-js"; 4 4 import { isTouchDevice } from "../layout"; 5 - import { appHandleLink, appList, appName, AppUrl } from "../utils/app-urls"; 5 + import { appHandleLink, appList } from "../utils/app-urls"; 6 6 import { createDebouncedValue } from "../utils/hooks/debounced"; 7 - import { Modal } from "./modal"; 8 7 9 8 export const [showSearch, setShowSearch] = createSignal(false); 10 9 ··· 68 67 input = input.trim().replace(/^@/, ""); 69 68 if (!input.length) return; 70 69 setShowSearch(false); 71 - if (search()?.length) { 70 + if (input === "me" && localStorage.getItem("lastSignedIn") !== null) { 71 + navigate(`/at://${localStorage.getItem("lastSignedIn")}`); 72 + } else if (search()?.length) { 72 73 navigate(`/at://${search()![0].did}`); 73 74 } else if (input.startsWith("https://") || input.startsWith("http://")) { 74 75 const hostLength = input.indexOf("/", 8); ··· 77 78 if (!(host in appList)) { 78 79 navigate(`/${input.replace("https://", "").replace("http://", "").replace("/", "")}`); 79 80 } else { 80 - const app = appList[host as AppUrl]; 81 + const app = appList[host as keyof typeof appList]; 81 82 const path = input.slice(hostLength + 1).split("/"); 82 83 83 84 const uri = appHandleLink[app](path); ··· 86 87 } else { 87 88 navigate(`/at://${input.replace("at://", "")}`); 88 89 } 90 + setShowSearch(false); 89 91 }; 90 92 91 93 return ( ··· 114 116 value={input() ?? ""} 115 117 onInput={(e) => setInput(e.currentTarget.value)} 116 118 /> 117 - <Show when={input()} fallback={ListUrlsTooltip()}> 119 + <Show when={input()}> 118 120 <button 119 121 type="button" 120 122 class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-600 dark:active:bg-neutral-500" ··· 144 146 </div> 145 147 </Show> 146 148 </form> 147 - ); 148 - }; 149 - 150 - const ListUrlsTooltip = () => { 151 - const [openList, setOpenList] = createSignal(false); 152 - 153 - let urls: Record<string, AppUrl[]> = {}; 154 - for (const [appUrl, appView] of Object.entries(appList)) { 155 - if (!urls[appView]) urls[appView] = [appUrl as AppUrl]; 156 - else urls[appView].push(appUrl as AppUrl); 157 - } 158 - 159 - return ( 160 - <> 161 - <Modal open={openList()} onClose={() => setOpenList(false)}> 162 - <div class="dark:bg-dark-300 dark:shadow-dark-800 absolute top-16 left-[50%] w-[26rem] -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"> 163 - <div class="mb-2 flex items-center gap-1 font-semibold"> 164 - <span class="iconify lucide--link"></span> 165 - <span>Supported URLs</span> 166 - </div> 167 - <div class="mb-2 text-sm text-neutral-500 dark:text-neutral-400"> 168 - Links that will be parsed automatically, as long as all the data necessary is on the 169 - URL. 170 - </div> 171 - <div class="flex flex-col gap-2 text-sm"> 172 - <For each={Object.entries(appName)}> 173 - {([appView, name]) => { 174 - return ( 175 - <div> 176 - <p class="font-semibold">{name}</p> 177 - <div class="grid grid-cols-2 gap-x-4 text-neutral-600 dark:text-neutral-400"> 178 - <For each={urls[appView]}>{(url) => <span>{url}</span>}</For> 179 - </div> 180 - </div> 181 - ); 182 - }} 183 - </For> 184 - </div> 185 - </div> 186 - </Modal> 187 - <button 188 - type="button" 189 - class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-600 dark:active:bg-neutral-500" 190 - onClick={() => setOpenList(true)} 191 - > 192 - <span class="iconify lucide--help-circle"></span> 193 - </button> 194 - </> 195 149 ); 196 150 }; 197 151
+10 -17
src/utils/app-urls.ts
··· 1 1 export type AppUrl = `${string}.${string}` | `localhost:${number}`; 2 + type AppUrlObject = Record<AppUrl, App>; 3 + type AppHandleLinkObject = Record<App, (url: string[]) => string>; 2 4 3 5 export enum App { 4 - Bluesky, 5 - Tangled, 6 - Whitewind, 7 - Frontpage, 8 - Pinksea, 9 - Linkat, 6 + Bluesky = 0, 7 + Tangled = 1, 8 + Whitewind = 2, 9 + Frontpage = 3, 10 + Pinksea = 4, 11 + Linkat = 5, 10 12 } 11 13 12 - export const appName = { 13 - [App.Bluesky]: "Bluesky", 14 - [App.Tangled]: "Tangled", 15 - [App.Whitewind]: "Whitewind", 16 - [App.Frontpage]: "Frontpage", 17 - [App.Pinksea]: "Pinksea", 18 - [App.Linkat]: "Linkat", 19 - }; 20 - 21 - export const appList: Record<AppUrl, App> = { 14 + export const appList: AppUrlObject = { 22 15 "localhost:19006": App.Bluesky, 23 16 "blacksky.community": App.Bluesky, 24 17 "bsky.app": App.Bluesky, ··· 35 28 "linkat.blue": App.Linkat, 36 29 }; 37 30 38 - export const appHandleLink: Record<App, (url: string[]) => string> = { 31 + export const appHandleLink: AppHandleLinkObject = { 39 32 [App.Bluesky]: (path) => { 40 33 const baseType = path[0]; 41 34 const user = path[1];
+1 -1
src/views/collection.tsx
··· 41 41 42 42 return ( 43 43 <span 44 - class="relative flex w-full min-w-0 items-baseline rounded px-0.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 44 + class="relative flex w-full items-baseline rounded px-0.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 45 45 ref={rkeyRef} 46 46 onmouseover={() => setHover(true)} 47 47 onmouseleave={() => setHover(false)}
+19 -11
src/views/record.tsx
··· 10 10 import { JSONValue } from "../components/json.jsx"; 11 11 import { agent } from "../components/login.jsx"; 12 12 import { Modal } from "../components/modal.jsx"; 13 - import { pds } from "../components/navbar.jsx"; 13 + import { pds, setCID } from "../components/navbar.jsx"; 14 14 import Tooltip from "../components/tooltip.jsx"; 15 15 import { setNotif } from "../layout.jsx"; 16 16 import { didDocCache, resolveLexiconAuthority, resolvePDS } from "../utils/api.js"; ··· 34 34 let rpc: Client; 35 35 36 36 const fetchRecord = async () => { 37 + setCID(undefined); 37 38 setValidRecord(undefined); 38 39 setValidSchema(undefined); 39 40 setLexiconUri(undefined); ··· 51 52 setNotice(res.data.error); 52 53 throw new Error(res.data.error); 53 54 } 55 + setCID(res.data.cid); 54 56 setExternalLink(checkUri(res.data.uri, res.data.value)); 55 57 resolveLexicon(params.collection as Nsid); 56 58 verify(res.data); ··· 196 198 label="Copy record" 197 199 icon="lucide--copy" 198 200 /> 199 - <Show when={record()?.cid}> 200 - {(cid) => <CopyMenu copyContent={cid()} label="Copy CID" icon="lucide--copy" />} 201 - </Show> 202 - <Show when={lexiconUri()}> 203 - <NavMenu 204 - href={`/${lexiconUri()}`} 205 - icon="lucide--scroll-text" 206 - label="Lexicon schema" 207 - /> 208 - </Show> 209 201 <Show when={externalLink()}> 210 202 {(externalLink) => ( 211 203 <NavMenu ··· 288 280 <span 289 281 class={`iconify ${validSchema() ? "lucide--check text-green-500 dark:text-green-400" : "lucide--x text-red-500 dark:text-red-400"}`} 290 282 ></span> 283 + </div> 284 + </Show> 285 + <Show when={lexiconUri()}> 286 + <div> 287 + <div class="flex items-center gap-1"> 288 + <span class="iconify lucide--scroll-text"></span> 289 + <p class="font-semibold">Lexicon document</p> 290 + </div> 291 + <div class="truncate text-xs"> 292 + <A 293 + href={`/${lexiconUri()}`} 294 + class="text-blue-400 hover:underline active:underline" 295 + > 296 + {lexiconUri()} 297 + </A> 298 + </div> 291 299 </div> 292 300 </Show> 293 301 </div>