atmosphere explorer
0
fork

Configure Feed

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

favicon in backlinks and car explorer

Juliet d22e1bed ef068af8

+62 -31
+11 -5
src/components/backlinks.tsx
··· 3 3 import { getAllBacklinks, getRecordBacklinks, LinksWithRecords } from "../utils/api.js"; 4 4 import { localDateFromTimestamp } from "../utils/date.js"; 5 5 import { Button } from "./button.jsx"; 6 + import { Favicon } from "./favicon.jsx"; 6 7 7 8 type BacklinksProps = { 8 9 target: string; ··· 122 123 ) => { 123 124 const [expanded, setExpanded] = createSignal(false); 124 125 126 + const authority = () => props.collection.split(".").slice(0, 2).join("."); 127 + 125 128 return ( 126 129 <div class="overflow-hidden rounded-lg border border-neutral-200 dark:border-neutral-700"> 127 130 <button 128 131 class="flex w-full items-center justify-between gap-3 px-3 py-2 text-left hover:bg-neutral-50 dark:hover:bg-neutral-800/50" 129 132 onClick={() => setExpanded(!expanded())} 130 133 > 131 - <div class="flex min-w-0 flex-1 flex-col"> 132 - <span class="w-full truncate">{props.collection}</span> 133 - <span class="w-full text-xs wrap-break-word text-neutral-500 dark:text-neutral-400"> 134 - {props.path.slice(1)} 135 - </span> 134 + <div class="flex min-w-0 flex-1 items-center gap-2"> 135 + <Favicon authority={authority()} /> 136 + <div class="flex min-w-0 flex-1 flex-col"> 137 + <span class="w-full truncate">{props.collection}</span> 138 + <span class="w-full text-xs wrap-break-word text-neutral-500 dark:text-neutral-400"> 139 + {props.path.slice(1)} 140 + </span> 141 + </div> 136 142 </div> 137 143 <div class="flex shrink-0 items-center gap-2 text-neutral-700 dark:text-neutral-300"> 138 144 <span class="text-xs">
+33
src/components/favicon.tsx
··· 1 + import { createSignal, JSX, Show } from "solid-js"; 2 + 3 + export const Favicon = (props: { 4 + authority: string; 5 + wrapper?: (children: JSX.Element) => JSX.Element; 6 + }) => { 7 + const [loaded, setLoaded] = createSignal(false); 8 + const domain = () => props.authority.split(".").reverse().join("."); 9 + 10 + const content = ( 11 + <> 12 + <Show when={!loaded()}> 13 + <span class="iconify lucide--globe size-4 text-neutral-400 dark:text-neutral-500" /> 14 + </Show> 15 + <img 16 + src={ 17 + ["bsky.app", "bsky.chat"].includes(domain()) ? 18 + "https://web-cdn.bsky.app/static/apple-touch-icon.png" 19 + : `https://${domain()}/favicon.ico` 20 + } 21 + alt="" 22 + class="h-4 w-4" 23 + classList={{ hidden: !loaded() }} 24 + onLoad={() => setLoaded(true)} 25 + onError={() => setLoaded(false)} 26 + /> 27 + </> 28 + ); 29 + 30 + return props.wrapper ? 31 + props.wrapper(content) 32 + : <div class="flex h-5 w-4 shrink-0 items-center justify-center">{content}</div>; 33 + };
+3
src/views/car/explore.tsx
··· 6 6 import { Title } from "@solidjs/meta"; 7 7 import { createEffect, createMemo, createSignal, For, Match, Show, Switch } from "solid-js"; 8 8 import { Button } from "../../components/button.jsx"; 9 + import { Favicon } from "../../components/favicon.jsx"; 9 10 import { JSONValue } from "../../components/json.jsx"; 10 11 import { TextInput } from "../../components/text-input.jsx"; 11 12 import { isTouchDevice } from "../../layout.jsx"; ··· 309 310 <For each={filteredEntries()}> 310 311 {(entry) => { 311 312 const hasSingleEntry = entry.entries.length === 1; 313 + const authority = () => entry.name.split(".").slice(0, 2).join("."); 312 314 313 315 return ( 314 316 <li> ··· 326 328 }} 327 329 class="flex w-full items-center gap-2 rounded p-2 text-left text-sm hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-800 dark:active:bg-neutral-700" 328 330 > 331 + <Favicon authority={authority()} /> 329 332 <span 330 333 class="truncate font-medium" 331 334 classList={{
+15 -26
src/views/repo.tsx
··· 23 23 MenuSeparator, 24 24 NavMenu, 25 25 } from "../components/dropdown.jsx"; 26 + import { Favicon } from "../components/favicon.jsx"; 26 27 import { 27 28 addNotification, 28 29 removeNotification, ··· 453 454 )} 454 455 > 455 456 {(authority) => { 456 - const reversedDomain = authority.split(".").reverse().join("."); 457 - const [faviconLoaded, setFaviconLoaded] = createSignal(false); 458 - 459 457 const isHighlighted = () => location.hash === `#collections:${authority}`; 460 458 461 459 return ( ··· 467 465 "bg-blue-100 dark:bg-blue-500/25": isHighlighted(), 468 466 }} 469 467 > 470 - <a 471 - href={`#collections:${authority}`} 472 - class="relative flex h-5 w-4 shrink-0 items-center justify-center hover:opacity-70" 473 - > 474 - <span class="absolute top-1/2 -left-5 flex -translate-y-1/2 items-center text-base opacity-0 transition-opacity group-hover:opacity-100"> 475 - <span class="iconify lucide--link absolute -left-2 w-7"></span> 476 - </span> 477 - <Show when={!faviconLoaded()}> 478 - <span class="iconify lucide--globe size-4 text-neutral-400 dark:text-neutral-500" /> 479 - </Show> 480 - <img 481 - src={ 482 - ["bsky.app", "bsky.chat"].includes(reversedDomain) ? 483 - "https://web-cdn.bsky.app/static/apple-touch-icon.png" 484 - : `https://${reversedDomain}/favicon.ico` 485 - } 486 - alt={`${reversedDomain} favicon`} 487 - class="h-4 w-4" 488 - classList={{ hidden: !faviconLoaded() }} 489 - onLoad={() => setFaviconLoaded(true)} 490 - onError={() => setFaviconLoaded(false)} 491 - /> 492 - </a> 468 + <Favicon 469 + authority={authority} 470 + wrapper={(children) => ( 471 + <a 472 + href={`#collections:${authority}`} 473 + class="relative flex h-5 w-4 shrink-0 items-center justify-center hover:opacity-70" 474 + > 475 + <span class="absolute top-1/2 -left-5 flex -translate-y-1/2 items-center text-base opacity-0 transition-opacity group-hover:opacity-100"> 476 + <span class="iconify lucide--link absolute -left-2 w-7"></span> 477 + </span> 478 + {children} 479 + </a> 480 + )} 481 + /> 493 482 <div class="flex flex-1 flex-col"> 494 483 <For 495 484 each={nsids()?.[authority].nsids.filter((nsid) =>