Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124<script module lang="ts"> import { tv, type VariantProps } from "tailwind-variants";
export const avatarSizeClass = { mini: "size-3.25", small: "size-4.25", regular: "size-5.25", large: "size-6.5", full: "size-full" };
export const avatar = tv({ base: "relative flex shrink-0 items-center justify-center overflow-hidden rounded-full border border-border-default bg-background-canvas text-foreground-subtle", variants: { size: avatarSizeClass }, defaultVariants: { size: "regular" } });
export type AvatarSize = NonNullable<VariantProps<typeof avatar>["size"]>;
export const avatarSizePx = { mini: 13, small: 17, regular: 21, large: 26, full: undefined } satisfies Record<AvatarSize, number | undefined>;
export const avatarSizeNames = Object.keys(avatarSizePx) as AvatarSize[];</script>
<script lang="ts"> import UserRound from "$icon/user-round"; import { avatarUrl, avatarWidthFor } from "#lib/avatar.ts"; import { gradientCss } from "#lib/avatarGradient.ts"; import type { Moderation } from "#lib/api/moderationLabels.ts";
interface Props { did?: string; // null means the account has no avatar. undefined means nobody knows yet avatarCid?: string | null; src?: string; handle?: string; size?: AvatarSize; pixels?: number; loading?: "lazy" | "eager"; class?: string; moderation?: Moderation; }
let { did, avatarCid, src, handle, size = "regular", pixels, loading = "lazy", class: className = "", moderation }: Props = $props();
const px = $derived(pixels ?? avatarSizePx[size]); const source = $derived( moderation?.level === "hide" ? undefined : (src ?? (did && avatarCid !== null ? avatarUrl( did, px === undefined ? undefined : avatarWidthFor(px), undefined, avatarCid ) : undefined)) );
// the gradient shows until the image loads and stays when there is none const placeholder = $derived( did && moderation?.level !== "hide" ? gradientCss(did) : undefined );
// hidden with a style, not state, a page full of 404s would write state mid-render const hide = (event: Event) => { (event.currentTarget as HTMLImageElement).style.display = "none"; };
// a reused element has to recover from a previous failure const show = (event: Event) => { (event.currentTarget as HTMLImageElement).style.display = ""; };</script>
<span class={avatar({ size, class: className })} role={handle ? "img" : undefined} aria-label={handle ? `${handle}'s avatar` : undefined} aria-hidden={handle ? undefined : "true"} style:background-image={placeholder}> {#if !placeholder} <UserRound class="size-1/2" /> {/if} {#if source} <img src={source} alt="" width={px} height={px} {loading} decoding="async" class={[ "absolute inset-0 size-full object-cover", moderation?.level === "warn" && "scale-125 blur-md" ]} onerror={hide} onload={show} /> {/if}</span>