johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
<script lang="ts">
import type * as listItems from '#lib/lexicons/dev/knotless/listItems.ts';
import type { Answer } from '#lib/data.ts';
import type { ItemView } from '#lib/lexicons/dev/knotless/defs.ts';
import type { Paged } from '#lib/pages.svelte.ts';
import { stateIcon } from '#lib/icons.ts';
import { closed, filtered, filterHref, has, toggled, withState, withTerm } from '#lib/query.ts';
import Icon from '#lib/atoms/Icon.svelte';
import More from '#lib/atoms/More.svelte';
import FilterMenu from '#lib/molecules/FilterMenu.svelte';
import ItemRow from '#lib/molecules/ItemRow.svelte';
import Empty from '#lib/molecules/Empty.svelte';
/**
* A page of the pulls or issues of the repository whose page is at
* `base`, the `open` ones or the closed, that the filter `q` matches:
* the filter to change, a switch between open and closed, menus of the
* labels and authors to filter by, the `pages` shown so far and the way
* to the next, and for pulls the way to the merge queue; and the way to
* open another.
*/
let {
items: list,
pages,
kind,
open,
base,
queue,
q = ''
}: {
items: Answer<typeof listItems.main>;
pages: Paged<ItemView>;
kind: 'pull' | 'issue';
open: boolean;
base: string;
queue?: string;
q?: string;
} = $props();
const label = $derived(kind === 'pull' ? 'pulls' : 'issues');
// The filter as the page shows it, with its state when only `?state=` said it.
const here = $derived(open || closed(q) ? q : withState(q, 'closed'));
const labels = $derived(
(list.labels ?? []).map((l) => ({
name: l.name,
color: l.color ?? '',
on: has(q, 'label', l.name),
href: filterHref(toggled(here, 'label', l.name))
}))
);
const authors = $derived(
(list.authors ?? []).map((a) => {
const name = a.handle ?? a.did;
return { name, on: has(q, 'author', name), href: filterHref(toggled(here, 'author', name)) };
})
);
</script>
<div class="list-top">
<form class="query" role="search">
<Icon name="search" /><input
type="search"
name="q"
value={q}
placeholder="label:kind/bug crash"
aria-label="Filter {label}"
/>
</form>
<a class="btn primary" href="{base}/{label}/new">{kind === 'pull' ? 'New pull' : 'New issue'}</a>
</div>
<div class="box items">
<div class="boxhead" data-sveltekit-reset="false">
<nav class="filter">
<a href={filterHref(withState(here, 'open'))} aria-current={open ? 'page' : undefined}
><Icon name={stateIcon(kind, 'open')} />{list.openCount} Open</a
>
<a href={filterHref(withState(here, 'closed'))} aria-current={open ? undefined : 'page'}
><Icon name="done" />{list.closedCount} Closed</a
>
</nav>
<div class="menus">
{#if authors.length}<FilterMenu title="Author" options={authors} />{/if}
{#if labels.length}<FilterMenu title="Labels" options={labels} />{/if}
</div>
{#if queue}<a class="end queue-link" href={queue} aria-label="Merge queue"
><Icon name="queue" /><span>Merge queue</span></a
>{/if}
</div>
<ul class="list">
{#each pages.items as i (i.uri)}
<ItemRow
item={i}
{kind}
{base}
labelHref={(name) => filterHref(withTerm(here, 'label', name))}
/>
{:else}
<li class="blank">
{#if filtered(q)}
<Empty title="No {open ? 'open' : 'closed'} {label} match"
><a href={filterHref(open ? '' : withState('', 'closed'))}>Clear the filter</a></Empty
>
{:else}
<Empty title="No {open ? 'open' : 'closed'} {label}" />
{/if}
</li>
{/each}
</ul>
</div>
<More {pages} label="More {label}" />