Radish alpha
r
Radicle desktop app
Radicle
Git (anonymous pull)
Log in to clone via SSH
Add Releases list view + Release detail stub
Daniel Norman committed 7 days ago
commit da7e970c75cbe9fb769aa3bb2c18c8af4fc6e1c2
parent 71a55f31121b9cf4330d077f387d5019d17731d0
3 files changed +139 -0
modified src/App.svelte
@@ -42,6 +42,8 @@
  import Issues from "@app/views/repo/Issues.svelte";
  import Patch from "@app/views/repo/Patch.svelte";
  import Patches from "@app/views/repo/Patches.svelte";
+
  import Release from "@app/views/repo/Release.svelte";
+
  import Releases from "@app/views/repo/Releases.svelte";
  import RepoCommit from "@app/views/repo/RepoCommit.svelte";
  import RepoCommits from "@app/views/repo/RepoCommits.svelte";
  import RepoHome from "@app/views/repo/RepoHome.svelte";
@@ -227,6 +229,10 @@
      <Patch {...$activeRouteStore.params} />
    {:else if $activeRouteStore.resource === "repo.patches"}
      <Patches {...$activeRouteStore.params} />
+
    {:else if $activeRouteStore.resource === "repo.releases"}
+
      <Releases {...$activeRouteStore.params} />
+
    {:else if $activeRouteStore.resource === "repo.release"}
+
      <Release {...$activeRouteStore.params} />
    {:else}
      {unreachable($activeRouteStore)}
    {/if}
added src/views/repo/Release.svelte
@@ -0,0 +1,25 @@
+
<script lang="ts">
+
  // Detail view for a single release.
+
  // Stub: see Releases.svelte for the list view; this page is filled in
+
  // alongside the seed/download UI in a follow-up commit.
+
  import type { Release } from "@bindings/cob/release/Release";
+
  import type { RepoInfo } from "@bindings/repo/RepoInfo";
+

+
  import Layout from "./Layout.svelte";
+
  import Topbar from "@app/components/Topbar.svelte";
+

+
  interface Props {
+
    repo: RepoInfo;
+
    releases: Release[];
+
    release: Release;
+
  }
+

+
  const { release }: Props = $props();
+
</script>
+

+
<Layout>
+
  <Topbar>
+
    <span>Release {release.oid.slice(0, 7)}</span>
+
  </Topbar>
+
  <pre style="padding: 1rem;">{JSON.stringify(release, null, 2)}</pre>
+
</Layout>
added src/views/repo/Releases.svelte
@@ -0,0 +1,108 @@
+
<script lang="ts">
+
  import type { Release } from "@bindings/cob/release/Release";
+
  import type { RepoInfo } from "@bindings/repo/RepoInfo";
+

+
  import * as router from "@app/lib/router";
+

+
  import Layout from "./Layout.svelte";
+
  import ScrollArea from "@app/components/ScrollArea.svelte";
+
  import Topbar from "@app/components/Topbar.svelte";
+

+
  interface Props {
+
    repo: RepoInfo;
+
    releases: Release[];
+
  }
+

+
  const { repo, releases }: Props = $props();
+

+
  function shortOid(oid: string): string {
+
    return oid.slice(0, 7);
+
  }
+

+
  function formatTimestamp(ts: number): string {
+
    return new Date(ts * 1000).toLocaleString();
+
  }
+
</script>
+

+
<style>
+
  .page {
+
    display: flex;
+
    flex-direction: column;
+
    height: 100%;
+
  }
+
  .topbar-title {
+
    font: var(--txt-body-m-semibold);
+
    color: var(--color-text-secondary);
+
    padding-right: 0.25rem;
+
  }
+
  .list {
+
    display: flex;
+
    flex-direction: column;
+
    gap: 1px;
+
    min-height: 100%;
+
  }
+
  .row {
+
    display: flex;
+
    align-items: center;
+
    padding: 0.75rem 1rem;
+
    background-color: var(--color-surface-1);
+
    text-decoration: none;
+
    color: inherit;
+
    gap: 1rem;
+
  }
+
  .row:hover {
+
    background-color: var(--color-surface-subtle);
+
  }
+
  .row .oid {
+
    font: var(--txt-body-m-mono);
+
    color: var(--color-text-secondary);
+
  }
+
  .row .count {
+
    font: var(--txt-body-s-regular);
+
    color: var(--color-text-secondary);
+
  }
+
  .row .timestamp {
+
    font: var(--txt-body-s-regular);
+
    color: var(--color-text-secondary);
+
    margin-left: auto;
+
  }
+
  .empty {
+
    display: flex;
+
    flex: 1;
+
    align-items: center;
+
    justify-content: center;
+
    color: var(--color-text-secondary);
+
    padding: 2rem;
+
  }
+
</style>
+

+
<Layout selfScroll>
+
  <div class="page">
+
    <Topbar>
+
      <span class="topbar-title">Releases</span>
+
    </Topbar>
+

+
    <ScrollArea style="height: 100%; min-width: 0;">
+
      <div class="list">
+
        {#each releases as release (release.id)}
+
          <a
+
            class="row"
+
            href={router.routeToPath({
+
              resource: "repo.release",
+
              rid: repo.rid,
+
              release: release.id,
+
            })}>
+
            <span class="oid">{shortOid(release.oid)}</span>
+
            <span class="count">
+
              {release.artifacts.length}
+
              {release.artifacts.length === 1 ? "artifact" : "artifacts"}
+
            </span>
+
            <span class="timestamp">{formatTimestamp(release.timestamp)}</span>
+
          </a>
+
        {:else}
+
          <div class="empty">No releases yet</div>
+
        {/each}
+
      </div>
+
    </ScrollArea>
+
  </div>
+
</Layout>