Restyle reactions and highlight own reactions

This commit is contained in:
Brandon Oxendine
2026-04-30 11:11:56 +02:00
committed by Rūdolfs Ošiņš
parent 052839ac7c
commit fbae6e22ed
8 changed files with 86 additions and 26 deletions
+5
View File
@@ -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);
}
+3 -1
View File
@@ -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>
+1
View File
@@ -433,6 +433,7 @@
<ThreadComponent
inline
rid={codeComments.rid}
currentUserNid={codeComments.config.publicKey}
{thread}
reactOnComment={codeComments.reactOnComment}
createReply={(codeComments.canReply ?? true)
+1
View File
@@ -109,6 +109,7 @@
<ThreadComponent
{thread}
{rid}
currentUserNid={config.publicKey}
canEditComment={partial(
roles.isDelegateOrAuthor,
config.publicKey,
+73 -25
View File
@@ -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>
+1
View File
@@ -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"
+1
View File
@@ -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)
+1
View File
@@ -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)