Radish alpha
r
rad:z4D5UCArafTzTQpDZNQRuqswh3ury
Radicle desktop app
Radicle
Git
radicle-desktop src views repo RepoCommit.svelte
<script lang="ts">
  import type { Diff } from "@bindings/diff/Diff";
  import type { Commit } from "@bindings/repo/Commit";
  import type { RepoInfo } from "@bindings/repo/RepoInfo";

  import * as router from "@app/lib/router";
  import {
    absoluteTimestamp,
    explorerUrl,
    formatOid,
    formatTimestamp,
    gravatarURL,
    pluralize,
  } from "@app/lib/utils";

  import Changeset from "@app/components/Changeset.svelte";
  import DiffStatBadge from "@app/components/DiffStatBadge.svelte";
  import ExternalLink from "@app/components/ExternalLink.svelte";
  import Icon from "@app/components/Icon.svelte";
  import Id from "@app/components/Id.svelte";
  import ScrollArea from "@app/components/ScrollArea.svelte";
  import Topbar from "@app/components/Topbar.svelte";

  import Layout from "./Layout.svelte";

  interface Props {
    repo: RepoInfo;
    commit: Commit;
    diff: Diff;
  }

  const { repo, commit, diff }: Props = $props();
</script>

<style>
  .page {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
  }
  .breadcrumb {
    display: flex;
    align-items: center;
    gap: 0.375rem;
  }
  .breadcrumb-link {
    cursor: pointer;
    background: none;
    border: none;
    padding: 0;
    font: var(--txt-body-m-regular);
    color: var(--color-text-secondary);
  }
  .breadcrumb-link:hover {
    color: var(--color-text-primary);
  }
  .content {
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }
  .meta {
    padding: 0.25rem 0 0.5rem;
  }
  .meta-header {
    display: flex;
    gap: 0.75rem;
    align-items: flex-start;
    justify-content: space-between;
    padding: 0 0 1rem;
    flex-wrap: wrap;
  }
  .meta-title {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    min-width: 0;
  }
  .summary {
    font: var(--txt-body-l-semibold);
    overflow-wrap: anywhere;
  }
  .summary-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    color: var(--color-text-secondary);
    font: var(--txt-body-m-regular);
  }
  .summary-author {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
  }
  .summary-avatar {
    width: 1rem;
    height: 1rem;
    border-radius: 999px;
    flex: none;
  }
  .summary-timestamp {
    color: var(--color-text-quaternary);
  }
  .summary-message {
    white-space: pre-wrap;
    margin: 0;
    font: var(--txt-body-m-regular);
    color: var(--color-text-secondary);
  }
  .summary-parents {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    font: var(--txt-body-m-regular);
    color: var(--color-text-secondary);
  }
  .summary-parents-label {
    font: inherit;
    color: inherit;
  }
  .parent-link {
    cursor: pointer;
    background: none;
    border: none;
    padding: 0;
  }
  .parent-link:hover {
    color: var(--color-text-primary);
  }
  .chips {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    flex-wrap: wrap;
    padding-top: 0.125rem;
  }
  .files-chip {
    padding: 0 0.5rem;
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--border-radius-sm);
    height: 1.5rem;
    display: flex;
    align-items: center;
    font: var(--txt-code-regular);
    color: var(--color-text-secondary);
  }
</style>

<Layout selfScroll>
  <div class="page">
    <Topbar>
      <div class="breadcrumb">
        <button
          class="breadcrumb-link"
          onclick={() =>
            router.push({
              resource: "repo.commits",
              rid: repo.rid,
            })}>
          All commits
        </button>
        <Icon name="chevron-right" />
        <Id id={commit.id} clipboard={commit.id} placement="bottom-start" />
        <ExternalLink
          href={explorerUrl(`${repo.rid}/commits/${commit.id}`)}
          title="Open in app.radicle.xyz" />
      </div>
    </Topbar>
    <ScrollArea style="height: 100%; min-width: 0;">
      <div class="content">
        <section class="meta">
          <div class="meta-header">
            <div class="meta-title">
              <div class="summary txt-selectable">{commit.summary}</div>
              <div class="summary-meta">
                <span class="summary-author">
                  <img
                    class="summary-avatar"
                    alt=""
                    src={gravatarURL(commit.author.email)} />
                  <span class="txt-selectable">{commit.author.name}</span>
                </span>
                committed
                <Id id={commit.id} clipboard={commit.id} />
                <span
                  class="summary-timestamp"
                  title={absoluteTimestamp(commit.committer.time * 1000)}>
                  {formatTimestamp(commit.committer.time * 1000)}
                </span>
              </div>
              <div class="summary-parents">
                <span class="summary-parents-label">
                  {commit.parents.length === 1 ? "parent" : "parents"}
                </span>
                {#if commit.parents.length === 0}
                  <span>Initial commit</span>
                {:else}
                  {#each commit.parents as parent}
                    <button
                      class="parent-link txt-id"
                      onclick={() => {
                        void router.push({
                          resource: "repo.commit",
                          rid: repo.rid,
                          commit: parent,
                        });
                      }}>
                      {formatOid(parent)}
                    </button>
                  {/each}
                {/if}
              </div>
              <pre class="summary-message txt-selectable">{commit.message
                  .replace(commit.summary, "")
                  .trim()}</pre>
            </div>
            <div class="chips">
              <div class="files-chip">
                {diff.stats.filesChanged}
                {pluralize("file", diff.stats.filesChanged)} changed
              </div>
              <DiffStatBadge stats={diff.stats} />
            </div>
          </div>
        </section>

        <Changeset {diff} head={commit.id} />
      </div>
    </ScrollArea>
  </div>
</Layout>