johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
<script lang="ts">
import type * as getProfile from '#lib/lexicons/dev/knotless/getProfile.ts';
import Avatar from '#lib/atoms/Avatar.svelte';
import BotMark from '#lib/atoms/BotMark.svelte';
import Icon from '#lib/atoms/Icon.svelte';
import Pin from '#lib/atoms/Pin.svelte';
import { known, name, named, said } from '#lib/badges.ts';
import { urlPath } from '#lib/format.ts';
import ActorMenu from '#lib/molecules/ActorMenu.svelte';
import FollowButton from '#lib/molecules/FollowButton.svelte';
/**
* Who an account is, down the side of its page at `base`: who follows
* it and whom it follows, and following it, or blocking it, as `viewer`,
* the account logged in, if not itself, or else following it as whoever
* logs in, where they `can`; the badges it earned, each opening to say
* what it counted; and the organizations it is a member of.
*/
let {
profile: p,
base,
viewer,
can = false
}: { profile: getProfile.ProfileView; base: string; viewer?: string; can?: boolean } = $props();
let followers = $derived(p.followersCount);
const host = (url: string) => new URL(url).host;
const handle = $derived(p.handle ?? p.did);
const who = $derived([p.displayName && handle, p.pronouns].filter(Boolean).join(' · '));
const links = $derived(p.links ?? []);
const orgs = $derived(p.orgs ?? []);
const badges = $derived((p.badges ?? []).filter(known));
</script>
<aside class="profile">
<Avatar name={handle} size="xl" did={p.did} src={p.avatar} />
<div>
<h1>
{p.displayName ?? handle}{#if p.bot}<BotMark />{/if}
</h1>
{#if who}<p class="who">{who}</p>{/if}
</div>
{#if viewer !== p.did && (viewer || (can && followers !== undefined))}
<div class="profile-actions">
{#if followers !== undefined}<FollowButton
did={p.did}
following={p.viewer?.following}
in={!!viewer}
followed={(n) => (followers = n)}
/>{/if}
{#if viewer}<ActorMenu did={p.did} {handle} blocking={!!p.viewer?.blocking} />{/if}
</div>
{/if}
{#if p.description}<p class="bio">{p.description}</p>{/if}
{#if followers !== undefined}<p class="follows">
<Icon name="people" /><a href="{base}?tab=followers"
><b>{followers}</b> {followers === 1 ? 'follower' : 'followers'}</a
>
· <a href="{base}?tab=following"><b>{p.followsCount ?? 0}</b> following</a>
</p>{/if}
{#if links.length}<ul class="links">
{#each links as l}<li>
<Icon name="link" /><a href={l.url} rel="me nofollow noopener">{l.title ?? host(l.url)}</a
>
</li>{/each}
</ul>{/if}
{#if badges.length}
<section class="badges">
<h2>Badges</h2>
<ul>
{#each badges as b (b.kind)}
{@const words = said(b)}
<li>
<details class="popover badge">
<summary aria-label={named(b)} title={named(b)}
><Pin kind={b.kind} tier={b.tier} /></summary
>
<div class="menu badge-card">
<Pin kind={b.kind} tier={b.tier} />
<div>
<p class="badge-name">{name(b)}</p>
<p class="badge-tier">{words.tier}</p>
<p>{words.counted}</p>
{#if words.next}<p class="badge-next">{words.next}</p>{/if}
</div>
</div>
</details>
</li>
{/each}
</ul>
</section>
{/if}
{#if orgs.length}
<section class="orgs">
<h2>Organizations</h2>
<ul>
{#each orgs as o (o.actor.did)}<li>
<Avatar name={o.actor.handle} did={o.actor.did} src={o.actor.avatar} /><a
class="clip"
href="/{urlPath(o.actor.handle)}">{o.actor.handle}</a
>
</li>{/each}
</ul>
</section>
{/if}
</aside>