Radish alpha
r
rad:z4D5UCArafTzTQpDZNQRuqswh3ury
Radicle desktop app
Radicle
Git
Tweak revision view
Open rudolfs opened 1 year ago

See individual commits for more details. Once approved this can be squashed into one commit titled “Tweak revision section styling”.

check check-e2e

👉 Workflow runs 👉 Branch on GitHub

3 files changed +140 -99 53d49e0b 53d49e0b
modified src/components/Button.svelte
@@ -9,6 +9,7 @@
    active?: boolean;
    flatLeft?: boolean;
    flatRight?: boolean;
+
    title?: string;
  }

  const {
@@ -19,6 +20,7 @@
    active = false,
    flatLeft = false,
    flatRight = false,
+
    title,
  }: Props = $props();

  const style = $derived(
@@ -370,6 +372,7 @@
  onclick={!disabled ? onclick : undefined}
  role="button"
  tabindex="0"
+
  {title}
  {style}>
  <div class="p1-1"></div>
  <div class="p1-2"></div>
modified src/components/ReviewTeaser.svelte
@@ -18,33 +18,43 @@

  const { rid, review }: Props = $props();

-
  const backgroundColor = $derived.by(() => {
-
    if (review.verdict === "accept") {
-
      return "var(--color-fill-diff-green-light)";
-
    } else if (review.verdict === "reject") {
-
      return "var(--color-fill-diff-red-light)";
-
    } else {
-
      return "var(--color-fill-float-hover)";
-
    }
-
  });
-

  const header = $derived.by(() => {
    if (!review.verdict) {
      return "published a review";
    }

-
    return `${review.verdict ? `${review.verdict}ed` : "reviewed"} revision with a review`;
+
    return `${review.verdict ? `${review.verdict}ed` : "reviewed"} revision`;
  });

-
  const icon = $derived.by(() => {
-
    if (review.verdict === "accept") {
+
  function icon(verdict: Review["verdict"]) {
+
    if (verdict === "accept") {
      return "comment-checkmark";
-
    } else if (review.verdict === "reject") {
+
    } else if (verdict === "reject") {
      return "comment-cross";
    } else {
      return "comment";
    }
-
  });
+
  }
+

+
  function backgroundColor(verdict: Review["verdict"]) {
+
    if (verdict === undefined) {
+
      return "var(--color-fill-float)";
+
    } else if (verdict === "accept") {
+
      return "var(--color-fill-diff-green-light)";
+
    } else if (verdict === "reject") {
+
      return "var(--color-fill-diff-red-light)";
+
    }
+
  }
+

+
  function color(verdict: Review["verdict"]) {
+
    if (verdict === undefined) {
+
      return "var(--color-foreground-dim)";
+
    } else if (verdict === "accept") {
+
      return "var(--color-foreground-success)";
+
    } else if (verdict === "reject") {
+
      return "var(--color-foreground-red)";
+
    }
+
  }
</script>

<style>
@@ -53,7 +63,7 @@
    display: flex;
    align-items: flex-start;
    padding: 0.5rem 0.75rem;
-
    gap: 1rem;
+
    gap: 0.75rem;
  }
  .review-content {
    width: 100%;
@@ -76,9 +86,9 @@
  }
</style>

-
<div class="review" style:background-color={backgroundColor}>
-
  <div class="icon">
-
    <Icon name={icon} />
+
<div class="review" style:background-color={backgroundColor(review.verdict)}>
+
  <div class="icon" style:color={color(review.verdict)}>
+
    <Icon name={icon(review.verdict)} />
  </div>
  <div class="review-content">
    <div class="review-header">
@@ -95,12 +105,10 @@
        {/if}
      </div>
    </div>
-
    <div>
-
      {#if review.summary?.trim()}
+
    {#if review.summary?.trim()}
+
      <div>
        <Markdown {rid} breaks content={review.summary} />
-
      {:else}
-
        <span class="txt-missing">No summary.</span>
-
      {/if}
-
    </div>
+
      </div>
+
    {/if}
  </div>
</div>
modified src/components/Revision.svelte
@@ -58,8 +58,12 @@

  let focusReply: boolean = $state(false);
  let hideChanges = $state(false);
-
  let hideDiscussion = $state(false);
-
  let hideReviews = $state(false);
+
  let hideDiscussion = $state(
+
    revision.discussion === undefined || revision.discussion.length === 0,
+
  );
+
  let hideReviews = $state(
+
    revision.reviews === undefined || revision.reviews.length === 0,
+
  );
  let topLevelReplyOpen = $state(false);
  let filesExpanded = $state(true);

@@ -87,8 +91,12 @@
    // eslint-disable-next-line @typescript-eslint/no-unused-expressions
    patchId;

-
    hideReviews = false;
-
    hideDiscussion = false;
+
    hideReviews =
+
      revision.reviews === undefined || revision.reviews.length === 0;
+
    hideDiscussion =
+
      revision.discussion === undefined || revision.discussion.length === 0;
+
    focusReply = false;
+
    topLevelReplyOpen = false;
    hideChanges = false;
  });

@@ -253,6 +261,7 @@
      behavior: "smooth",
      block: "center",
    });
