forked from pdsls.dev/pdsls
this repo has no description
at main 9.8 kB view raw
1import { A, Params, useLocation } from "@solidjs/router"; 2import Tooltip from "./tooltip"; 3import { createEffect, createSignal, Show } from "solid-js"; 4import { didDocCache, labelerCache, validateHandle } from "../utils/api"; 5import { setShowHandle, showHandle } from "./settings"; 6import { Did, Handle } from "@atcute/lexicons"; 7import { addToClipboard } from "../utils/copy"; 8 9export const [pds, setPDS] = createSignal<string>(); 10export const [cid, setCID] = createSignal<string>(); 11export const [isLabeler, setIsLabeler] = createSignal(false); 12export const [validRecord, setValidRecord] = createSignal<boolean | undefined>(undefined); 13export const [validSchema, setValidSchema] = createSignal<boolean | undefined>(undefined); 14 15const swapIcons: Record<string, string> = { 16 "did:plc:vwzwgnygau7ed7b7wt5ux7y2": "i-lucide-microchip", 17 "did:plc:oisofpd7lj26yvgiivf3lxsi": "i-lucide-bone", 18 "did:plc:uu5axsmbm2or2dngy4gwchec": "i-lucide-train-track", 19 "did:plc:7x6rtuenkuvxq3zsvffp2ide": "i-lucide-rabbit", 20 "did:plc:ia76kvnndjutgedggx2ibrem": "i-lucide-rabbit", 21 "did:plc:5rowvb4jjbm26fdkx6a5rxls": "i-lucide-rabbit", 22 "did:plc:hdhoaan3xa3jiuq4fg4mefid": "i-lucide-lab-shark", 23 "did:plc:hvakvedv6byxhufjl23mfmsd": "i-lucide-rat", 24 "did:plc:ezhjhbzqt32bqprrn6qjlkri": "i-lucide-film", 25 "did:plc:6v6jqsy7swpzuu53rmzaybjy": "i-lucide-fish", 26 "did:plc:hx53snho72xoj7zqt5uice4u": "i-lucide-lab-flower-rose-single", 27 "did:plc:wzsilnxf24ehtmmc3gssy5bu": "i-lucide-music-2", 28 "did:plc:bnqkww7bjxaacajzvu5gswdf": "i-lucide-gem", 29 "did:plc:pm6jxakrtzmkorra62cr43kr": "i-lucide-flag", 30 "did:plc:355lbopbpckczt672hss2ra4": "i-lucide-lab-basketball", 31 "did:plc:44ybard66vv44zksje25o7dz": "i-lucide-mountain-snow", 32 "did:plc:q6gjnaw2blty4crticxkmujt": "i-lucide-cat", 33 "did:plc:oky5czdrnfjpqslsw2a5iclo": "i-tabler-brand-bluesky", 34}; 35 36const NavBar = (props: { params: Params }) => { 37 const location = useLocation(); 38 const [handle, setHandle] = createSignal(props.params.repo); 39 const [validHandle, setValidHandle] = createSignal<boolean | undefined>(undefined); 40 const [fullCid, setFullCid] = createSignal(false); 41 42 createEffect(() => { 43 if (cid() !== undefined) setFullCid(false); 44 }); 45 46 createEffect(async () => { 47 if (pds() !== undefined && props.params.repo) { 48 const hdl = 49 didDocCache[props.params.repo]?.alsoKnownAs 50 ?.filter((alias) => alias.startsWith("at://"))[0] 51 .split("at://")[1] ?? props.params.repo; 52 if (hdl !== handle()) { 53 setValidHandle(undefined); 54 setHandle(hdl); 55 setValidHandle(await validateHandle(hdl as Handle, props.params.repo as Did)); 56 } 57 } 58 }); 59 60 return ( 61 <div class="break-anywhere mt-4 flex w-[21rem] flex-col font-mono text-sm sm:w-[24rem]"> 62 <div class="relative flex items-center justify-between gap-1"> 63 <div class="min-h-1.25rem flex basis-full items-center gap-2"> 64 <Tooltip text="PDS"> 65 <button onclick={() => addToClipboard(pds()!)}> 66 <div class="i-lucide-server shrink-0 text-lg" /> 67 </button> 68 </Tooltip> 69 <Show when={pds()}> 70 <Show when={props.params.repo}> 71 <A end href={pds()!} inactiveClass="text-blue-400 w-full hover:underline"> 72 {pds()} 73 </A> 74 </Show> 75 <Show when={!props.params.repo}> 76 <span>{pds()}</span> 77 </Show> 78 </Show> 79 </div> 80 <Tooltip 81 text={`Copy ${ 82 props.params.collection ? "AT URI" 83 : props.params.repo ? "DID" 84 : "PDS" 85 }`} 86 > 87 <button 88 onclick={() => 89 addToClipboard( 90 props.params.collection ? 91 `at://${props.params.repo}/${props.params.collection}${props.params.rkey ? `/${props.params.rkey}` : ""}` 92 : props.params.repo ? props.params.repo 93 : pds()!, 94 ) 95 } 96 > 97 <div class="i-lucide-copy shrink-0 text-lg" /> 98 </button> 99 </Tooltip> 100 </div> 101 <div class="flex flex-col flex-wrap"> 102 <Show when={props.params.repo}> 103 <div> 104 <div class="relative mt-1 flex items-center justify-between gap-1"> 105 <div class="flex basis-full items-center gap-2"> 106 <Tooltip text="Repository"> 107 <button onclick={() => addToClipboard(props.params.repo)}> 108 <div class="i-lucide-at-sign text-lg" /> 109 </button> 110 </Tooltip> 111 <div class="flex gap-1"> 112 {props.params.collection || location.pathname.includes("/labels") ? 113 <A 114 end 115 href={`/at://${props.params.repo}`} 116 inactiveClass="text-blue-400 hover:underline" 117 > 118 {showHandle() ? handle() : props.params.repo} 119 </A> 120 : <span>{showHandle() ? handle() : props.params.repo}</span>} 121 <Show when={showHandle()}> 122 <Tooltip 123 text={ 124 validHandle() === true ? "Valid handle" 125 : validHandle() === undefined ? 126 "Validating" 127 : "Invalid handle" 128 } 129 > 130 <div 131 classList={{ 132 "i-lucide-circle-check": validHandle() === true, 133 "i-lucide-circle-x text-red-500 dark:text-red-400": 134 validHandle() === false, 135 "i-lucide-loader-circle animate-spin": validHandle() === undefined, 136 }} 137 /> 138 </Tooltip> 139 </Show> 140 </div> 141 </div> 142 <Tooltip text={showHandle() ? "Show DID" : "Show Handle"}> 143 <button onclick={() => setShowHandle(!showHandle())}> 144 <div 145 class={ 146 "shrink-0 text-lg " + 147 (swapIcons[props.params.repo] ?? "i-lucide-arrow-left-right") 148 } 149 /> 150 </button> 151 </Tooltip> 152 </div> 153 <Show when={props.params.repo in labelerCache && !props.params.collection}> 154 <div class="mt-1 flex items-center gap-2"> 155 <div class="i-lucide-tag text-lg" /> 156 <A 157 end 158 href={`/at://${props.params.repo}/labels`} 159 inactiveClass="text-blue-400 grow hover:underline" 160 > 161 labels 162 </A> 163 </div> 164 </Show> 165 </div> 166 </Show> 167 <Show when={props.params.collection}> 168 <div class="mt-1 flex items-center gap-2"> 169 <Tooltip text="Collection"> 170 <button onclick={() => addToClipboard(props.params.collection)}> 171 <div class="i-lucide-list text-lg" /> 172 </button> 173 </Tooltip> 174 <Show when={props.params.rkey}> 175 <A 176 end 177 href={`/at://${props.params.repo}/${props.params.collection}`} 178 inactiveClass="text-blue-400 w-full hover:underline" 179 > 180 {props.params.collection} 181 </A> 182 </Show> 183 <Show when={!props.params.rkey}> 184 <span>{props.params.collection}</span> 185 </Show> 186 </div> 187 </Show> 188 <Show when={props.params.rkey}> 189 <div class="mt-1 flex items-center gap-2"> 190 <Tooltip text="Record"> 191 <button onclick={() => addToClipboard(props.params.rkey)}> 192 <div class="i-lucide-braces text-lg" /> 193 </button> 194 </Tooltip> 195 <div class="flex gap-1"> 196 <span>{props.params.rkey}</span> 197 <Show when={validRecord()}> 198 <Tooltip text="Valid record"> 199 <div class="i-lucide-lock-keyhole" /> 200 </Tooltip> 201 </Show> 202 <Show when={validRecord() === false}> 203 <Tooltip text="Invalid record"> 204 <div class="i-lucide-lock-keyhole-open text-red-500 dark:text-red-400" /> 205 </Tooltip> 206 </Show> 207 <Show when={validRecord() === undefined}> 208 <Tooltip text="Validating"> 209 <div class="i-lucide-loader-circle animate-spin" /> 210 </Tooltip> 211 </Show> 212 <Show when={validSchema()}> 213 <Tooltip text="Valid schema"> 214 <div class="i-lucide-file-check" /> 215 </Tooltip> 216 </Show> 217 <Show when={validSchema() === false}> 218 <Tooltip text="Invalid schema"> 219 <div class="i-lucide-file-x text-red-500 dark:text-red-400" /> 220 </Tooltip> 221 </Show> 222 </div> 223 </div> 224 </Show> 225 </div> 226 <Show when={props.params.rkey && cid()}> 227 {(cid) => ( 228 <div class="mt-1 flex gap-2"> 229 <Tooltip text="CID"> 230 <button onclick={() => addToClipboard(cid())}> 231 <div class="i-lucide-box text-lg" /> 232 </button> 233 </Tooltip> 234 <button 235 dir="rtl" 236 classList={{ "bg-transparent text-left": true, truncate: !fullCid() }} 237 onclick={() => setFullCid(!fullCid())} 238 > 239 {cid()} 240 </button> 241 </div> 242 )} 243 </Show> 244 </div> 245 ); 246}; 247 248export { NavBar };