Skip to content

Commit 0e74376

Browse files
sturlanclaude
andcommitted
fix(thread): address PR review comments
- Remove stale updateParticipantsToDisplay() call (CI fix) - Add size prop to RecipientBubble (default 26) to restore pre-PR behaviour - Pass :size="24" to recipient bubbles via prop instead of !important CSS hacks - Fix duplicate :key risk in recipient v-for loops with index suffix - Replace router-link.left with div + role="button" to fix button-in-<a> a11y violation - Add keyboard handlers (Enter/Space) on envelope header div - Fix @click.stop on unsubscribe button (latent click-propagation bug) AI-assisted: Claude Code (claude-sonnet-4-6) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2add2e4 commit 0e74376

3 files changed

Lines changed: 44 additions & 54 deletions

File tree

src/components/RecipientBubble.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
v-bind="attrs"
1111
:display-name="label"
1212
:avatar-image="avatarUrlAbsolute"
13+
:size="size"
1314
@click="onClickOpenContactDialog" />
1415
</template>
1516
<template>
@@ -157,6 +158,11 @@ export default {
157158
type: String,
158159
required: true,
159160
},
161+
162+
size: {
163+
type: Number,
164+
default: 26,
165+
},
160166
},
161167
162168
data() {

src/components/Thread.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ export default {
217217
if (this.mainStore.getPreference('layout-message-view', 'threaded') === 'threaded') {
218218
await this.fetchThread()
219219
}
220-
this.updateParticipantsToDisplay()
221220
this.updateSummary()
222221
this.loadedThreads = 0
223222
},

src/components/ThreadEnvelope.vue

Lines changed: 38 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -55,32 +55,34 @@
5555
@click.prevent="hasWriteAcl ? onToggleJunk() : false" />
5656
</div>
5757

58-
<router-link
59-
:to="route"
60-
event=""
58+
<div
6159
class="left"
6260
:class="{ seen: envelope.flags.seen }"
63-
@click.native.prevent="$emit('toggle-expand', $event)">
61+
role="button"
62+
tabindex="0"
63+
@click="$emit('toggle-expand', $event)"
64+
@keydown.enter="$emit('toggle-expand', $event)"
65+
@keydown.space.prevent="$emit('toggle-expand', $event)">
6466
<div class="envelope__header__left__sender-subject-tags">
6567
<div class="sender" :class="{ 'sender--expanded': expanded }">
6668
{{ envelope.from && envelope.from[0] ? envelope.from[0].label : '' }}
67-
<button
68-
v-if="expanded && hasRecipients"
69-
type="button"
70-
class="sender__email sender__email--toggle"
71-
:style="{ color: senderEmailColor }"
72-
@click.stop.prevent="showRecipients = !showRecipients">
73-
{{ senderEmail }}
74-
<ChevronUpIcon v-if="showRecipients" :size="16" />
75-
<ChevronDownIcon v-else :size="16" />
76-
</button>
77-
<p
78-
v-else-if="expanded"
79-
class="sender__email"
80-
:style="{ color: senderEmailColor }">
81-
{{ senderEmail }}
82-
</p>
8369
</div>
70+
<button
71+
v-if="expanded && hasRecipients"
72+
type="button"
73+
class="sender__email sender__email--toggle"
74+
:style="{ color: senderEmailColor }"
75+
@click.stop.prevent="showRecipients = !showRecipients">
76+
{{ senderEmail }}
77+
<ChevronUpIcon v-if="showRecipients" :size="16" />
78+
<ChevronDownIcon v-else :size="16" />
79+
</button>
80+
<p
81+
v-else-if="expanded"
82+
class="sender__email"
83+
:style="{ color: senderEmailColor }">
84+
{{ senderEmail }}
85+
</p>
8486
<div v-if="hasChangedSubject" class="subline">
8587
{{ cleanSubject }}
8688
</div>
@@ -110,11 +112,11 @@
110112
v-if="message && message.dkimValid && (message.unsubscribeUrl || message.unsubscribeMailto)"
111113
variant="tertiary"
112114
class="envelope__header__unsubscribe"
113-
@click="showListUnsubscribeConfirmation = true">
115+
@click.stop="showListUnsubscribeConfirmation = true">
114116
{{ t('mail', 'Unsubscribe') }}
115117
</NcButton>
116118
</div>
117-
</router-link>
119+
</div>
118120
<div class="right">
119121
<Moment class="timestamp" :timestamp="envelope.dateInt" />
120122
<template v-if="expanded">
@@ -288,26 +290,29 @@
288290
<div v-if="envelope.to && envelope.to.length" class="recipients">
289291
<span class="recipients__label">{{ t('mail', 'To:') }}</span>
290292
<RecipientBubble
291-
v-for="recipient in envelope.to"
292-
:key="recipient.email"
293+
v-for="(recipient, index) in envelope.to"
294+
:key="`${recipient.email}-${index}`"
293295
:email="recipient.email"
294-
:label="recipient.label" />
296+
:label="recipient.label"
297+
:size="24" />
295298
</div>
296299
<div v-if="envelope.cc && envelope.cc.length" class="recipients">
297300
<span class="recipients__label">{{ t('mail', 'Cc:') }}</span>
298301
<RecipientBubble
299-
v-for="recipient in envelope.cc"
300-
:key="recipient.email"
302+
v-for="(recipient, index) in envelope.cc"
303+
:key="`${recipient.email}-${index}`"
301304
:email="recipient.email"
302-
:label="recipient.label" />
305+
:label="recipient.label"
306+
:size="24" />
303307
</div>
304308
<div v-if="envelope.bcc && envelope.bcc.length" class="recipients">
305309
<span class="recipients__label">{{ t('mail', 'Bcc:') }}</span>
306310
<RecipientBubble
307-
v-for="recipient in envelope.bcc"
308-
:key="recipient.email"
311+
v-for="(recipient, index) in envelope.bcc"
312+
:key="`${recipient.email}-${index}`"
309313
:email="recipient.email"
310-
:label="recipient.label" />
314+
:label="recipient.label"
315+
:size="24" />
311316
</div>
312317
</div>
313318
<MessageLoadingSkeleton v-if="loading === Loading.Skeleton" />
@@ -589,16 +594,6 @@ export default {
589594
return recipients.to.concat(recipients.cc).length > 1
590595
},
591596
592-
route() {
593-
return {
594-
name: 'message',
595-
params: {
596-
mailboxId: this.mailboxId || this.envelope.mailboxId,
597-
threadId: this.envelope.databaseId,
598-
},
599-
}
600-
},
601-
602597
isEncrypted() {
603598
return this.envelope.previewText
604599
&& isPgpText(this.envelope.previewText)
@@ -1181,12 +1176,10 @@ export default {
11811176
11821177
&--expanded {
11831178
color: var(--color-text-maxcontrast);
1184-
display: flex;
1185-
flex-direction: column;
1186-
align-items: flex-start;
11871179
}
11881180
11891181
&__email {
1182+
margin-inline-start: calc(var(--default-grid-baseline) * 2);
11901183
text-overflow: ellipsis;
11911184
overflow: hidden;
11921185
@@ -1465,20 +1458,12 @@ export default {
14651458
}
14661459
14671460
:deep(.user-bubble__content) {
1468-
height: 24px !important;
1469-
line-height: 24px !important;
1470-
border-radius: var(--border-radius-pill) !important;
1461+
border-radius: var(--border-radius-pill);
14711462
14721463
> :last-child {
14731464
padding-inline-end: 0;
14741465
}
14751466
}
1476-
1477-
:deep(.user-bubble__avatar) {
1478-
--avatar-size: 24px !important;
1479-
font-size: 11px !important;
1480-
line-height: 24px !important;
1481-
}
14821467
}
14831468
}
14841469

0 commit comments

Comments
 (0)