+
    await tick();
    focusReply = true;
  }

@@ -330,11 +339,6 @@
    left: -18.5px;
    background-color: var(--color-fill-separator);
  }
-
  .review-row {
-
    display: flex;
-
    align-items: center;
-
    justify-content: space-between;
-
  }
</style>

<div class="txt-small patch-body">
@@ -355,23 +359,96 @@
      repoDelegates.map(delegate => delegate.did),
      revision.author.did,
    ) && partial(editRevision, revision.id)}>
-
    {#snippet actions()}
-
      <Icon name="reply" onclick={toggleReply} />
-
    {/snippet}
  </CommentComponent>
</div>

-
<div style:margin="1rem 0">
-
  <div class="global-flex" style:margin-bottom="1rem">
+
<div style:margin={hideReviews ? "1.5rem 0" : "1.5rem 0 2.5rem 0"}>
+
  <div class="global-flex">
+
    <NakedButton
+
      disabled={revision.reviews === undefined || revision.reviews.length === 0}
+
      variant="ghost"
+
      onclick={() => (hideReviews = !hideReviews)}>
+
      <Icon name={hideReviews ? "chevron-right" : "chevron-down"} />
+
      <div class="txt-semibold global-flex txt-regular">
+
        Reviews <span style:font-weight="var(--font-weight-regular)">
+
          {revision.reviews?.length ?? 0}
+
        </span>
+
      </div>
+
    </NakedButton>
+

+
    <div class="global-flex" style:margin-left="auto">
+
      <NakedButton
+
        variant="secondary"
+
        disabled={hasOwnReview}
+
        title={hasOwnReview ? "You already published a review" : undefined}
+
        onclick={() => createReview()}>
+
        <Icon name="plus" />
+
        <span class="txt-small">Write Review</span>
+
      </NakedButton>
+
      <Button
+
        variant="danger"
+
        disabled={hasOwnReview}
+
        title={hasOwnReview ? "You already published a review" : undefined}
+
        onclick={() => createReview("reject")}>
+
        <Icon name="comment-cross" />
+
        <span class="txt-small">Reject</span>
+
      </Button>
+
      <Button
+
        variant="success"
+
        disabled={hasOwnReview}
+
        title={hasOwnReview ? "You already published a review" : undefined}
+
        onclick={() => createReview("accept")}>
+
        <Icon name="comment-checkmark" />
+
        <span class="txt-small">Accept</span>
+
      </Button>
+
    </div>
+
  </div>
+

+
  {#if revision.reviews && revision.reviews.length}
+
    <div class:hide={hideReviews} style:margin-top="1rem">
+
      {#each revision.reviews as review}
+
        <ReviewTeaser {rid} {review} />
+
      {/each}
+
    </div>
+
  {/if}
+
</div>
+

+
<div style:margin={hideDiscussion ? "1.5rem 0" : "0 0 2.5rem 0"}>
+
  <div class="global-flex">
    <NakedButton
-
      stylePadding="0 4px"
      variant="ghost"
+
      disabled={revision.discussion === undefined ||
+
        revision.discussion.length === 0}
      onclick={() => (hideDiscussion = !hideDiscussion)}>
      <Icon name={hideDiscussion ? "chevron-right" : "chevron-down"} />
-
      <div class="txt-semibold global-flex txt-regular">Discussion</div>
+
      <div class="txt-semibold global-flex txt-regular">
+
        Discussion <span style:font-weight="var(--font-weight-regular)">
+
          {revision.discussion?.length ?? 0}
+
        </span>
+
      </div>
    </NakedButton>
+
    <div style:margin-left="auto">
+
      <NakedButton
+
        variant="secondary"
+
        onclick={async () => {
+
          if (hideDiscussion) {
+
            hideDiscussion = false;
+
          } else {
+
            if (
+
              revision.discussion === undefined ||
+
              revision.discussion.length === 0
+
            ) {
+
              hideDiscussion = true;
+
            }
+
          }
+
          await toggleReply();
+
        }}>
+
        <Icon name="comment" />
+
        <span class="txt-small">Comment</span>
+
      </NakedButton>
+
    </div>
  </div>
-
  <div class:hide={hideDiscussion}>
+
  <div class:hide={hideDiscussion} style:margin-top="1rem">
    {#each threads as thread}
      <ThreadComponent
        {thread}
@@ -394,7 +471,15 @@
        focus={focusReply}
        onexpand={toggleReply}
        onclose={topLevelReplyOpen
-
          ? () => (topLevelReplyOpen = false)
+
          ? () => {
+
              if (
+
                revision.discussion === undefined ||
+
                revision.discussion.length === 0
+
              ) {
+
                hideDiscussion = !hideDiscussion;
+
              }
+
              topLevelReplyOpen = false;
+
            }
          : undefined}
        placeholder="Leave a comment"
        submit={partial(createComment)} />
@@ -402,65 +487,10 @@
  </div>
</div>

-
<div style:margin="1rem 0">
-
  <div class="review-row">
-
    <div
-
      class="global-flex"
-
      style:margin-bottom={hideReviews || revision.reviews?.length === 0
-
        ? undefined
-
        : "1rem"}>
-
      <NakedButton
-
        stylePadding="0 4px"
-
        variant="ghost"
-
        onclick={() => (hideReviews = !hideReviews)}>
-
        <Icon
-
          name={hideReviews || revision.reviews?.length === 0
-
            ? "chevron-right"
-
            : "chevron-down"} />
-
        <div class="txt-semibold global-flex txt-regular">Reviews</div>
-
      </NakedButton>
-
    </div>
-
    <div class="global-flex">
-
      <Button
-
        variant="success"
-
        disabled={hasOwnReview}
-
        onclick={() => createReview("accept")}>
-
        <Icon name="comment-checkmark" />
-
        <span class="txt-small">Accept</span>
-
      </Button>
-
      <Button
-
        variant="danger"
-
        disabled={hasOwnReview}
-
        onclick={() => createReview("reject")}>
-
        <Icon name="comment-cross" />
-
        <span class="txt-small">Reject</span>
-
      </Button>
-
      <Button
-
        variant="secondary"
-
        disabled={hasOwnReview}
-
        onclick={() => createReview()}>
-
        <Icon name="plus" />
-
        <span class="txt-small">New Review</span>
-
      </Button>
-
    </div>
-
  </div>
-

-
  {#if revision.reviews && revision.reviews.length}
-
    <div class:hide={hideReviews}>
-
      {#each revision.reviews as review}
-
        <ReviewTeaser {rid} {review} />
-
      {/each}
-
    </div>
-
  {/if}
-
</div>
-

<div
  class="txt-semibold global-flex"
  style:margin-bottom={hideChanges ? undefined : "1rem"}>
-
  <NakedButton
-
    stylePadding="0 4px"
-
    variant="ghost"
-
    onclick={() => (hideChanges = !hideChanges)}>
+
  <NakedButton variant="ghost" onclick={() => (hideChanges = !hideChanges)}>
    <Icon name={hideChanges ? "chevron-right" : "chevron-down"} />
    <div class="txt-semibold global-flex txt-regular">Changes</div>
  </NakedButton>