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

johnandersen777.bsky.social/knotless

git that lives in your Atmosphere account

Forked from chadtmiller.com/knotless

0
0
103 lines · 3.6 KB Raw History
<script lang="ts">
	import type { RepoView } from '#lib/lexicons/dev/knotless/defs.ts';
	import type * as blockActor from '#lib/lexicons/dev/knotless/blockActor.ts';
	import type * as listBlocks from '#lib/lexicons/dev/knotless/listBlocks.ts';
	import type * as unblockActor from '#lib/lexicons/dev/knotless/unblockActor.ts';
	import type { AtIdentifierString, AtUriString } from '@atproto/lex';
	import { invalidateAll } from '$app/navigation';
	import { call } from '#lib/data.ts';
	import { urlPath } from '#lib/format.ts';
	import Avatar from '#lib/atoms/Avatar.svelte';
	import Time from '#lib/atoms/Time.svelte';
	import Empty from '#lib/molecules/Empty.svelte';
	/**
	 * The accounts the account blocks, each from all its repositories or
	 * from one, the latest first, with a way to unblock each; and to block
	 * another, from all of them or from one of its public `repos`.
	 */
	let { blocks, repos }: { blocks: listBlocks.Block[]; repos: RepoView[] } = $props();
	let who = $state('');
	let repo = $state('');
	// What is under way: 'block', or the account being unblocked.
	let busy = $state('');
	let problem = $state('');
	async function change(
		nsid: 'dev.knotless.blockActor' | 'dev.knotless.unblockActor',
		subject: string,
		from?: string
	) {
		busy = nsid === 'dev.knotless.blockActor' ? 'block' : subject;
		problem = '';
		try {
			const input = {
				subject: subject as AtIdentifierString,
				repo: from ? (from as AtUriString) : undefined
			};
			await call<typeof blockActor.main | typeof unblockActor.main>(nsid, input);
			await invalidateAll();
			if (nsid === 'dev.knotless.blockActor') who = '';
		} catch (err) {
			problem = (err as Error).message;
		} finally {
			busy = '';
		}
	}
	const uriOf = (b: listBlocks.Block) =>
		b.repo && (`at://${b.repo.did}/dev.knotless.repo/${b.repo.name}` as const);
</script>

<div class="settings-section"><h2>Blocked accounts</h2></div>
<div class="settings-form">
	<p>
		Nothing an account you block writes about your repositories shows: its pulls, issues and
		comments are left out, and you hear nothing it does. Block it from all your repositories, or
		from one.
	</p>
	<form
		class="inline-form"
		onsubmit={(e) => (e.preventDefault(), change('dev.knotless.blockActor', who.trim(), repo))}
	>
		<input
			aria-label="Handle or DID to block"
			required
			maxlength="253"
			placeholder="handle.example.com"
			bind:value={who}
		/>
		<select aria-label="Block from" bind:value={repo}>
			<option value="">All your repositories</option>
			{#each repos as r (r.uri)}<option value={r.uri}>{r.name}</option>{/each}
		</select>
		<button class="btn" type="submit" disabled={!!busy} aria-busy={busy === 'block'}
			>{busy === 'block' ? 'Blocking…' : 'Block'}</button
		>
	</form>
	{#if problem}<p class="problem" role="alert">{problem}</p>{/if}
	<div class="box">
		<ul class="list">
			{#each blocks as b (b.uri)}
				<li>
					<Avatar name={b.subject.handle} size="lg" did={b.subject.did} src={b.subject.avatar} />
					<div class="grow">
						<a class="clip" href="/{urlPath(b.subject.handle)}"><b>{b.subject.handle}</b></a>
						<p class="meta">
							{#if b.repo}<span>{`From ${b.repo.name}`}</span>{:else}<span
									>From all your repositories</span
								>{/if}<Time at={b.createdAt} />
						</p>
					</div>
					<button
						class="btn"
						type="button"
						disabled={!!busy}
						aria-busy={busy === b.subject.did}
						onclick={() => change('dev.knotless.unblockActor', b.subject.did, uriOf(b))}
						>{busy === b.subject.did ? 'Unblocking…' : 'Unblock'}</button
					>
				</li>
			{:else}
				<li class="blank"><Empty title="No blocked accounts" /></li>
			{/each}
		</ul>
	</div>
</div>