johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
<script lang="ts">
import RepoList from '#lib/organisms/RepoList.svelte';
import OwnerCards from '#lib/organisms/OwnerCards.svelte';
import CodeResults from '#lib/organisms/CodeResults.svelte';
import Meta from '#lib/atoms/Meta.svelte';
import Icon from '#lib/atoms/Icon.svelte';
import Count from '#lib/atoms/Count.svelte';
import Empty from '#lib/molecules/Empty.svelte';
import More from '#lib/atoms/More.svelte';
import { Pages, type Kept } from '#lib/pages.svelte.ts';
import type { FileView } from '#lib/lexicons/dev/knotless/searchCode.ts';
import type { Snapshot } from './$types';
import { plural, repoHref } from '#lib/format.ts';
let { data } = $props();
const q = $derived(data.query);
const topic = $derived(data.topic);
const code = $derived(data.code);
const heading = $derived(
topic
? `Repositories about ${topic}`
: q
? `Results for “${q}”`
: data.type === 'code'
? 'Code'
: 'Repositories'
);
const title = $derived(
topic
? `${topic} · knotless`
: q
? `“${q}” · knotless`
: data.type === 'code'
? 'code · knotless'
: 'repositories · knotless'
);
/** This search, as `type`. */
const of = (type: 'code' | 'repositories', query = q) => {
const params = new URLSearchParams();
if (query) params.set('q', query);
if (topic && type === 'repositories') params.set('topic', topic);
if (type === 'code') params.set('type', 'code');
return `/search${params.size ? `?${params}` : ''}`;
};
// The repository `repo:` keeps the search to, and the search without it.
const within = $derived(/(?:^|\s)repo:(\S+?)\/(\S+)(?=\s|$)/.exec(q));
const everywhere = $derived(of('code', q.replace(/(^|\s)repo:\S+/, ' ').trim()));
// The language `lang:` keeps the search to, and the search without it.
const LANG = /(?:^|\s)lang:("[^"]*"|\S+)/;
const picked = $derived(LANG.exec(q)?.[1].replace(/"/g, '').toLowerCase());
const unpicked = $derived(q.replace(LANG, ' ').replace(/\s+/g, ' ').trim());
// The languages of all the search finds, most files first, each to
// narrow it to, or, picked, to widen it again: each row filled behind
// as far as its share of the first's, which fills its own.
const languages = $derived(code.kind === 'found' ? (code.answer.languages ?? []) : []);
const most = $derived(languages[0]?.files ?? 1);
// The files found, a page at a time, each added below those before.
const files = new Pages(
() => data,
(d) =>
d.code.kind === 'found'
? { items: d.code.answer.files, cursor: d.code.answer.cursor }
: { items: [] },
(f) => `${f.repo.did}/${f.repo.name}/${f.path}`
);
// The files loaded below the first page, kept for going back to it.
export const snapshot: Snapshot<Kept<FileView> | null> = {
capture: () => files.capture(),
restore: (kept) => files.restore(kept)
};
// How deep the pages go, as searchCode stops them.
const DEEPEST = 200;
const narrowed = (name: string) =>
name.toLowerCase() === picked
? of('code', unpicked)
: of('code', `${unpicked} lang:${name.includes(' ') ? `"${name}"` : name}`);
</script>
<Meta {title} />
<div class="search-page results">
<div class="search-side">
<nav class="account-nav search-nav" aria-label="Filter by">
<p class="search-nav-head">Filter by</p>
<a href={of('code')} aria-current={data.type === 'code' ? 'page' : undefined}
><Icon name="code" />Code{#if data.counts.code !== undefined}<Count
n={data.counts.code}
/>{/if}</a
>
<a href={of('repositories')} aria-current={data.type === 'repositories' ? 'page' : undefined}
><Icon name="repo" />Repositories{#if data.counts.repos !== undefined}<Count
n={data.counts.repos}
more={data.counts.more}
/>{/if}</a
>
</nav>
{#if languages.length}
<nav class="search-langs" aria-labelledby="search-langs-head">
<p class="search-nav-head" id="search-langs-head">Languages</p>
{#each languages as l (l.name)}<a
class="search-lang"
href={narrowed(l.name)}
aria-current={l.name.toLowerCase() === picked ? 'page' : undefined}
title={plural(l.files, 'file', 'files')}
aria-label="{l.name}, {plural(l.files, 'file', 'files')}"
style:--lang={l.color ?? 'var(--faint)'}
><i
class="search-lang-bar"
aria-hidden="true"
style:width="max(var(--space-3), {(l.files * 100) / most}%)"
></i><span>{l.name}</span></a
>{/each}
</nav>
{/if}
</div>
<div class="settings-main">
<h1>{heading}</h1>
{#if data.type === 'code'}
{#if code.kind === 'found' && code.answer.files.length}
<p class="search-count mute">
{plural(code.answer.fileCount, 'file', 'files')}{#if within}{' in '}<a
href={repoHref(within[1], within[2])}>{within[1]}/{within[2]}</a
>{' · '}<a href={everywhere}>Search all of knotless</a>{/if}
</p>
<CodeResults files={files.items} />
<More pages={files} label="More files" />
{#if !files.href && code.answer.fileCount > DEEPEST}<p class="search-deepest mute">
These are the best {DEEPEST}. Add lang:, file: or repo: to find the rest.
</p>{/if}
{:else}
<div class="box">
{#if code.kind === 'off'}<Empty title="Code search is off here"
>This server searches no code.</Empty
>
{:else if code.kind === 'missing'}<Empty title="No repository {code.repo}"
>Check its owner and name, or <a href={everywhere}>search all of knotless</a>.</Empty
>
{:else if code.kind === 'bad'}<Empty title="That search can’t be read"
>{code.message}</Empty
>
{:else if code.kind === 'found'}<Empty title="No code found"
>{#if picked && languages.length}No {languages.find(
(l) => l.name.toLowerCase() === picked
)?.name ?? picked} file matches.
<a href={of('code', unpicked)}>Search every language</a> instead.{:else if within}Nothing
in {within[1]}/{within[2]} matches. <a href={everywhere}>Search all of knotless</a> instead.{:else}Only
each repository’s default branch is searched. <a href={of('repositories')}
>Search repositories</a
> instead.{/if}</Empty
>
{:else}<Empty title="Search code"
>Type what to look for, as a word, "quoted text" or /a regex/. Add repo:owner/name to
search one repository.</Empty
>{/if}
</div>
{/if}
{:else}
{#if data.owners.length}
<h2>Owners</h2>
<OwnerCards owners={data.owners} />
<h2>Repositories</h2>
{/if}
<RepoList repos={data.repos}
>{#snippet empty()}{#if data.indexed}<Empty title="No repositories found" />{:else}<Empty
title="Search is off here">This server keeps no index to search.</Empty
>{/if}{/snippet}</RepoList
>
{/if}
</div>
</div>