atmosphere explorer

fix rounding

handle.invalid 893336b0 3ee6b8b0

verified
+182 -173
+1 -1
src/auth/account.tsx
··· 196 196 </Modal> 197 197 <button 198 198 onclick={() => setOpenManager(true)} 199 - class={`flex items-center rounded-lg ${agent() && avatars[agent()!.sub] ? "p-1.25" : "p-1.5"} hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600`} 199 + class={`flex items-center rounded-md ${agent() && avatars[agent()!.sub] ? "p-1.25" : "p-1.5"} hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600`} 200 200 > 201 201 {agent() && avatars[agent()!.sub] ? 202 202 <img src={getThumbnailUrl(avatars[agent()!.sub])} class="size-5 rounded-full" />
+2 -2
src/components/create/index.tsx
··· 463 463 <button 464 464 class={ 465 465 hasPermission() ? 466 - `flex items-center p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 ${props.create ? "rounded-lg" : "rounded-sm"}` 467 - : `flex items-center p-1.5 opacity-40 ${props.create ? "rounded-lg" : "rounded-sm"}` 466 + `flex items-center p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 ${props.create ? "rounded-md" : "rounded-sm"}` 467 + : `flex items-center p-1.5 opacity-40 ${props.create ? "rounded-md" : "rounded-sm"}` 468 468 } 469 469 onclick={() => { 470 470 if (hasPermission()) {
+178 -169
src/components/search.tsx
··· 66 66 return ( 67 67 <button 68 68 onclick={() => setShowSearch(!showSearch())} 69 - class="dark:bg-dark-200 dark:hover:bg-dark-100 mr-1 box-border flex h-7.5 items-center gap-1 rounded-lg border-[0.5px] border-neutral-300 bg-white px-2 text-xs text-neutral-500 hover:bg-neutral-100 active:bg-neutral-200 dark:border-neutral-600 dark:text-neutral-400 dark:active:bg-neutral-700" 69 + class="dark:bg-dark-200 dark:hover:bg-dark-100 mr-1 box-border flex h-7.5 items-center gap-1 rounded-md border-[0.5px] border-neutral-300 bg-white px-2 text-xs text-neutral-500 hover:bg-neutral-100 active:bg-neutral-200 dark:border-neutral-600 dark:text-neutral-400 dark:active:bg-neutral-700" 70 70 > 71 71 <span class="iconify lucide--search"></span> 72 72 <span>Search</span> ··· 196 196 }; 197 197 198 198 return ( 199 - <Modal open={showSearch()} onClose={() => setShowSearch(false)} alignTop contentClass="dark:bg-dark-200 dark:shadow-dark-700 pointer-events-auto mx-3 w-full max-w-lg rounded-lg border-[0.5px] border-neutral-300 bg-white shadow-md dark:border-neutral-700"> 200 - <form 201 - class="w-full" 202 - onsubmit={(e) => { 203 - e.preventDefault(); 204 - processInput(searchInput.value); 205 - }} 199 + <Modal 200 + open={showSearch()} 201 + onClose={() => setShowSearch(false)} 202 + alignTop 203 + contentClass="dark:bg-dark-200 dark:shadow-dark-700 pointer-events-auto mx-3 w-full max-w-lg rounded-lg border-[0.5px] border-neutral-300 bg-white shadow-md dark:border-neutral-700" 204 + > 205 + <form 206 + class="w-full" 207 + onsubmit={(e) => { 208 + e.preventDefault(); 209 + processInput(searchInput.value); 210 + }} 211 + > 212 + <label for="input" class="hidden"> 213 + PDS URL, AT URI, NSID, DID, or handle 214 + </label> 215 + <div 216 + class={`flex items-center gap-2 px-2 ${ 217 + getPrefixSuggestions().length > 0 || search()?.length ? "rounded-t-lg" : "rounded-lg" 218 + }`} 206 219 > 207 - <label for="input" class="hidden"> 208 - PDS URL, AT URI, NSID, DID, or handle 209 - </label> 210 - <div 211 - class={`flex items-center gap-2 px-2 ${ 212 - getPrefixSuggestions().length > 0 || search()?.length ? "rounded-t-lg" : "rounded-lg" 213 - }`} 214 - > 215 - <label 216 - for="input" 217 - class="iconify lucide--search text-neutral-500 dark:text-neutral-400" 218 - ></label> 219 - <input 220 - type="text" 221 - spellcheck={false} 222 - autocapitalize="off" 223 - placeholder="Handle, DID, AT URI, NSID, PDS" 224 - ref={searchInput} 225 - id="input" 226 - class="grow py-2.5 select-none placeholder:text-sm focus:outline-none" 227 - value={input() ?? ""} 228 - onInput={(e) => { 229 - setInput(e.currentTarget.value); 230 - setSelectedIndex(-1); 231 - }} 232 - onBlur={() => setSelectedIndex(-1)} 233 - onKeyDown={(e) => { 234 - const results = search(); 235 - const prefixSuggestions = getPrefixSuggestions(); 236 - const totalSuggestions = (prefixSuggestions.length || 0) + (results?.length || 0); 220 + <label 221 + for="input" 222 + class="iconify lucide--search text-neutral-500 dark:text-neutral-400" 223 + ></label> 224 + <input 225 + type="text" 226 + spellcheck={false} 227 + autocapitalize="off" 228 + placeholder="Handle, DID, AT URI, NSID, PDS" 229 + ref={searchInput} 230 + id="input" 231 + class="grow py-2.5 select-none placeholder:text-sm focus:outline-none" 232 + value={input() ?? ""} 233 + onInput={(e) => { 234 + setInput(e.currentTarget.value); 235 + setSelectedIndex(-1); 236 + }} 237 + onBlur={() => setSelectedIndex(-1)} 238 + onKeyDown={(e) => { 239 + const results = search(); 240 + const prefixSuggestions = getPrefixSuggestions(); 241 + const totalSuggestions = (prefixSuggestions.length || 0) + (results?.length || 0); 237 242 238 - if (!totalSuggestions) return; 243 + if (!totalSuggestions) return; 239 244 240 - if (e.key === "ArrowDown") { 241 - e.preventDefault(); 242 - setSelectedIndex((prev) => (prev === -1 ? 0 : (prev + 1) % totalSuggestions)); 243 - } else if (e.key === "ArrowUp") { 245 + if (e.key === "ArrowDown") { 246 + e.preventDefault(); 247 + setSelectedIndex((prev) => (prev === -1 ? 0 : (prev + 1) % totalSuggestions)); 248 + } else if (e.key === "ArrowUp") { 249 + e.preventDefault(); 250 + setSelectedIndex((prev) => 251 + prev === -1 ? 252 + totalSuggestions - 1 253 + : (prev - 1 + totalSuggestions) % totalSuggestions, 254 + ); 255 + } else if (e.key === "Enter") { 256 + const index = selectedIndex(); 257 + if (index >= 0) { 244 258 e.preventDefault(); 245 - setSelectedIndex((prev) => 246 - prev === -1 ? 247 - totalSuggestions - 1 248 - : (prev - 1 + totalSuggestions) % totalSuggestions, 249 - ); 250 - } else if (e.key === "Enter") { 251 - const index = selectedIndex(); 252 - if (index >= 0) { 253 - e.preventDefault(); 254 - if (index < prefixSuggestions.length) { 255 - const selectedPrefix = prefixSuggestions[index]; 256 - setInput(selectedPrefix.prefix); 257 - setSelectedIndex(-1); 258 - searchInput.focus(); 259 - } else { 260 - const adjustedIndex = index - prefixSuggestions.length; 261 - if (results && results[adjustedIndex]) { 262 - setShowSearch(false); 263 - navigate(`/at://${results[adjustedIndex].did}`); 264 - } 259 + if (index < prefixSuggestions.length) { 260 + const selectedPrefix = prefixSuggestions[index]; 261 + setInput(selectedPrefix.prefix); 262 + setSelectedIndex(-1); 263 + searchInput.focus(); 264 + } else { 265 + const adjustedIndex = index - prefixSuggestions.length; 266 + if (results && results[adjustedIndex]) { 267 + setShowSearch(false); 268 + navigate(`/at://${results[adjustedIndex].did}`); 265 269 } 266 - } else if (results?.length && prefixSuggestions.length === 0) { 267 - e.preventDefault(); 268 - setShowSearch(false); 269 - navigate(`/at://${results[0].did}`); 270 270 } 271 + } else if (results?.length && prefixSuggestions.length === 0) { 272 + e.preventDefault(); 273 + setShowSearch(false); 274 + navigate(`/at://${results[0].did}`); 271 275 } 272 - }} 273 - /> 274 - <Show when={input()} fallback={ListUrlsTooltip()}> 275 - <button 276 - type="button" 277 - class="dark:hover:bg-dark-100 flex items-center rounded-md p-1 hover:bg-neutral-100 active:bg-neutral-200 dark:active:bg-neutral-700" 278 - onClick={() => setInput(undefined)} 279 - > 280 - <span class="iconify lucide--x"></span> 281 - </button> 282 - </Show> 283 - </div> 276 + } 277 + }} 278 + /> 279 + <Show when={input()} fallback={ListUrlsTooltip()}> 280 + <button 281 + type="button" 282 + class="dark:hover:bg-dark-100 flex items-center rounded-md p-1 hover:bg-neutral-100 active:bg-neutral-200 dark:active:bg-neutral-700" 283 + onClick={() => setInput(undefined)} 284 + > 285 + <span class="iconify lucide--x"></span> 286 + </button> 287 + </Show> 288 + </div> 289 + 290 + <Show when={getPrefixSuggestions().length > 0 || (input() && search()?.length)}> 291 + <div 292 + class="flex w-full flex-col border-t border-neutral-200 p-2 dark:border-neutral-700" 293 + onMouseDown={(e) => e.preventDefault()} 294 + > 295 + {/* Prefix suggestions */} 296 + <For each={getPrefixSuggestions()}> 297 + {(prefixItem, index) => ( 298 + <button 299 + type="button" 300 + class={`flex items-center rounded-md p-2 ${ 301 + index() === selectedIndex() ? 302 + "bg-neutral-200 dark:bg-neutral-700" 303 + : "dark:hover:bg-dark-100 hover:bg-neutral-100 active:bg-neutral-200 dark:active:bg-neutral-700" 304 + }`} 305 + onClick={() => { 306 + setInput(prefixItem.prefix); 307 + setSelectedIndex(-1); 308 + searchInput.focus(); 309 + }} 310 + > 311 + <span class={`text-sm font-semibold`}>{prefixItem.prefix}</span> 312 + <span class="text-sm text-neutral-600 dark:text-neutral-400"> 313 + {prefixItem.description} 314 + </span> 315 + </button> 316 + )} 317 + </For> 284 318 285 - <Show when={getPrefixSuggestions().length > 0 || (input() && search()?.length)}> 286 - <div 287 - class="flex w-full flex-col border-t border-neutral-200 p-2 dark:border-neutral-700" 288 - onMouseDown={(e) => e.preventDefault()} 289 - > 290 - {/* Prefix suggestions */} 291 - <For each={getPrefixSuggestions()}> 292 - {(prefixItem, index) => ( 293 - <button 294 - type="button" 295 - class={`flex items-center rounded-md p-2 ${ 296 - index() === selectedIndex() ? 319 + {/* Typeahead results */} 320 + <For each={search()}> 321 + {(actor, index) => { 322 + const adjustedIndex = getPrefixSuggestions().length + index(); 323 + return ( 324 + <A 325 + class={`flex items-center gap-2 rounded-md p-2 ${ 326 + adjustedIndex === selectedIndex() ? 297 327 "bg-neutral-200 dark:bg-neutral-700" 298 328 : "dark:hover:bg-dark-100 hover:bg-neutral-100 active:bg-neutral-200 dark:active:bg-neutral-700" 299 329 }`} 300 - onClick={() => { 301 - setInput(prefixItem.prefix); 302 - setSelectedIndex(-1); 303 - searchInput.focus(); 304 - }} 330 + href={`/at://${actor.did}`} 331 + onClick={() => setShowSearch(false)} 305 332 > 306 - <span class={`text-sm font-semibold`}>{prefixItem.prefix}</span> 307 - <span class="text-sm text-neutral-600 dark:text-neutral-400"> 308 - {prefixItem.description} 309 - </span> 310 - </button> 311 - )} 312 - </For> 313 - 314 - {/* Typeahead results */} 315 - <For each={search()}> 316 - {(actor, index) => { 317 - const adjustedIndex = getPrefixSuggestions().length + index(); 318 - return ( 319 - <A 320 - class={`flex items-center gap-2 rounded-md p-2 ${ 321 - adjustedIndex === selectedIndex() ? 322 - "bg-neutral-200 dark:bg-neutral-700" 323 - : "dark:hover:bg-dark-100 hover:bg-neutral-100 active:bg-neutral-200 dark:active:bg-neutral-700" 324 - }`} 325 - href={`/at://${actor.did}`} 326 - onClick={() => setShowSearch(false)} 327 - > 328 - <img 329 - src={actor.avatar?.replace("img/avatar/", "img/avatar_thumbnail/")} 330 - class="size-9 rounded-full" 331 - /> 332 - <div class="flex min-w-0 flex-col"> 333 - <Show when={actor.displayName}> 334 - <span class="truncate text-sm font-medium">{actor.displayName}</span> 335 - </Show> 336 - <span class="truncate text-xs text-neutral-600 dark:text-neutral-400"> 337 - @{actor.handle} 338 - </span> 339 - </div> 340 - </A> 341 - ); 342 - }} 343 - </For> 344 - </div> 345 - </Show> 346 - </form> 333 + <img 334 + src={actor.avatar?.replace("img/avatar/", "img/avatar_thumbnail/")} 335 + class="size-9 rounded-full" 336 + /> 337 + <div class="flex min-w-0 flex-col"> 338 + <Show when={actor.displayName}> 339 + <span class="truncate text-sm font-medium">{actor.displayName}</span> 340 + </Show> 341 + <span class="truncate text-xs text-neutral-600 dark:text-neutral-400"> 342 + @{actor.handle} 343 + </span> 344 + </div> 345 + </A> 346 + ); 347 + }} 348 + </For> 349 + </div> 350 + </Show> 351 + </form> 347 352 </Modal> 348 353 ); 349 354 }; ··· 359 364 360 365 return ( 361 366 <> 362 - <Modal open={openList()} onClose={() => setOpenList(false)} alignTop contentClass="dark:bg-dark-300 dark:shadow-dark-700 pointer-events-auto w-88 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md sm:w-104 dark:border-neutral-700"> 363 - <div class="mb-2 flex items-center gap-1 font-semibold"> 364 - <span class="iconify lucide--link"></span> 365 - <span>Supported URLs</span> 366 - </div> 367 - <div class="mb-2 text-sm text-neutral-600 dark:text-neutral-400"> 368 - Links that will be parsed automatically, as long as all the data necessary is on the 369 - URL. 370 - </div> 371 - <div class="flex flex-col gap-2 text-sm"> 372 - <For each={Object.entries(appName)}> 373 - {([appView, name]) => { 374 - return ( 375 - <div> 376 - <p class="font-semibold">{name}</p> 377 - <div class="grid grid-cols-2 gap-x-4 text-neutral-600 dark:text-neutral-400"> 378 - <For each={urls[appView]}> 379 - {(url) => ( 380 - <a 381 - href={`${url.startsWith("localhost:") ? "http://" : "https://"}${url}`} 382 - target="_blank" 383 - class="hover:underline active:underline" 384 - > 385 - {url} 386 - </a> 387 - )} 388 - </For> 389 - </div> 367 + <Modal 368 + open={openList()} 369 + onClose={() => setOpenList(false)} 370 + alignTop 371 + contentClass="dark:bg-dark-300 dark:shadow-dark-700 pointer-events-auto w-88 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md sm:w-104 dark:border-neutral-700" 372 + > 373 + <div class="mb-2 flex items-center gap-1 font-semibold"> 374 + <span class="iconify lucide--link"></span> 375 + <span>Supported URLs</span> 376 + </div> 377 + <div class="mb-2 text-sm text-neutral-600 dark:text-neutral-400"> 378 + Links that will be parsed automatically, as long as all the data necessary is on the URL. 379 + </div> 380 + <div class="flex flex-col gap-2 text-sm"> 381 + <For each={Object.entries(appName)}> 382 + {([appView, name]) => { 383 + return ( 384 + <div> 385 + <p class="font-semibold">{name}</p> 386 + <div class="grid grid-cols-2 gap-x-4 text-neutral-600 dark:text-neutral-400"> 387 + <For each={urls[appView]}> 388 + {(url) => ( 389 + <a 390 + href={`${url.startsWith("localhost:") ? "http://" : "https://"}${url}`} 391 + target="_blank" 392 + class="hover:underline active:underline" 393 + > 394 + {url} 395 + </a> 396 + )} 397 + </For> 390 398 </div> 391 - ); 392 - }} 393 - </For> 394 - </div> 399 + </div> 400 + ); 401 + }} 402 + </For> 403 + </div> 395 404 </Modal> 396 405 <button 397 406 type="button"
+1 -1
src/layout.tsx
··· 156 156 </Show> 157 157 <AccountManager /> 158 158 <MenuProvider> 159 - <DropdownMenu icon="lucide--menu text-lg" buttonClass="rounded-lg p-1.5"> 159 + <DropdownMenu icon="lucide--menu text-lg" buttonClass="rounded-md p-1.5"> 160 160 <NavMenu href="/jetstream" label="Jetstream" icon="lucide--radio-tower" /> 161 161 <NavMenu href="/firehose" label="Firehose" icon="lucide--rss" /> 162 162 <NavMenu href="/spacedust" label="Spacedust" icon="lucide--orbit" />