diff --git a/locales/en/app.json b/locales/en/app.json index 9b1a567503..3455231f45 100644 --- a/locales/en/app.json +++ b/locales/en/app.json @@ -156,6 +156,13 @@ "join_as_guest": "Join as guest", "join_button": "Join call", "leave_button": "Back to recents", + "participants_in_call_one": "{{count}} participant in call: {{names}}", + "participants_in_call_other": "{{count}} participants in call: {{names}}", + "participants_in_call_overflow_one": "{{count}} participant in call: {{names}}, and {{overflowCount}} other", + "participants_in_call_overflow_other": "{{count}} participants in call: {{names}}, and {{overflowCount}} others", + "participants_overflow_count": "+{{count}}", + "participants_overflow_label_one": "{{count}} more participant", + "participants_overflow_label_other": "{{count}} more participants", "waiting_for_invite": "Request sent! Waiting for permission to join…" }, "log_in": "Log In", diff --git a/src/room/CallParticipantRow.module.css b/src/room/CallParticipantRow.module.css new file mode 100644 index 0000000000..cccc8d8a62 --- /dev/null +++ b/src/room/CallParticipantRow.module.css @@ -0,0 +1,60 @@ +/* +Copyright 2026 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +.participantRow { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: flex-start; + gap: var(--cpd-space-4x); + padding: 0 var(--cpd-space-4x); + max-width: 100%; +} + +.participantItem { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--cpd-space-1x); + width: 64px; +} + +.participantName { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: center; + font: var(--cpd-font-body-sm-regular); + color: var(--cpd-color-text-secondary); +} + +.overflowItem { + display: inline-flex; + flex-direction: column; + align-items: center; + gap: var(--cpd-space-1x); + width: 64px; + cursor: default; +} + +.overflowCircle { + width: 48px; + height: 48px; + border-radius: 50%; + background-color: var(--cpd-color-bg-subtle-secondary); + display: flex; + justify-content: center; + align-items: center; + font: var(--cpd-font-body-md-semibold); + color: var(--cpd-color-text-secondary); +} + +.overflowCount { + font: var(--cpd-font-body-sm-regular); + color: var(--cpd-color-text-secondary); +} diff --git a/src/room/CallParticipantRow.test.tsx b/src/room/CallParticipantRow.test.tsx new file mode 100644 index 0000000000..6d1ba069ee --- /dev/null +++ b/src/room/CallParticipantRow.test.tsx @@ -0,0 +1,136 @@ +/* +Copyright 2026 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { type JSX, type ReactNode } from "react"; +import { describe, expect, test, vi } from "vitest"; +import { render, screen } from "@testing-library/react"; +import { TooltipProvider } from "@vector-im/compound-web"; + +import { CallParticipantRow } from "./CallParticipantRow"; +import { type CallParticipant } from "./useCallParticipants"; + +// Mock the Avatar component to avoid MXC URL resolution side effects +vi.mock("../Avatar", () => ({ + Avatar: ({ + id, + name, + size, + }: { + id: string; + name: string; + size: number; + }): JSX.Element => ( +
+ ), + Size: { SM: "sm", MD: "md", LG: "lg", XL: "xl" }, +})); + +function renderWithProviders(children: ReactNode): ReturnType