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

johnandersen777.bsky.social/knotless

git that lives in your Atmosphere account

Forked from chadtmiller.com/knotless

0
0
83 lines · 2.7 KB Raw History
<script lang="ts">
	import type { ActorView } from '#lib/lexicons/dev/knotless/defs.ts';
	import type * as repo from '#lib/lexicons/dev/knotless/repo.ts';
	import Avatar from '#lib/atoms/Avatar.svelte';
	import Icon from '#lib/atoms/Icon.svelte';
	/**
	 * One menu for the facts a pull or an issue has none of yet, so its
	 * facts line stays short however many kinds there are: the `people` it
	 * may `ask` to review it, the `assignable` it may `assign` it to, and
	 * the `labels` it may `label` it with. Once one is chosen, that fact
	 * shows, and is changed from there.
	 */
	let {
		people = [],
		ask,
		assignable = [],
		assign,
		labels = [],
		label
	}: {
		people?: ActorView[];
		ask?: (did: ActorView['did'], removed: boolean) => Promise<unknown>;
		assignable?: ActorView[];
		assign?: (did: ActorView['did'], removed: boolean) => Promise<unknown>;
		labels?: repo.Label[];
		label?: (name: string, removed: boolean) => Promise<unknown>;
	} = $props();
	const asking = $derived(!!ask && people.length > 0);
	const assigning = $derived(!!assign && assignable.length > 0);
	const labelling = $derived(!!label && labels.length > 0);
	let busy = $state('');
	async function doing(key: string, work: () => Promise<unknown>) {
		busy = key;
		await work();
		busy = '';
	}
	const hex = (color?: string) => (/^#[0-9a-fA-F]{6}$/.test(color ?? '') ? color : undefined);
</script>

{#snippet person(p: ActorView, key: string, pick: () => Promise<unknown>)}
	<button class="menu-item" type="button" disabled={!!busy} onclick={() => doing(key, pick)}
		>{#if busy === key}<span class="spinner"></span>{:else}<Avatar
				name={p.handle}
				did={p.did}
				src={p.avatar}
			/>{/if}<span>{p.handle}</span></button
	>
{/snippet}

{#if asking || assigning || labelling}
	<details class="popover filter-menu add-menu" data-held={busy || undefined}>
		<summary><Icon name="plus" />Add</summary>
		<div class="menu">
			{#if asking}
				<div class="menu-head">Ask to review</div>
				{#each people as p (p.did)}{@render person(p, `review ${p.did}`, () =>
						ask!(p.did, false)
					)}{/each}
			{/if}
			{#if assigning}
				<div class="menu-head" class:sub={asking}>Assign</div>
				{#each assignable as p (p.did)}{@render person(p, `assign ${p.did}`, () =>
						assign!(p.did, false)
					)}{/each}
			{/if}
			{#if labelling}
				<div class="menu-head" class:sub={asking || assigning}>Label</div>
				{#each labels as l (l.name)}
					<button
						class="menu-item"
						type="button"
						disabled={!!busy}
						onclick={() => doing(l.name, () => label!(l.name, false))}
						>{#if busy === l.name}<span class="spinner"></span>{:else}<span
								class="dot"
								style:--label={hex(l.color)}
							></span>{/if}<span>{l.name}</span></button
					>
				{/each}
			{/if}
		</div>
	</details>
{/if}