atagen

malice

public
Star0
Watch0
1b586ca058592ee4ddfa70958d7c0c4ff0c90c69
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
web/src/lib/MxcAvatar.svelteSvelte58 lines1.4 KB
1
<script lang="ts">
2
  import { mediaUrl } from './api';
3
  import { initialsOf, senderHue } from './format';
4
5
  export let mxc: string | null;
6
  export let label: string;
7
  export let size = 34;
8
  /** 'circle' for people, 'rounded' for rooms/spaces */
9
  export let shape: 'circle' | 'rounded' = 'circle';
10
  export let seed: string | null = null;
11
12
  $: src = mediaUrl(mxc);
13
14
  let failed = false;
15
  $: if (mxc) failed = false;
16
  $: px = `${size}px`;
17
  $: fontPx = `${Math.max(10, Math.round(size * 0.36))}px`;
18
  $: hue = senderHue(seed ?? label ?? '#');
19
</script>
20
21
{#if src && !failed}
22
  <img
23
    {src}
24
    alt=""
25
    aria-hidden="true"
26
    width={size}
27
    height={size}
28
    loading="lazy"
29
    class="mxc-avatar"
30
    class:circle={shape === 'circle'}
31
    style={`width:${px};height:${px};`}
32
    on:error={() => (failed = true)}
33
  />
34
{:else}
35
  <span class="mxc-fallback" class:circle={shape === 'circle'} aria-hidden="true" style={`width:${px};height:${px};font-size:${fontPx};background:hsl(${hue} 32% 30%);`}>
36
    {initialsOf(label || '#')}
37
  </span>
38
{/if}
39
40
<style>
41
  .mxc-avatar {
42
    flex: none;
43
    object-fit: cover;
44
    border-radius: var(--r-md);
45
    background: var(--bg-soft);
46
  }
47
  .mxc-avatar.circle { border-radius: 50%; }
48
  .mxc-fallback {
49
    flex: none;
50
    display: inline-grid;
51
    place-items: center;
52
    border-radius: var(--r-md);
53
    color: #fff;
54
    font-weight: 700;
55
    letter-spacing: 0.02em;
56
  }
57
  .mxc-fallback.circle { border-radius: 50%; }
58
</style>