forked from coracle/flotilla
49 lines
1.6 KiB
Svelte
49 lines
1.6 KiB
Svelte
<script lang="ts">
|
|
import cx from "classnames"
|
|
import {removeUndefined} from "@welshman/lib"
|
|
import {deriveProfile, deriveProfileDisplay} from "@welshman/app"
|
|
import {getColor, getBlobVariant} from "@app/theme"
|
|
import ImageIcon from "@lib/components/ImageIcon.svelte"
|
|
|
|
type Props = {
|
|
pubkey?: string
|
|
class?: string
|
|
size?: number
|
|
url?: string
|
|
shape?: "blob" | "circle"
|
|
style?: string
|
|
}
|
|
|
|
const {pubkey, url, size = 7, shape = "blob", style = "", ...props}: Props = $props()
|
|
|
|
const profile = deriveProfile(pubkey, removeUndefined([url]))
|
|
const display = deriveProfileDisplay(pubkey)
|
|
|
|
// Organic, hand-drawn-feeling mask. The variant is stable per pubkey so a
|
|
// person's silhouette never changes; `shape="circle"` opts back into a disc.
|
|
const shapeClass =
|
|
shape === "circle"
|
|
? "rounded-full"
|
|
: ["avatar-blob", "avatar-blob-2", "avatar-blob-3"][getBlobVariant(pubkey) - 1]
|
|
|
|
const color = getColor(pubkey)
|
|
const px = $derived(size * 4)
|
|
const initial = $derived([...($display || "")].find(c => c.trim()) || "?")
|
|
</script>
|
|
|
|
{#if $profile?.picture}
|
|
<ImageIcon {size} alt="" {style} class={cx(props.class, shapeClass)} src={$profile.picture} />
|
|
{:else}
|
|
<!-- Fallback: a subtle gradient derived from the pubkey + the person's initial. -->
|
|
<div
|
|
class={cx(
|
|
props.class,
|
|
shapeClass,
|
|
"font-display flex shrink-0 items-center justify-center font-bold text-white uppercase select-none",
|
|
)}
|
|
style="width:{px}px;height:{px}px;font-size:{px *
|
|
0.45}px;background-image:linear-gradient(135deg,{color},color-mix(in oklab,{color},#000 28%));{style}">
|
|
{initial}
|
|
</div>
|
|
{/if}
|