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 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}