Radish alpha
r
Radicle desktop app
Radicle
Git (anonymous pull)
Log in to clone via SSH
Add commit picker to the new-release form
Daniel Norman committed 7 days ago
commit cea53bb7cb148209d520ac8d49b08854656c7391
parent cd0cc35b01fe763fa71f451946573232154c0106
2 files changed +136 -13
added src/components/CommitPicker.svelte
@@ -0,0 +1,129 @@
+
<script lang="ts">
+
  import type { Commit } from "@bindings/repo/Commit";
+

+
  import fuzzysort from "fuzzysort";
+

+
  interface Props {
+
    commits: Commit[];
+
    value: string;
+
    disabled?: boolean;
+
    onSelect: (oid: string) => void;
+
  }
+

+
  const { commits, value, disabled = false, onSelect }: Props = $props();
+

+
  let query = $state(value);
+
  let open = $state(false);
+

+
  // Keep the typed value in sync when the parent overwrites it (e.g. tag
+
  // selection auto-fills the OID). Without this the picker would keep
+
  // showing the user's stale input.
+
  $effect(() => {
+
    query = value;
+
  });
+

+
  const results = $derived(
+
    fuzzysort.go(query, commits, {
+
      keys: ["id", "summary"],
+
      threshold: 0.5,
+
      all: true,
+
      limit: 20,
+
    }),
+
  );
+

+
  function pick(oid: string) {
+
    query = oid;
+
    open = false;
+
    onSelect(oid);
+
  }
+
</script>
+

+
<style>
+
  .wrapper {
+
    position: relative;
+
  }
+
  input {
+
    width: 100%;
+
    padding: 0.4rem 0.5rem;
+
    border: 1px solid var(--color-border-subtle);
+
    border-radius: var(--border-radius-sm);
+
    background-color: var(--color-surface-canvas);
+
    font: var(--txt-body-m-regular);
+
  }
+
  .menu {
+
    position: absolute;
+
    z-index: 10;
+
    top: calc(100% + 0.25rem);
+
    left: 0;
+
    right: 0;
+
    max-height: 18rem;
+
    overflow-y: auto;
+
    background-color: var(--color-surface-canvas);
+
    border: 1px solid var(--color-border-subtle);
+
    border-radius: var(--border-radius-sm);
+
    box-shadow: var(--elevation-low);
+
  }
+
  .item {
+
    display: flex;
+
    flex-direction: column;
+
    gap: 0.125rem;
+
    padding: 0.5rem 0.75rem;
+
    cursor: pointer;
+
    text-align: left;
+
    background: none;
+
    border: none;
+
    width: 100%;
+
    border-bottom: 1px solid var(--color-border-subtle);
+
  }
+
  .item:last-child {
+
    border-bottom: none;
+
  }
+
  .item:hover {
+
    background-color: var(--color-surface-subtle);
+
  }
+
  .summary {
+
    font: var(--txt-body-m-regular);
+
    color: var(--color-text-primary);
+
    white-space: nowrap;
+
    overflow: hidden;
+
    text-overflow: ellipsis;
+
  }
+
  .oid {
+
    font: var(--txt-body-s-mono);
+
    color: var(--color-text-secondary);
+
  }
+
  .empty {
+
    padding: 0.75rem;
+
    color: var(--color-text-secondary);
+
    font: var(--txt-body-s-regular);
+
  }
+
</style>
+

+
<div class="wrapper">
+
  <input
+
    type="text"
+
    placeholder="Search commits or paste an OID"
+
    bind:value={query}
+
    oninput={() => onSelect(query)}
+
    onfocus={() => (open = true)}
+
    onblur={() => setTimeout(() => (open = false), 150)}
+
    {disabled} />
+
  {#if open && !disabled}
+
    <div class="menu">
+
      {#each results as result}
+
        <button
+
          type="button"
+
          class="item"
+
          onmousedown={e => {
+
            e.preventDefault();
+
            pick(result.obj.id);
+
          }}>
+
          <span class="summary">{result.obj.summary}</span>
+
          <span class="oid">{result.obj.id.slice(0, 12)}…</span>
+
        </button>
+
      {:else}
+
        <div class="empty">No matching commits</div>
+
      {/each}
+
    </div>
+
  {/if}
+
</div>
modified src/views/repo/NewRelease.svelte
@@ -18,6 +18,8 @@
  import { invoke } from "@app/lib/invoke";
  import * as router from "@app/lib/router";

+
  import CommitPicker from "@app/components/CommitPicker.svelte";
+

  interface Props {
    repo: RepoInfo;
    onCancel: () => void;
@@ -288,20 +290,12 @@
  </div>

  <div class="field">
-
    <label for="release-oid">Commit OID</label>
-
    <input
-
      id="release-oid"
-
      type="text"
-
      placeholder="e.g. ec49ecb..."
-
      list="release-oid-options"
+
    <span class="field-label">Commit</span>
+
    <CommitPicker
+
      {commits}
      value={oid}
-
      oninput={e => onCommitInput((e.currentTarget as HTMLInputElement).value)}
-
      disabled={submitting} />
-
    <datalist id="release-oid-options">
-
      {#each commits as commit (commit.id)}
-
        <option value={commit.id} label={commit.summary}></option>
-
      {/each}
-
    </datalist>
+
      disabled={submitting}
+
      onSelect={onCommitInput} />
  </div>

  <div class="field">