Radish alpha
r
rad:z4D5UCArafTzTQpDZNQRuqswh3ury
Radicle desktop app
Radicle
Git
Restyle reactions and highlight own reactions
Brandon Oxendine committed 5 hours ago
commit fbae6e22edf48c0fa95da7db90912c2a65d11956
parent 052839a
8 files changed +86 -26
modified public/colors.css
@@ -67,6 +67,8 @@

  --color-surface-brand-primary: var(--color-brand-bg);
  --color-surface-brand-secondary: var(--color-brand-hover);
+
  --color-surface-brand-subtle: var(--color-accent-blue-100);
+
  --color-surface-brand-mid: var(--color-accent-blue-200);
  --color-border-brand: var(--color-brand-hover);
  --color-text-brand: var(--color-brand-text-light);
}
@@ -124,6 +126,9 @@
  --color-code-error: var(--color-semantic-red-400);
  --color-code-functions: var(--color-accent-emerald-400);

+
  --color-surface-brand-subtle: var(--color-accent-blue-900);
+
  --color-surface-brand-mid: var(--color-accent-blue-800);
+

  --color-text-brand: var(--color-brand-text-dark);
}

modified src/components/Comment.svelte
@@ -23,6 +23,7 @@
    beforeTimestamp?: Snippet;
    id?: string;
    rid: string;
+
    currentUserNid?: string;
    author: Author;
    body?: string;
    reactions?: Reaction[];
@@ -46,6 +47,7 @@
    beforeTimestamp,
    id,
    rid,
+
    currentUserNid,
    author,
    body = $bindable(),
    reactions,
@@ -243,7 +245,7 @@
            }
          }} />
      {/if}
-
      <Reactions handleReaction={reactOnComment} {reactions} />
+
      <Reactions handleReaction={reactOnComment} {currentUserNid} {reactions} />
    </div>
  {/if}
</div>
modified src/components/Diff.svelte
@@ -433,6 +433,7 @@
      <ThreadComponent
        inline
        rid={codeComments.rid}
