atmosphere explorer pds.ls
tool typescript atproto
437
fork

Configure Feed

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

fix routing transitions

juliet.paris db7ee22b 09c36a6a

verified
+45 -45
+37 -42
src/components/navbar.tsx
··· 1 1 import * as TID from "@atcute/tid"; 2 - import { A, Params } from "@solidjs/router"; 2 + import { A, useParams } from "@solidjs/router"; 3 3 import { createEffect, createMemo, createSignal, JSX, Match, Show, Switch } from "solid-js"; 4 4 import { canHover } from "../layout"; 5 5 import { didDocCache } from "../lib/api"; ··· 85 85 ); 86 86 }; 87 87 88 - export const NavBar = (props: { params: Params }) => { 89 - const [handle, setHandle] = createSignal(props.params.repo); 88 + export const NavBar = () => { 89 + const params = useParams(); 90 + const [handle, setHandle] = createSignal(params.repo); 90 91 const [pdsHovered, setPdsHovered] = createSignal(false); 91 92 const [repoHovered, setRepoHovered] = createSignal(false); 92 93 const [collectionHovered, setCollectionHovered] = createSignal(false); 93 94 const isCustomDomain = () => handle() && !handle()!.endsWith(".bsky.social"); 94 95 95 96 createEffect(() => { 96 - if (pds() !== undefined && props.params.repo) { 97 - const hdl = 98 - didDocCache[props.params.repo]?.alsoKnownAs 99 - ?.filter((alias) => alias.startsWith("at://"))[0] 100 - ?.split("at://")[1] ?? props.params.repo; 101 - if (hdl !== handle()) setHandle(hdl); 102 - } 97 + pds(); 98 + if (!params.repo) return; 99 + const hdl = 100 + didDocCache[params.repo]?.alsoKnownAs 101 + ?.filter((alias) => alias.startsWith("at://"))[0] 102 + ?.split("at://")[1] ?? params.repo; 103 + setHandle(hdl); 103 104 }); 104 105 105 106 const rkeyTimestamp = createMemo(() => { 106 - if (!props.params.rkey || !TID.validate(props.params.rkey)) return undefined; 107 - const timestamp = TID.parse(props.params.rkey).timestamp / 1000; 107 + if (!params.rkey || !TID.validate(params.rkey)) return undefined; 108 + const timestamp = TID.parse(params.rkey).timestamp / 1000; 108 109 return timestamp <= Date.now() ? timestamp : undefined; 109 110 }); 110 111 ··· 130 131 classList={{ 131 132 "iconify shrink-0 transition-colors duration-200": true, 132 133 "lucide--unplug text-red-500 dark:text-red-400": 133 - pds() === "Missing PDS" && props.params.repo?.startsWith("did:"), 134 + pds() === "Missing PDS" && params.repo?.startsWith("did:"), 134 135 "lucide--hard-drive text-neutral-500 group-hover:text-neutral-700 dark:text-neutral-400 dark:group-hover:text-neutral-200": 135 - pds() !== "Missing PDS" || !props.params.repo?.startsWith("did:"), 136 + pds() !== "Missing PDS" || !params.repo?.startsWith("did:"), 136 137 }} 137 138 ></span> 138 139 </HoverFavicon> 139 140 </Tooltip> 140 - <Show when={pds() && (pds() !== "Missing PDS" || props.params.repo?.startsWith("did:"))}> 141 + <Show when={pds() && (pds() !== "Missing PDS" || params.repo?.startsWith("did:"))}> 141 142 <Show 142 143 when={pds() === "Missing PDS"} 143 144 fallback={ 144 - <Show 145 - when={props.params.repo} 146 - fallback={<span class="py-0.5 font-medium">{pds()}</span>} 147 - > 145 + <Show when={params.repo} fallback={<span class="py-0.5 font-medium">{pds()}</span>}> 148 146 <A 149 147 end 150 148 href={pds()!} ··· 165 163 </div> 166 164 167 165 <div class="flex flex-col"> 168 - <Show when={props.params.repo}> 166 + <Show when={params.repo}> 169 167 {/* Repository Level */} 170 168 <div 171 169 class="group relative flex items-center justify-between gap-1 rounded-md border-[0.5px] border-transparent bg-transparent px-2 transition-all duration-200 hover:border-neutral-300 hover:bg-neutral-50/40 dark:hover:border-neutral-600 dark:hover:bg-neutral-800/40" ··· 183 181 </HoverFavicon> 184 182 </Tooltip> 185 183 <Show 186 - when={props.params.collection} 184 + when={params.collection} 187 185 fallback={ 188 186 <span class="flex min-w-0 gap-1 py-0.5 font-medium"> 189 187 <Show 190 - when={handle() !== props.params.repo} 191 - fallback={<span class="truncate">{props.params.repo}</span>} 188 + when={handle() !== params.repo} 189 + fallback={<span class="truncate">{params.repo}</span>} 192 190 > 193 191 <span class="max-w-full shrink-0 truncate">{handle()}</span> 194 192 <span class="truncate text-neutral-500 dark:text-neutral-400"> 195 - ({props.params.repo}) 193 + ({params.repo}) 196 194 </span> 197 195 </Show> 198 196 </span> ··· 200 198 > 201 199 <A 202 200 end 203 - href={`/at://${props.params.repo}`} 201 + href={`/at://${params.repo}`} 204 202 inactiveClass="flex grow min-w-0 gap-1 py-0.5 font-medium text-blue-500 hover:text-blue-600 transition-colors duration-150 dark:text-blue-400 dark:hover:text-blue-300" 205 203 > 206 204 <Show 207 - when={handle() !== props.params.repo} 208 - fallback={<span class="truncate">{props.params.repo}</span>} 205 + when={handle() !== params.repo} 206 + fallback={<span class="truncate">{params.repo}</span>} 209 207 > 210 208 <span class="max-w-full shrink-0 truncate">{handle()}</span> 211 - <span class="truncate">({props.params.repo})</span> 209 + <span class="truncate">({params.repo})</span> 212 210 </Show> 213 211 </A> 214 212 </Show> 215 213 </div> 216 - <CopyButton content={props.params.repo!} label="Copy DID" /> 214 + <CopyButton content={params.repo!} label="Copy DID" /> 217 215 </div> 218 216 </Show> 219 217 220 218 {/* Collection Level */} 221 - <Show when={props.params.collection}> 219 + <Show when={params.collection}> 222 220 <div 223 221 class="group flex items-center justify-between gap-2 rounded-md border-[0.5px] border-transparent bg-transparent px-2 transition-all duration-200 hover:border-neutral-300 hover:bg-neutral-50/40 dark:hover:border-neutral-600 dark:hover:bg-neutral-800/40" 224 222 onMouseEnter={() => { ··· 231 229 <div class="flex basis-full items-center gap-2"> 232 230 <Tooltip text="Collection"> 233 231 <HoverFavicon 234 - domain={props.params.collection!.split(".").slice(0, 2).reverse().join(".")} 232 + domain={params.collection!.split(".").slice(0, 2).reverse().join(".")} 235 233 hovered={collectionHovered()} 236 234 > 237 235 <span class="iconify lucide--folder-open text-neutral-500 transition-colors duration-200 group-hover:text-neutral-700 dark:text-neutral-400 dark:group-hover:text-neutral-200"></span> 238 236 </HoverFavicon> 239 237 </Tooltip> 240 238 <Show 241 - when={props.params.rkey} 242 - fallback={<span class="py-0.5 font-medium">{props.params.collection}</span>} 239 + when={params.rkey} 240 + fallback={<span class="py-0.5 font-medium">{params.collection}</span>} 243 241 > 244 242 <A 245 243 end 246 - href={`/at://${props.params.repo}/${props.params.collection}`} 244 + href={`/at://${params.repo}/${params.collection}`} 247 245 inactiveClass="text-blue-500 dark:text-blue-400 grow py-0.5 font-medium hover:text-blue-600 transition-colors duration-150 dark:hover:text-blue-300" 248 246 > 249 - {props.params.collection} 247 + {params.collection} 250 248 </A> 251 249 </Show> 252 250 </div> 253 - <CopyButton 254 - content={`at://${props.params.repo}/${props.params.collection}`} 255 - label="Copy AT URI" 256 - /> 251 + <CopyButton content={`at://${params.repo}/${params.collection}`} label="Copy AT URI" /> 257 252 </div> 258 253 </Show> 259 254 260 255 {/* Record Level */} 261 - <Show when={props.params.rkey}> 256 + <Show when={params.rkey}> 262 257 <div class="group flex items-center justify-between gap-2 rounded-md border-[0.5px] border-transparent bg-transparent px-2 transition-all duration-200 hover:border-neutral-300 hover:bg-neutral-50/40 dark:hover:border-neutral-600 dark:hover:bg-neutral-800/40"> 263 258 <div class="flex basis-full items-center gap-2"> 264 259 <Tooltip text="Record"> 265 260 <span class="iconify lucide--file-json text-neutral-500 transition-colors duration-200 group-hover:text-neutral-700 dark:text-neutral-400 dark:group-hover:text-neutral-200"></span> 266 261 </Tooltip> 267 262 <div class="flex min-w-0 gap-1 py-0.5 font-medium"> 268 - <span>{props.params.rkey}</span> 263 + <span>{params.rkey}</span> 269 264 <Show when={rkeyTimestamp()}> 270 265 <span class="truncate text-neutral-500 dark:text-neutral-400"> 271 266 ({localDateFromTimestamp(rkeyTimestamp()!)}) ··· 274 269 </div> 275 270 </div> 276 271 <CopyButton 277 - content={`at://${props.params.repo}/${props.params.collection}/${props.params.rkey}`} 272 + content={`at://${params.repo}/${params.collection}/${params.rkey}`} 278 273 label="Copy AT URI" 279 274 /> 280 275 </div>
+8 -3
src/layout.tsx
··· 1 - import { A, RouteSectionProps, useLocation, useNavigate } from "@solidjs/router"; 1 + import { A, RouteSectionProps, useIsRouting, useLocation, useNavigate } from "@solidjs/router"; 2 2 import { createEffect, ErrorBoundary, on, onCleanup, onMount, Show, Suspense } from "solid-js"; 3 3 import { AccountManager } from "./auth/account.jsx"; 4 4 import { agent } from "./auth/state.js"; ··· 27 27 const Layout = (props: RouteSectionProps<unknown>) => { 28 28 const location = useLocation(); 29 29 const navigate = useNavigate(); 30 + const isRouting = useIsRouting(); 30 31 31 32 if (location.search.includes("hrt=true")) localStorage.setItem("hrt", "true"); 32 33 else if (location.search.includes("hrt=false")) localStorage.setItem("hrt", "false"); ··· 158 159 <div class="flex w-full flex-col items-center gap-3 text-pretty"> 159 160 <Search /> 160 161 <Show when={props.params.pds}> 161 - <NavBar params={props.params} /> 162 + <NavBar /> 162 163 </Show> 163 164 <ErrorBoundary 164 165 fallback={(err, reset) => { ··· 172 173 return <div class="mt-3 wrap-anywhere">Error: {err.message}</div>; 173 174 }} 174 175 > 175 - <Suspense fallback={<Spinner />}>{props.children}</Suspense> 176 + <Suspense fallback={<Spinner />}> 177 + <Show when={!isRouting()} fallback={<Spinner />}> 178 + {props.children} 179 + </Show> 180 + </Suspense> 176 181 </ErrorBoundary> 177 182 </div> 178 183 <NotificationContainer />