atmosphere explorer
0
fork

Configure Feed

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

remove solidjs/meta

Juliet b54f5474 8b1b98ca

+224 -253
-1
package.json
··· 51 51 "@mary/exif-rm": "jsr:^0.2.2", 52 52 "@mary/zip": "jsr:^0.1.1", 53 53 "@skyware/firehose": "^0.5.2", 54 - "@solidjs/meta": "^0.29.4", 55 54 "@solidjs/router": "^0.15.4", 56 55 "@takumi-rs/image-response": "^0.72.0", 57 56 "@takumi-rs/wasm": "^0.72.0",
-12
pnpm-lock.yaml
··· 89 89 '@skyware/firehose': 90 90 specifier: ^0.5.2 91 91 version: 0.5.2 92 - '@solidjs/meta': 93 - specifier: ^0.29.4 94 - version: 0.29.4(solid-js@1.9.11) 95 92 '@solidjs/router': 96 93 specifier: ^0.15.4 97 94 version: 0.15.4(solid-js@1.9.11) ··· 860 857 861 858 '@skyware/firehose@0.5.2': 862 859 resolution: {integrity: sha512-Ayg/cF0BkakBNQVA51ClDka0+nC96WiARNrGElMQxfqbwao0PBaCXkunfr8qS4DWS3TqLnR6hA9mvm1vAYlxJQ==} 863 - 864 - '@solidjs/meta@0.29.4': 865 - resolution: {integrity: sha512-zdIWBGpR9zGx1p1bzIPqF5Gs+Ks/BH8R6fWhmUa/dcK1L2rUC8BAcZJzNRYBQv74kScf1TSOs0EY//Vd/I0V8g==} 866 - peerDependencies: 867 - solid-js: '>=1.8.4' 868 860 869 861 '@solidjs/router@0.15.4': 870 862 resolution: {integrity: sha512-WOpgg9a9T638cR+5FGbFi/IV4l2FpmBs1GpIMSPa0Ce9vyJN7Wts+X2PqMf9IYn0zUj2MlSJtm1gp7/HI/n5TQ==} ··· 2328 2320 '@atcute/car': 3.1.3 2329 2321 '@atcute/cbor': 2.3.2 2330 2322 nanoevents: 9.1.0 2331 - 2332 - '@solidjs/meta@0.29.4(solid-js@1.9.11)': 2333 - dependencies: 2334 - solid-js: 1.9.11 2335 2323 2336 2324 '@solidjs/router@0.15.4(solid-js@1.9.11)': 2337 2325 dependencies:
+70 -77
src/layout.tsx
··· 1 1 import { Handle } from "@atcute/lexicons"; 2 - import { Meta, MetaProvider, Title } from "@solidjs/meta"; 3 2 import { A, RouteSectionProps, useLocation, useNavigate } from "@solidjs/router"; 4 3 import { createEffect, ErrorBoundary, onCleanup, onMount, Show, Suspense } from "solid-js"; 5 4 import { AccountManager } from "./auth/account.jsx"; ··· 117 116 }); 118 117 119 118 return ( 120 - <MetaProvider> 121 - <Title>PDSls</Title> 122 - <Show when={location.pathname !== "/"}> 123 - <Meta name="robots" content="noindex, nofollow" /> 124 - </Show> 125 - <div id="main" class="mx-auto mb-8 flex max-w-lg flex-col items-center p-3"> 126 - <header 127 - class={`dark:shadow-dark-700 mb-3 flex h-13 w-full items-center justify-between rounded-xl border-[0.5px] border-neutral-300 bg-neutral-50 bg-size-[95%] bg-right bg-no-repeat p-2 pl-3 shadow-xs [--header-bg:#fafafa] [--trans-blue:#5BCEFA90] [--trans-pink:#F5A9B890] [--trans-white:#FFFFFF90] dark:border-neutral-700 dark:bg-neutral-800 dark:[--header-bg:#262626] dark:[--trans-blue:#5BCEFAa0] dark:[--trans-pink:#F5A9B8a0] dark:[--trans-white:#FFFFFFa0] ${localStorage.getItem("hrt") === "true" ? "bg-[linear-gradient(to_left,transparent_10%,var(--header-bg)_85%),linear-gradient(to_bottom,var(--trans-blue)_0%,var(--trans-blue)_20%,var(--trans-pink)_20%,var(--trans-pink)_40%,var(--trans-white)_40%,var(--trans-white)_60%,var(--trans-pink)_60%,var(--trans-pink)_80%,var(--trans-blue)_80%,var(--trans-blue)_100%)]" : ""}`} 128 - style={{ 129 - "background-image": 130 - props.params.repo && props.params.repo in headers ? 131 - `linear-gradient(to left, transparent 20%, var(--header-bg) 85%), url(/headers/${headers[props.params.repo]})` 132 - : undefined, 133 - }} 119 + <div id="main" class="mx-auto mb-8 flex max-w-lg flex-col items-center p-3"> 120 + <header 121 + class={`dark:shadow-dark-700 mb-3 flex h-13 w-full items-center justify-between rounded-xl border-[0.5px] border-neutral-300 bg-neutral-50 bg-size-[95%] bg-right bg-no-repeat p-2 pl-3 shadow-xs [--header-bg:#fafafa] [--trans-blue:#5BCEFA90] [--trans-pink:#F5A9B890] [--trans-white:#FFFFFF90] dark:border-neutral-700 dark:bg-neutral-800 dark:[--header-bg:#262626] dark:[--trans-blue:#5BCEFAa0] dark:[--trans-pink:#F5A9B8a0] dark:[--trans-white:#FFFFFFa0] ${localStorage.getItem("hrt") === "true" ? "bg-[linear-gradient(to_left,transparent_10%,var(--header-bg)_85%),linear-gradient(to_bottom,var(--trans-blue)_0%,var(--trans-blue)_20%,var(--trans-pink)_20%,var(--trans-pink)_40%,var(--trans-white)_40%,var(--trans-white)_60%,var(--trans-pink)_60%,var(--trans-pink)_80%,var(--trans-blue)_80%,var(--trans-blue)_100%)]" : ""}`} 122 + style={{ 123 + "background-image": 124 + props.params.repo && props.params.repo in headers ? 125 + `linear-gradient(to left, transparent 20%, var(--header-bg) 85%), url(/headers/${headers[props.params.repo]})` 126 + : undefined, 127 + }} 128 + > 129 + <A 130 + href="/" 131 + style='font-feature-settings: "cv05"' 132 + class="relative flex items-center gap-1 text-xl font-semibold" 134 133 > 135 - <A 136 - href="/" 137 - style='font-feature-settings: "cv05"' 138 - class="relative flex items-center gap-1 text-xl font-semibold" 139 - > 140 - <span class="iconify tabler--binary-tree-filled text-[#76c4e5]"></span> 141 - <span>PDSls</span> 142 - <Show when={localStorage.getItem("hrt") === "true"}> 143 - <img 144 - src="/ribbon.webp" 145 - alt="" 146 - class="pointer-events-none absolute -top-3 -right-4 w-8 rotate-15" 147 - /> 148 - </Show> 149 - </A> 150 - <div class="relative flex items-center gap-0.5 rounded-lg bg-neutral-50/60 p-1 dark:bg-neutral-800/60"> 151 - <div class="mr-1"> 152 - <SearchButton /> 153 - </div> 154 - <Show when={agent()}> 155 - <RecordEditor create={true} scope="create" /> 156 - </Show> 157 - <AccountManager /> 158 - <MenuProvider> 159 - <DropdownMenu icon="lucide--menu text-lg" buttonClass="rounded-md p-1.5"> 160 - <NavMenu href="/jetstream" label="Jetstream" icon="lucide--radio-tower" /> 161 - <NavMenu href="/firehose" label="Firehose" icon="lucide--rss" /> 162 - <NavMenu href="/spacedust" label="Spacedust" icon="lucide--sparkles" /> 163 - <MenuSeparator /> 164 - <NavMenu href="/labels" label="Labels" icon="lucide--tag" /> 165 - <NavMenu href="/car" label="Archive tools" icon="lucide--folder-archive" /> 166 - <MenuSeparator /> 167 - <NavMenu href="/settings" label="Settings" icon="lucide--settings" /> 168 - </DropdownMenu> 169 - </MenuProvider> 170 - </div> 171 - </header> 172 - <div class="flex w-full flex-col items-center gap-3 text-pretty"> 173 - <Search /> 174 - <Show when={props.params.pds}> 175 - <NavBar params={props.params} /> 134 + <span class="iconify tabler--binary-tree-filled text-[#76c4e5]"></span> 135 + <span>PDSls</span> 136 + <Show when={localStorage.getItem("hrt") === "true"}> 137 + <img 138 + src="/ribbon.webp" 139 + alt="" 140 + class="pointer-events-none absolute -top-3 -right-4 w-8 rotate-15" 141 + /> 176 142 </Show> 177 - <Show keyed when={location.pathname}> 178 - <ErrorBoundary 179 - fallback={(err) => <div class="mt-3 wrap-anywhere">Error: {err.message}</div>} 180 - > 181 - <Suspense 182 - fallback={ 183 - <span class="iconify lucide--loader-circle mt-3 animate-spin text-xl"></span> 184 - } 185 - > 186 - {props.children} 187 - </Suspense> 188 - </ErrorBoundary> 143 + </A> 144 + <div class="relative flex items-center gap-0.5 rounded-lg bg-neutral-50/60 p-1 dark:bg-neutral-800/60"> 145 + <div class="mr-1"> 146 + <SearchButton /> 147 + </div> 148 + <Show when={agent()}> 149 + <RecordEditor create={true} scope="create" /> 189 150 </Show> 151 + <AccountManager /> 152 + <MenuProvider> 153 + <DropdownMenu icon="lucide--menu text-lg" buttonClass="rounded-md p-1.5"> 154 + <NavMenu href="/jetstream" label="Jetstream" icon="lucide--radio-tower" /> 155 + <NavMenu href="/firehose" label="Firehose" icon="lucide--rss" /> 156 + <NavMenu href="/spacedust" label="Spacedust" icon="lucide--sparkles" /> 157 + <MenuSeparator /> 158 + <NavMenu href="/labels" label="Labels" icon="lucide--tag" /> 159 + <NavMenu href="/car" label="Archive tools" icon="lucide--folder-archive" /> 160 + <MenuSeparator /> 161 + <NavMenu href="/settings" label="Settings" icon="lucide--settings" /> 162 + </DropdownMenu> 163 + </MenuProvider> 190 164 </div> 191 - <NotificationContainer /> 192 - <PermissionPromptContainer /> 193 - <Show when={plcDirectory() !== "https://plc.directory"}> 194 - <div class="dark:bg-dark-500 fixed right-0 bottom-0 left-0 z-10 flex items-center justify-center bg-neutral-100 px-3 py-1 text-xs"> 195 - <span> 196 - PLC directory: <span class="font-medium">{plcDirectory()}</span> 197 - </span> 198 - </div> 165 + </header> 166 + <div class="flex w-full flex-col items-center gap-3 text-pretty"> 167 + <Search /> 168 + <Show when={props.params.pds}> 169 + <NavBar params={props.params} /> 170 + </Show> 171 + <Show keyed when={location.pathname}> 172 + <ErrorBoundary 173 + fallback={(err) => <div class="mt-3 wrap-anywhere">Error: {err.message}</div>} 174 + > 175 + <Suspense 176 + fallback={ 177 + <span class="iconify lucide--loader-circle mt-3 animate-spin text-xl"></span> 178 + } 179 + > 180 + {props.children} 181 + </Suspense> 182 + </ErrorBoundary> 199 183 </Show> 200 184 </div> 201 - </MetaProvider> 185 + <NotificationContainer /> 186 + <PermissionPromptContainer /> 187 + <Show when={plcDirectory() !== "https://plc.directory"}> 188 + <div class="dark:bg-dark-500 fixed right-0 bottom-0 left-0 z-10 flex items-center justify-center bg-neutral-100 px-3 py-1 text-xs"> 189 + <span> 190 + PLC directory: <span class="font-medium">{plcDirectory()}</span> 191 + </span> 192 + </div> 193 + </Show> 194 + </div> 202 195 ); 203 196 }; 204 197
+1 -2
src/views/car/explore.tsx
··· 4 4 import { Did } from "@atcute/lexicons"; 5 5 import { fromStream, isCommit } from "@atcute/repo"; 6 6 import * as TID from "@atcute/tid"; 7 - import { Title } from "@solidjs/meta"; 8 7 import { useLocation, useNavigate } from "@solidjs/router"; 9 8 import { 10 9 createEffect, ··· 188 187 if (location.hash) navigate(location.pathname, { replace: true }); 189 188 }; 190 189 190 + document.title = "Explore archive - PDSls"; 191 191 return ( 192 192 <> 193 - <Title>Explore archive - PDSls</Title> 194 193 <Show 195 194 when={archive()} 196 195 fallback={
+1 -2
src/views/car/index.tsx
··· 1 - import { Title } from "@solidjs/meta"; 2 1 import { A } from "@solidjs/router"; 3 2 4 3 export const CarView = () => { 4 + document.title = "Archive tools - PDSls"; 5 5 return ( 6 6 <div class="flex w-full max-w-3xl flex-col gap-y-4 px-2"> 7 - <Title>Archive tools - PDSls</Title> 8 7 <div class="flex flex-col gap-y-1"> 9 8 <h1 class="text-lg font-semibold">Archive tools</h1> 10 9 <p class="text-sm text-neutral-600 dark:text-neutral-400">
+3 -3
src/views/car/unpack.tsx
··· 1 1 import { fromStream } from "@atcute/repo"; 2 2 import { zip, type ZipEntry } from "@mary/zip"; 3 - import { Title } from "@solidjs/meta"; 4 3 import { createSignal, onCleanup } from "solid-js"; 5 4 import { createDropHandler, createFileChangeHandler, handleDragOver } from "./file-handlers.js"; 6 5 import { createLogger, LoggerView } from "./logger.jsx"; ··· 114 113 115 114 try { 116 115 // eslint-disable-next-line @typescript-eslint/no-explicit-any 117 - const fd = await (window as any).showSaveFilePicker({ 116 + const fd = await (window as any) 117 + .showSaveFilePicker({ 118 118 suggestedName: `${file.name.replace(/\.car$/, "")}.zip`, 119 119 id: "car-unpack", 120 120 startIn: "downloads", ··· 230 230 baseDrop(e); 231 231 }; 232 232 233 + document.title = "Unpack archive - PDSls"; 233 234 return ( 234 235 <> 235 - <Title>Unpack archive - PDSls</Title> 236 236 <WelcomeView 237 237 title="Unpack archive" 238 238 subtitle="Upload a CAR file to extract all records into a ZIP archive."
+2 -2
src/views/collection.tsx
··· 2 2 import { Client, simpleFetchHandler } from "@atcute/client"; 3 3 import { $type, ActorIdentifier, InferXRPCBodyOutput } from "@atcute/lexicons"; 4 4 import * as TID from "@atcute/tid"; 5 - import { Title } from "@solidjs/meta"; 6 5 import { A, useBeforeLeave, useParams, useSearchParams } from "@solidjs/router"; 7 6 import { createMemo, createResource, createSignal, For, onMount, Show } from "solid-js"; 8 7 import { createStore } from "solid-js/store"; ··· 240 239 true, 241 240 ); 242 241 242 + document.title = `${params.collection} - PDSls`; 243 + 243 244 return ( 244 245 <> 245 - <Title>{params.collection} - PDSls</Title> 246 246 <Show when={records.length || response()}> 247 247 <div class="flex w-full flex-col items-center"> 248 248 {/* Tab bar */}
+1
src/views/home.tsx
··· 91 91 </a> 92 92 ); 93 93 94 + document.title = "PDSls"; 94 95 return ( 95 96 <div class="flex w-full flex-col gap-6 px-2 wrap-break-word"> 96 97 {/* Welcome Section */}
+133 -136
src/views/labels.tsx
··· 2 2 import { Client, simpleFetchHandler } from "@atcute/client"; 3 3 import { isAtprotoDid } from "@atcute/identity"; 4 4 import { Handle } from "@atcute/lexicons"; 5 - import { Title } from "@solidjs/meta"; 6 5 import { useSearchParams } from "@solidjs/router"; 7 6 import { createMemo, createSignal, For, onMount, Show } from "solid-js"; 8 7 import { Button } from "../components/button.jsx"; ··· 187 186 fetchLabels(new FormData(formRef)); 188 187 }; 189 188 189 + document.title = "Labels - PDSls"; 190 190 return ( 191 - <> 192 - <Title>Labels - PDSls</Title> 193 - <div class="flex w-full flex-col items-center"> 194 - <div class="flex w-full flex-col gap-y-1 px-3 pb-3"> 195 - <h1 class="text-lg font-semibold">Labels</h1> 196 - <p class="text-sm text-neutral-600 dark:text-neutral-400"> 197 - Query labels applied to accounts and records. 198 - </p> 191 + <div class="flex w-full flex-col items-center"> 192 + <div class="flex w-full flex-col gap-y-1 px-3 pb-3"> 193 + <h1 class="text-lg font-semibold">Labels</h1> 194 + <p class="text-sm text-neutral-600 dark:text-neutral-400"> 195 + Query labels applied to accounts and records. 196 + </p> 197 + </div> 198 + <form 199 + ref={formRef} 200 + class="flex w-full max-w-3xl flex-col gap-y-3 px-3 pb-2" 201 + onSubmit={(e) => { 202 + e.preventDefault(); 203 + handleSearch(); 204 + }} 205 + > 206 + <div class="flex flex-col gap-y-3"> 207 + <label class="flex w-full flex-col gap-y-1"> 208 + <span class="text-sm font-medium text-neutral-700 dark:text-neutral-300"> 209 + Labeler handle or DID 210 + </span> 211 + <TextInput 212 + name="did" 213 + value={didInput()} 214 + onInput={(e) => setDidInput(e.currentTarget.value)} 215 + placeholder="moderation.bsky.app (default)" 216 + class="w-full" 217 + /> 218 + </label> 219 + 220 + <label class="flex w-full flex-col gap-y-1"> 221 + <span class="text-sm font-medium text-neutral-700 dark:text-neutral-300"> 222 + URI patterns (comma-separated) 223 + </span> 224 + <textarea 225 + id="uriPatterns" 226 + name="uriPatterns" 227 + spellcheck={false} 228 + rows={2} 229 + value={searchParams.uriPatterns ?? "*"} 230 + placeholder="at://did:web:example.com/app.bsky.feed.post/*" 231 + class="dark:bg-dark-100 grow rounded-lg bg-white px-2 py-1.5 text-sm outline-1 outline-neutral-200 focus:outline-neutral-400 dark:outline-neutral-600 dark:focus:outline-neutral-400" 232 + /> 233 + </label> 199 234 </div> 200 - <form 201 - ref={formRef} 202 - class="flex w-full max-w-3xl flex-col gap-y-3 px-3 pb-2" 203 - onSubmit={(e) => { 204 - e.preventDefault(); 205 - handleSearch(); 206 - }} 207 - > 208 - <div class="flex flex-col gap-y-3"> 209 - <label class="flex w-full flex-col gap-y-1"> 210 - <span class="text-sm font-medium text-neutral-700 dark:text-neutral-300"> 211 - Labeler handle or DID 212 - </span> 213 - <TextInput 214 - name="did" 215 - value={didInput()} 216 - onInput={(e) => setDidInput(e.currentTarget.value)} 217 - placeholder="moderation.bsky.app (default)" 218 - class="w-full" 219 - /> 220 - </label> 221 235 222 - <label class="flex w-full flex-col gap-y-1"> 223 - <span class="text-sm font-medium text-neutral-700 dark:text-neutral-300"> 224 - URI patterns (comma-separated) 225 - </span> 226 - <textarea 227 - id="uriPatterns" 228 - name="uriPatterns" 229 - spellcheck={false} 230 - rows={2} 231 - value={searchParams.uriPatterns ?? "*"} 232 - placeholder="at://did:web:example.com/app.bsky.feed.post/*" 233 - class="dark:bg-dark-100 grow rounded-lg bg-white px-2 py-1.5 text-sm outline-1 outline-neutral-200 focus:outline-neutral-400 dark:outline-neutral-600 dark:focus:outline-neutral-400" 234 - /> 235 - </label> 236 + <Button type="submit" disabled={loading()} classList={{ "w-fit": true }}> 237 + <span class="iconify lucide--search" /> 238 + <span>Search labels</span> 239 + </Button> 240 + 241 + <Show when={error()}> 242 + <div class="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-800 dark:border-red-800 dark:bg-red-900/20 dark:text-red-300"> 243 + {error()} 236 244 </div> 245 + </Show> 246 + </form> 237 247 238 - <Button type="submit" disabled={loading()} classList={{ "w-fit": true }}> 239 - <span class="iconify lucide--search" /> 240 - <span>Search labels</span> 241 - </Button> 242 - 243 - <Show when={error()}> 244 - <div class="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-800 dark:border-red-800 dark:bg-red-900/20 dark:text-red-300"> 245 - {error()} 248 + <Show when={hasSearched()}> 249 + <div class="w-full max-w-3xl py-2 pb-20"> 250 + <Show when={loading() && labels().length === 0}> 251 + <div class="flex flex-col items-center justify-center py-12 text-center"> 252 + <span class="iconify lucide--loader-circle mb-3 animate-spin text-4xl text-neutral-400" /> 253 + <p class="text-sm text-neutral-600 dark:text-neutral-400">Loading labels...</p> 246 254 </div> 247 255 </Show> 248 - </form> 249 256 250 - <Show when={hasSearched()}> 251 - <div class="w-full max-w-3xl py-2 pb-20"> 252 - <Show when={loading() && labels().length === 0}> 253 - <div class="flex flex-col items-center justify-center py-12 text-center"> 254 - <span class="iconify lucide--loader-circle mb-3 animate-spin text-4xl text-neutral-400" /> 255 - <p class="text-sm text-neutral-600 dark:text-neutral-400">Loading labels...</p> 257 + <Show when={!loading() || labels().length > 0}> 258 + <Show when={filteredLabels().length > 0}> 259 + <div class="grid gap-2"> 260 + <For each={filteredLabels()}>{(label) => <LabelCard label={label} />}</For> 256 261 </div> 257 262 </Show> 258 263 259 - <Show when={!loading() || labels().length > 0}> 260 - <Show when={filteredLabels().length > 0}> 261 - <div class="grid gap-2"> 262 - <For each={filteredLabels()}>{(label) => <LabelCard label={label} />}</For> 263 - </div> 264 - </Show> 264 + <Show when={labels().length > 0 && filteredLabels().length === 0}> 265 + <div class="flex flex-col items-center justify-center py-8 text-center"> 266 + <span class="iconify lucide--search-x mb-2 text-3xl text-neutral-400" /> 267 + <p class="text-sm text-neutral-600 dark:text-neutral-400"> 268 + No labels match your filter 269 + </p> 270 + </div> 271 + </Show> 265 272 266 - <Show when={labels().length > 0 && filteredLabels().length === 0}> 267 - <div class="flex flex-col items-center justify-center py-8 text-center"> 268 - <span class="iconify lucide--search-x mb-2 text-3xl text-neutral-400" /> 269 - <p class="text-sm text-neutral-600 dark:text-neutral-400"> 270 - No labels match your filter 271 - </p> 272 - </div> 273 - </Show> 273 + <Show when={labels().length === 0 && !loading()}> 274 + <div class="flex flex-col items-center justify-center py-8 text-center"> 275 + <span class="iconify lucide--tags mb-2 text-3xl text-neutral-400" /> 276 + <p class="text-sm text-neutral-600 dark:text-neutral-400">No labels found</p> 277 + </div> 278 + </Show> 279 + </Show> 280 + </div> 274 281 275 - <Show when={labels().length === 0 && !loading()}> 276 - <div class="flex flex-col items-center justify-center py-8 text-center"> 277 - <span class="iconify lucide--tags mb-2 text-3xl text-neutral-400" /> 278 - <p class="text-sm text-neutral-600 dark:text-neutral-400">No labels found</p> 279 - </div> 282 + <Show when={labels().length > 1}> 283 + <div class="dark:bg-dark-500 fixed bottom-0 z-10 flex w-full flex-col items-center gap-2 border-t border-neutral-200 bg-neutral-100 px-3 pt-3 pb-6 dark:border-neutral-700"> 284 + <div 285 + class="dark:bg-dark-200 flex w-full max-w-lg cursor-text items-center gap-2 rounded-lg border border-neutral-200 bg-white px-3 dark:border-neutral-700" 286 + onClick={(e) => { 287 + const input = e.currentTarget.querySelector("input"); 288 + if (e.target !== input) input?.focus(); 289 + }} 290 + > 291 + <span class="iconify lucide--filter text-neutral-500 dark:text-neutral-400" /> 292 + <input 293 + ref={filterInputRef} 294 + type="text" 295 + spellcheck={false} 296 + autocapitalize="off" 297 + autocomplete="off" 298 + class="grow py-2 select-none placeholder:text-sm focus:outline-none" 299 + placeholder="Filter labels... (* for partial, -exclude)" 300 + value={filter()} 301 + onInput={(e) => setFilter(e.currentTarget.value)} 302 + /> 303 + <Show when={canHover && !filter()}> 304 + <kbd class="rounded border border-neutral-200 bg-neutral-50 px-1.5 py-0.5 font-mono text-xs text-neutral-400 select-none dark:border-neutral-600 dark:bg-neutral-700"> 305 + / 306 + </kbd> 280 307 </Show> 281 - </Show> 282 - </div> 308 + </div> 283 309 284 - <Show when={labels().length > 1}> 285 - <div class="dark:bg-dark-500 fixed bottom-0 z-10 flex w-full flex-col items-center gap-2 border-t border-neutral-200 bg-neutral-100 px-3 pt-3 pb-6 dark:border-neutral-700"> 286 - <div 287 - class="dark:bg-dark-200 flex w-full max-w-lg cursor-text items-center gap-2 rounded-lg border border-neutral-200 bg-white px-3 dark:border-neutral-700" 288 - onClick={(e) => { 289 - const input = e.currentTarget.querySelector("input"); 290 - if (e.target !== input) input?.focus(); 291 - }} 292 - > 293 - <span class="iconify lucide--filter text-neutral-500 dark:text-neutral-400" /> 294 - <input 295 - ref={filterInputRef} 296 - type="text" 297 - spellcheck={false} 298 - autocapitalize="off" 299 - autocomplete="off" 300 - class="grow py-2 select-none placeholder:text-sm focus:outline-none" 301 - placeholder="Filter labels... (* for partial, -exclude)" 302 - value={filter()} 303 - onInput={(e) => setFilter(e.currentTarget.value)} 304 - /> 305 - <Show when={canHover && !filter()}> 306 - <kbd class="rounded border border-neutral-200 bg-neutral-50 px-1.5 py-0.5 font-mono text-xs text-neutral-400 select-none dark:border-neutral-600 dark:bg-neutral-700"> 307 - / 308 - </kbd> 310 + <div class="flex min-h-7.5 w-full max-w-lg items-center justify-between"> 311 + <div class="w-20" /> 312 + 313 + <div> 314 + <Show when={filter()}> 315 + <span>{filteredLabels().length}</span> 316 + <span>/</span> 309 317 </Show> 318 + <span>{labels().length} labels</span> 310 319 </div> 311 320 312 - <div class="flex min-h-7.5 w-full max-w-lg items-center justify-between"> 313 - <div class="w-20" /> 314 - 315 - <div> 316 - <Show when={filter()}> 317 - <span>{filteredLabels().length}</span> 318 - <span>/</span> 319 - </Show> 320 - <span>{labels().length} labels</span> 321 - </div> 322 - 323 - <div class="flex w-20 items-center justify-end"> 324 - <Show when={cursor()}> 325 - <Button 326 - onClick={handleLoadMore} 327 - disabled={loading()} 328 - classList={{ "w-20 h-7.5 justify-center": true }} 321 + <div class="flex w-20 items-center justify-end"> 322 + <Show when={cursor()}> 323 + <Button 324 + onClick={handleLoadMore} 325 + disabled={loading()} 326 + classList={{ "w-20 h-7.5 justify-center": true }} 327 + > 328 + <Show 329 + when={!loading()} 330 + fallback={ 331 + <span class="iconify lucide--loader-circle animate-spin text-base" /> 332 + } 329 333 > 330 - <Show 331 - when={!loading()} 332 - fallback={ 333 - <span class="iconify lucide--loader-circle animate-spin text-base" /> 334 - } 335 - > 336 - Load more 337 - </Show> 338 - </Button> 339 - </Show> 340 - </div> 334 + Load more 335 + </Show> 336 + </Button> 337 + </Show> 341 338 </div> 342 339 </div> 343 - </Show> 340 + </div> 344 341 </Show> 345 - </div> 346 - </> 342 + </Show> 343 + </div> 347 344 ); 348 345 };
+2 -2
src/views/pds.tsx
··· 2 2 import { Client, simpleFetchHandler } from "@atcute/client"; 3 3 import { InferXRPCBodyOutput } from "@atcute/lexicons"; 4 4 import * as TID from "@atcute/tid"; 5 - import { Title } from "@solidjs/meta"; 6 5 import { A, useLocation, useParams } from "@solidjs/router"; 7 6 import { createResource, createSignal, For, Show } from "solid-js"; 8 7 import { Button } from "../components/button"; ··· 136 135 </A> 137 136 ); 138 137 138 + document.title = `${params.pds} - PDSls`; 139 + 139 140 return ( 140 141 <> 141 - <Title>{params.pds} - PDSls</Title> 142 142 <Show when={repos() || response()}> 143 143 <div class="flex w-full flex-col px-2"> 144 144 <div class="mb-3 flex gap-4 text-sm sm:text-base">
+2 -4
src/views/record.tsx
··· 6 6 import { ActorIdentifier, is, Nsid } from "@atcute/lexicons"; 7 7 import { AtprotoDid, Did, isNsid } from "@atcute/lexicons/syntax"; 8 8 import { verifyRecord } from "@atcute/repo"; 9 - import { Title } from "@solidjs/meta"; 10 9 import { A, useLocation, useNavigate, useParams } from "@solidjs/router"; 11 10 import { createResource, createSignal, ErrorBoundary, For, Show, Suspense } from "solid-js"; 12 11 import { agent } from "../auth/state"; ··· 408 407 ); 409 408 }; 410 409 410 + document.title = `${params.collection}/${params.rkey} - PDSls`; 411 + 411 412 return ( 412 413 <> 413 - <Title> 414 - {params.collection}/{params.rkey} - PDSls 415 - </Title> 416 414 <ErrorBoundary 417 415 fallback={(err) => ( 418 416 <div class="flex w-full flex-col items-center gap-1 px-2 py-4">
+7 -8
src/views/repo.tsx
··· 1 1 import { Client, simpleFetchHandler } from "@atcute/client"; 2 2 import { DidDocument } from "@atcute/identity"; 3 3 import { ActorIdentifier, Did, Handle, Nsid } from "@atcute/lexicons"; 4 - import { Title } from "@solidjs/meta"; 5 4 import { A, useLocation, useNavigate, useParams } from "@solidjs/router"; 6 5 import { 7 6 createEffect, ··· 320 319 setDownloading(false); 321 320 }; 322 321 323 - const getTitle = () => { 324 - const doc = didDoc(); 325 - const handle = doc?.alsoKnownAs 326 - ?.find((alias) => alias.startsWith("at://")) 322 + document.title = `${params.repo} - PDSls`; 323 + 324 + createEffect(() => { 325 + const handle = didDoc() 326 + ?.alsoKnownAs?.find((alias) => alias.startsWith("at://")) 327 327 ?.replace("at://", ""); 328 - return `${handle || params.repo} - PDSls`; 329 - }; 328 + if (handle) document.title = `${handle} - PDSls`; 329 + }); 330 330 331 331 return ( 332 332 <> 333 - <Title>{getTitle()}</Title> 334 333 <Show when={repo()}> 335 334 <div class="flex w-full flex-col gap-3 wrap-break-word"> 336 335 <div class="flex justify-between px-2 text-sm sm:text-base">
+1 -2
src/views/settings.tsx
··· 1 - import { Title } from "@solidjs/meta"; 2 1 import { createSignal } from "solid-js"; 3 2 import { TextInput } from "../components/text-input.jsx"; 4 3 import { ThemeSelection } from "../components/theme.jsx"; ··· 9 8 ); 10 9 11 10 const Settings = () => { 11 + document.title = "Settings - PDSls"; 12 12 return ( 13 13 <div class="flex w-full flex-col gap-2 px-2"> 14 - <Title>Settings - PDSls</Title> 15 14 <div class="text-lg font-semibold">Settings</div> 16 15 <div class="flex flex-col gap-3"> 17 16 <div class="flex flex-col gap-1">
+1 -2
src/views/stream/index.tsx
··· 1 1 import { Firehose } from "@skyware/firehose"; 2 - import { Title } from "@solidjs/meta"; 3 2 import { A, useLocation, useSearchParams } from "@solidjs/router"; 4 3 import { createSignal, For, onCleanup, onMount, Show } from "solid-js"; 5 4 import { Button } from "../../components/button"; ··· 329 328 if (statsUpdateIntervalId !== null) clearInterval(statsUpdateIntervalId); 330 329 }); 331 330 331 + document.title = `${config().label} - PDSls`; 332 332 return ( 333 333 <> 334 - <Title>{config().label} - PDSls</Title> 335 334 <div class="flex w-full flex-col items-center gap-2"> 336 335 {/* Tab Navigation */} 337 336 <div class="flex gap-4 font-medium">