+
        currentUserNid={codeComments.config.publicKey}
        {thread}
        reactOnComment={codeComments.reactOnComment}
        createReply={(codeComments.canReply ?? true)
modified src/components/Discussion.svelte
@@ -109,6 +109,7 @@
      <ThreadComponent
        {thread}
        {rid}
+
        currentUserNid={config.publicKey}
        canEditComment={partial(
          roles.isDelegateOrAuthor,
          config.publicKey,
modified src/components/Reactions.svelte
@@ -2,57 +2,105 @@
  import type { Author } from "@bindings/cob/Author";
  import type { Reaction } from "@bindings/cob/Reaction";

-
  import { emojiToTwemoji } from "@app/lib/utils";
+
  import { emojiToTwemoji, publicKeyFromDid, truncateId } from "@app/lib/utils";

  interface Props {
    reactions: Reaction[];
+
    currentUserNid?: string;
    handleReaction?: (authors: Author[], reaction: string) => Promise<void>;
  }

-
  const { reactions, handleReaction }: Props = $props();
+
  const { reactions, currentUserNid, handleReaction }: Props = $props();

  function authorsToTooltip(authors: Author[]) {
    return authors.map(a => a.alias ?? a.did).join("\n");
  }
+

+
  function isMine(authors: Author[]) {
+
    if (!currentUserNid) return false;
+
    return authors.some(a => publicKeyFromDid(a.did) === currentUserNid);
+
  }
+

+
  function formatAuthor(a: Author) {
+
    const pk = publicKeyFromDid(a.did);
+
    if (currentUserNid && pk === currentUserNid) {
+
      return "You";
+
    }
+
    return a.alias ?? truncateId(pk);
+
  }
+

+
  function formatAuthors(authors: Author[]) {
+
    if (authors.length > 3) return `${authors.length}`;
+
    return authors.map(formatAuthor).join(", ");
+
  }
</script>

<style>
  .reactions {
    display: flex;
    align-items: center;
-
    gap: 0.5rem;
+
    gap: 0.375rem;
+
    flex-wrap: wrap;
  }
  .reaction {
    display: inline-flex;
    flex-direction: row;
-
    gap: 0.5rem;
+
    align-items: center;
+
    gap: 0.25rem;
+
    padding: 2px 5px;
+
    border: 1px solid transparent;
+
    border-radius: var(--border-radius-sm);
+
    background-color: var(--color-surface-subtle);
+
  }
+
  .reaction.interactive {
    cursor: pointer;
+
    transition: background-color 0.1s ease-in-out;
+
  }
+
  .reaction.interactive:focus {
+
    outline: none;
+
  }
+
  .reaction.interactive:focus-visible {
+
    outline: 2px solid var(--color-border-brand);
+
    outline-offset: 1px;
+
  }
+
  .reaction.interactive:hover {
+
    background-color: var(--color-surface-mid);
+
  }
+
  .reaction.mine {
+
    background-color: var(--color-surface-brand-subtle);
+
    border-color: var(--color-surface-brand-mid);
+
  }
+
  .reaction.mine .count {
+
    color: var(--color-text-brand);
+
  }
+
  .reaction.interactive.mine:hover {
+
    background-color: var(--color-surface-brand-mid);
+
  }
+
  .reaction :global(.txt-emoji) {
+
    width: 16px;
+
    height: 16px;
+
    vertical-align: middle;
+
    margin: 0;
  }
</style>

<div class="reactions">
  {#each reactions as { emoji, authors }}
-
    <div title={authorsToTooltip(authors)}>
-
      {#if handleReaction}
-
        <!-- svelte-ignore a11y_click_events_have_key_events -->
-
        <div
-
          role="button"
-
          tabindex="0"
-
          class="reaction txt-body-s-regular"
-
          onclick={async () => {
-
            if (handleReaction) {
-
              await handleReaction(authors, emoji);
-
            }
-
          }}>
-
          <span>{@html emojiToTwemoji(emoji, ["21a9"])}</span>
-
          <span>{authors.length}</span>
-
        </div>
-
      {:else}
-
        <div class="reaction txt-body-s-regular" style="padding: 2px 4px;">
-
          <span>{@html emojiToTwemoji(emoji, ["21a9"])}</span>
-
          <span>{authors.length}</span>
-
        </div>
-
      {/if}
+
    <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
+
    <div
+
      role={handleReaction ? "button" : undefined}
+
      tabindex={handleReaction ? 0 : undefined}
+
      title={isMine(authors) && handleReaction
+
        ? "Remove reaction"
+
        : authorsToTooltip(authors)}
+
      class="reaction txt-body-s-regular"
+
      class:interactive={handleReaction}
+
      class:mine={isMine(authors)}
+
      onclick={handleReaction
+
        ? () => handleReaction(authors, emoji)
+
        : undefined}>
+
      <span>{@html emojiToTwemoji(emoji, ["21a9"])}</span>
+
      <span class="count">{formatAuthors(authors)}</span>
    </div>
  {/each}
</div>
modified src/components/Review.svelte
@@ -412,6 +412,7 @@
        <CommentComponent
          disableAttachments
          rid={repo.rid}
+
          currentUserNid={config.publicKey}
          disallowEmptyBody={!("draft" in review) &&
            review.verdict === undefined}
          emptyBodyTooltip="Summary is mandatory when verdict is None"
modified src/components/Revision.svelte
@@ -177,6 +177,7 @@
    <CommentComponent
      caption={revision.id === patchId ? "opened patch" : "created revision"}
      {rid}
+
      currentUserNid={config.publicKey}
      id={revision.id}
      lastEdit={revision.description.length > 1
        ? revision.description.at(-1)
modified src/views/repo/Issue.svelte
@@ -402,6 +402,7 @@
          <div class="issue-body">
            <CommentComponent
              rid={repo.rid}
+
              currentUserNid={config.publicKey}
              id={issue.id}
              lastEdit={issue.body.edits.length > 1
                ? issue.body.edits.at(-1)