mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-15 11:20:36 +08:00
Add repo fuzzy finder to home screen
This commit is contained in:
Generated
+25
@@ -38,9 +38,11 @@
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-svelte": "^3.3.2",
|
||||
"execa": "^9.5.2",
|
||||
"fuzzysort": "^3.1.0",
|
||||
"get-port": "^7.1.0",
|
||||
"happy-dom": "^17.4.4",
|
||||
"hast-util-to-dom": "^4.0.1",
|
||||
"keyux": "^0.11.1",
|
||||
"lodash": "^4.17.21",
|
||||
"marked": "^15.0.7",
|
||||
"marked-emoji": "^2.0.0",
|
||||
@@ -2830,6 +2832,13 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/fuzzysort": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz",
|
||||
"integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
@@ -3260,6 +3269,22 @@
|
||||
"katex": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/keyux": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/keyux/-/keyux-0.11.1.tgz",
|
||||
"integrity": "sha512-FIPQNnbtYuGdVU/vL0X9fcJwtkuzOwhzceUezMZMgTwGDNA2tmO4A/uA4tt1hdb0Cu3S3o+dNm5ifA+/reNX2A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
|
||||
@@ -53,9 +53,11 @@
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-svelte": "^3.3.2",
|
||||
"execa": "^9.5.2",
|
||||
"fuzzysort": "^3.1.0",
|
||||
"get-port": "^7.1.0",
|
||||
"happy-dom": "^17.4.4",
|
||||
"hast-util-to-dom": "^4.0.1",
|
||||
"keyux": "^0.11.1",
|
||||
"lodash": "^4.17.21",
|
||||
"marked": "^15.0.7",
|
||||
"marked-emoji": "^2.0.0",
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
repo: RepoInfo;
|
||||
selfDid: string;
|
||||
onclick?: () => void;
|
||||
focussed?: boolean;
|
||||
}
|
||||
|
||||
const { repo, selfDid, onclick }: Props = $props();
|
||||
const { repo, selfDid, onclick, focussed }: Props = $props();
|
||||
|
||||
const project = $derived(repo.payloads["xyz.radicle.project"]!);
|
||||
</script>
|
||||
@@ -34,7 +35,7 @@
|
||||
</style>
|
||||
|
||||
<Border
|
||||
variant="ghost"
|
||||
variant={focussed ? "secondary" : "ghost"}
|
||||
styleCursor="pointer"
|
||||
styleWidth="100%"
|
||||
stylePadding="8px 12px"
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
onDismiss?: () => void;
|
||||
valid?: boolean;
|
||||
oninput?: FormEventHandler<HTMLInputElement>;
|
||||
keyShortcuts?: string;
|
||||
}
|
||||
|
||||
/* eslint-disable prefer-const */
|
||||
@@ -31,6 +32,7 @@
|
||||
onDismiss,
|
||||
valid = true,
|
||||
oninput,
|
||||
keyShortcuts,
|
||||
}: Props = $props();
|
||||
/* eslint-enable prefer-const */
|
||||
|
||||
@@ -93,6 +95,7 @@
|
||||
variant={valid ? (focussed ? "secondary" : "ghost") : "danger"}
|
||||
styleWidth="100%">
|
||||
<input
|
||||
aria-keyshortcuts={keyShortcuts}
|
||||
onfocus={() => {
|
||||
focussed = true;
|
||||
}}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { mount } from "svelte";
|
||||
import { hotkeyKeyUX, hotkeyMacCompat, startKeyUX } from "keyux";
|
||||
import App from "./App.svelte";
|
||||
|
||||
const app = mount(App, { target: document.body });
|
||||
|
||||
const mac = hotkeyMacCompat();
|
||||
startKeyUX(window, [hotkeyKeyUX([mac])]);
|
||||
|
||||
export default app;
|
||||
|
||||
+67
-11
@@ -6,17 +6,22 @@
|
||||
import type { RepoCount } from "@bindings/repo/RepoCount";
|
||||
import type { RepoInfo } from "@bindings/repo/RepoInfo";
|
||||
|
||||
import fuzzysort from "fuzzysort";
|
||||
|
||||
import * as router from "@app/lib/router";
|
||||
import { didFromPublicKey } from "@app/lib/utils";
|
||||
import { didFromPublicKey, modifierKey } from "@app/lib/utils";
|
||||
import { dynamicInterval } from "@app/lib/interval";
|
||||
import { invoke } from "@app/lib/invoke";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
import Border from "@app/components/Border.svelte";
|
||||
import CopyableId from "@app/components/CopyableId.svelte";
|
||||
import HomeSidebar from "@app/components/HomeSidebar.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import Layout from "@app/views/repo/Layout.svelte";
|
||||
import Onboarding from "@app/views/home/Onboarding.svelte";
|
||||
import RepoCard from "@app/components/RepoCard.svelte";
|
||||
import TextInput from "@app/components/TextInput.svelte";
|
||||
|
||||
interface Props {
|
||||
activeTab?: HomeReposTab;
|
||||
@@ -63,6 +68,22 @@
|
||||
invoke<Config>("config"),
|
||||
]);
|
||||
}
|
||||
|
||||
let searchInput = $state("");
|
||||
|
||||
const searchableRepos = $derived(
|
||||
repos
|
||||
.flatMap(r => {
|
||||
if (r.payloads["xyz.radicle.project"]) {
|
||||
return { repo: r, name: r.payloads["xyz.radicle.project"].data.name };
|
||||
}
|
||||
})
|
||||
.filter((item): item is NonNullable<typeof item> => item !== undefined),
|
||||
);
|
||||
|
||||
const searchResults = $derived(
|
||||
fuzzysort.go(searchInput, searchableRepos, { key: "name", all: true }),
|
||||
);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -82,7 +103,6 @@
|
||||
padding-right: 1.5rem;
|
||||
align-items: center;
|
||||
min-height: 40px;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -100,24 +120,60 @@
|
||||
{notificationCount} />
|
||||
{/snippet}
|
||||
<div class="container">
|
||||
<div class="header">Repositories</div>
|
||||
<div class="global-flex" style:margin-bottom="0.5rem">
|
||||
<div class="header">Repositories</div>
|
||||
<div style:margin-left="auto">
|
||||
<TextInput
|
||||
onSubmit={async () => {
|
||||
if (searchResults.length === 1) {
|
||||
await router.push({
|
||||
resource: "repo.issues",
|
||||
rid: searchResults[0].obj.repo.rid,
|
||||
status: "open",
|
||||
});
|
||||
}
|
||||
}}
|
||||
onDismiss={() => {
|
||||
searchInput = "";
|
||||
}}
|
||||
placeholder={`Filter repositories ${modifierKey()} + f`}
|
||||
keyShortcuts="ctrl+f"
|
||||
bind:value={searchInput} />
|
||||
</div>
|
||||
</div>
|
||||
{#if repos.length > 0}
|
||||
<div class="repo-grid">
|
||||
{#each repos as repo}
|
||||
{#if repo.payloads["xyz.radicle.project"]}
|
||||
{#if searchResults.length > 0}
|
||||
<div class="repo-grid">
|
||||
{#each searchResults as result}
|
||||
<RepoCard
|
||||
{repo}
|
||||
focussed={searchResults.length === 1}
|
||||
repo={result.obj.repo}
|
||||
selfDid={didFromPublicKey(config.publicKey)}
|
||||
onclick={() => {
|
||||
void router.push({
|
||||
resource: "repo.issues",
|
||||
rid: repo.rid,
|
||||
rid: result.obj.repo.rid,
|
||||
status: "open",
|
||||
});
|
||||
}} />
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<Border
|
||||
variant="ghost"
|
||||
styleAlignItems="center"
|
||||
styleJustifyContent="center">
|
||||
<div
|
||||
class="global-flex"
|
||||
style:height="74px"
|
||||
style:justify-content="center">
|
||||
<div class="txt-missing txt-small global-flex" style:gap="0.25rem">
|
||||
<Icon name="none" />
|
||||
No matching repositories.
|
||||
</div>
|
||||
</div>
|
||||
</Border>
|
||||
{/if}
|
||||
{:else}
|
||||
<Onboarding {reload} />
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user