Files
plspace/src/components/profile/FriendSpace.svelte
T

87 lines
2.7 KiB
Svelte

<script lang="ts">
/**
* "Tom's Friend Space" — the grid of tiny avatars with names above them.
*
* Mastodon lets an account hide its follower/following lists, and remote
* accounts often return an empty list rather than an error, so the count and
* the grid are allowed to disagree; the count is authoritative.
*/
import type { Account, CustomEmoji } from '$lib/api/types'
import { displayNameOf, formatCount, profilePath } from '$lib/util/profile'
import Module from '../common/Module.svelte'
import Avatar from '../common/Avatar.svelte'
import EmojiText from '../common/EmojiText.svelte'
interface Props {
title: string
/** The subject, used in "Tom has 527 friends." */
ownerName: string
ownerEmojis?: CustomEmoji[]
friends: Account[]
total: number
viewAllHref: string
loading?: boolean
/** The list is withheld by the account's privacy settings. */
hidden?: boolean
/** The count is withheld too, so `total` is not meaningful. */
countHidden?: boolean
compact?: boolean
}
let {
title,
ownerName,
ownerEmojis,
friends,
total,
viewAllHref,
loading = false,
hidden = false,
countHidden = false,
compact = false,
}: Props = $props()
</script>
<Module {title} titleEmojis={ownerEmojis} variant="band">
{#snippet action()}
<a href={viewAllHref}>[view all]</a>
{/snippet}
<!-- Never render a withheld count as "0 friends" — that reports a privacy
setting as a fact about the person. -->
{#if countHidden}
<p class="friend-count">
<EmojiText text={ownerName} emojis={ownerEmojis} /> keeps their friend count private.
</p>
{:else}
<p class="friend-count">
<EmojiText text={ownerName} emojis={ownerEmojis} /> has
<span class="friend-count-value">{formatCount(total)}</span>
friend{total === 1 ? '' : 's'}.
</p>
{/if}
{#if hidden}
<p class="empty-note">This friends list is private.</p>
{:else if loading && friends.length === 0}
<p class="loading-note">Loading friends&hellip;</p>
{:else if friends.length === 0}
<p class="empty-note">No friends to show yet.</p>
{:else}
<ul class="friend-grid" class:friend-grid--compact={compact}>
{#each friends as friend (friend.id)}
<li class="friend-card" data-account={friend.acct}>
<a class="friend-card-link" href={profilePath(friend)}>
<EmojiText
class="friend-card-name"
text={displayNameOf(friend)}
emojis={friend.emojis}
/>
<Avatar account={friend} plain size="friend" class="friend-card-photo" />
</a>
</li>
{/each}
</ul>
{/if}
</Module>