diff --git a/frontend/src/lib/components/DraftBadge.svelte b/frontend/src/lib/components/DraftBadge.svelte index 4bf200b1fc..9a172cacf4 100644 --- a/frontend/src/lib/components/DraftBadge.svelte +++ b/frontend/src/lib/components/DraftBadge.svelte @@ -23,9 +23,26 @@ is_draft?: boolean draft_only?: boolean draft_users?: DraftUser[] + /** Authed user's workspace username — circles for THIS user are + * omitted because the row already signals their own draft via + * the asterisk appended to the displayed summary. Pass + * `$userStore?.username` from the row. */ + currentUsername?: string | null } - let { is_draft = false, draft_only = false, draft_users = [] }: Props = $props() + let { + is_draft = false, + draft_only = false, + draft_users = [], + currentUsername = undefined + }: Props = $props() + + // Drop the authed user from the circle row — their own draft is + // signalled by the asterisk on the row's summary, so showing both + // would be visual noise. Keep the legacy NULL-username row. + const otherUsers = $derived( + currentUsername ? draft_users.filter((u) => u.username !== currentUsername) : draft_users + ) /** Two-letter uppercase initials from a username — `john.doe`/`john_doe` → * `JD`, `alice` → `AL`, the legacy NULL-email row (no username) → `?`. */ @@ -60,15 +77,22 @@ return PALETTE[hash % PALETTE.length] } - // First 3 circles when ≤3 users; first 2 + a "+N" overflow when 4+. + // First 3 circles when ≤3 OTHER users; first 2 + a "+N" overflow + // when 4+. The slice/overflow math applies to `otherUsers` (post + // current-user filter), not the raw `draft_users` — otherwise + // dropping the authed user would silently change the visible count. const MAX_CIRCLES = 3 const visibleUsers = $derived( - draft_users.length <= MAX_CIRCLES ? draft_users : draft_users.slice(0, MAX_CIRCLES - 1) + otherUsers.length <= MAX_CIRCLES ? otherUsers : otherUsers.slice(0, MAX_CIRCLES - 1) ) const overflowCount = $derived( - draft_users.length > MAX_CIRCLES ? draft_users.length - (MAX_CIRCLES - 1) : 0 + otherUsers.length > MAX_CIRCLES ? otherUsers.length - (MAX_CIRCLES - 1) : 0 ) + // Show the badge whenever ANY draft exists (`draft_users` non-empty) + // OR when the authed user has a draft (`is_draft` true — the list + // endpoint sets this even for paths the user has a draft on but no + // one else does). const showBadge = $derived(is_draft || draft_users.length > 0) @@ -79,7 +103,7 @@ {draft_only ? 'Never deployed — only a draft exists.' : 'Deployed with drafts pending.'}