johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
<script lang="ts">
import type { ActorView } from '#lib/lexicons/dev/knotless/defs.ts';
import Avatar from '#lib/atoms/Avatar.svelte';
import BotMark from '#lib/atoms/BotMark.svelte';
import Icon from '#lib/atoms/Icon.svelte';
/**
* Whom a pull or an issue is assigned to, as a fact of it: their faces
* and who they are, opening to a row each. With `people` and `assign`,
* as the owner or a collaborator, it also assigns it to more of them,
* or takes one off.
*/
let {
assignees,
people = [],
assign
}: {
assignees: ActorView[];
people?: ActorView[];
assign?: (did: ActorView['did'], removed: boolean) => Promise<unknown>;
} = $props();
/** Those it may yet be assigned to. */
const more = $derived(people.filter((p) => !assignees.some((a) => a.did === p.did)));
const SHOWN = 5;
/** Who, in words: the first by name, then how many more. */
const who = $derived(
assignees.length > 1
? `${assignees[0].handle} and ${assignees.length - 1} more`
: (assignees[0]?.handle ?? '')
);
let busy = $state('');
async function pick(did: ActorView['did'], removed: boolean) {
busy = did;
await assign?.(did, removed);
busy = '';
}
</script>
{#if assignees.length}
<details class="popover filter-menu assignees-fact" data-held={busy || undefined}>
<summary aria-label="Assigned to {assignees.map((a) => a.handle).join(', ')}">
<span class="avs">
{#each assignees.slice(0, SHOWN).reverse() as a (a.did)}<span class="face"
><Avatar name={a.handle} did={a.did} src={a.avatar} bot={a.bot} /></span
>{/each}
</span>
<span class="said">Assigned to <b>{who}</b></span>
</summary>
<div class="menu">
<div class="menu-head">Assignees</div>
{#each assignees as a (a.did)}
<div class="menu-item reviewer">
<Avatar name={a.handle} did={a.did} src={a.avatar} />
<span class="who"
>{a.handle}{#if a.bot}<BotMark />{/if}</span
>
{#if assign}<button
class="stop"
type="button"
aria-label="Take {a.handle} off"
title="Take off"
disabled={!!busy}
aria-busy={busy === a.did}
onclick={() => pick(a.did, true)}
>{#if busy === a.did}<span class="spinner"></span>{:else}<Icon
name="x"
/>{/if}</button
>{/if}
</div>
{/each}
{#if assign && more.length}
<div class="menu-head sub">Assign</div>
{#each more as p (p.did)}
<button
class="menu-item"
type="button"
disabled={!!busy}
onclick={() => pick(p.did, false)}
><span class="tick"
>{#if busy === p.did}<span class="spinner"></span>{:else}<Icon
name="plus"
/>{/if}</span
><Avatar name={p.handle} did={p.did} src={p.avatar} /><span>{p.handle}</span></button
>
{/each}
{/if}
</div>
</details>
{/if}