~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/knotless

git that lives in your Atmosphere account

Forked from chadtmiller.com/knotless

0
0
104 lines · 3.5 KB Raw History
<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>