diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Participants/ParticipantsCollapsableList.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Participants/ParticipantsCollapsableList.tsx new file mode 100644 index 00000000..66373772 --- /dev/null +++ b/src/frontend/src/features/rooms/livekit/components/controls/Participants/ParticipantsCollapsableList.tsx @@ -0,0 +1,106 @@ +import { useState } from 'react' +import { css } from '@/styled-system/css' +import { ToggleButton } from 'react-aria-components' +import { HStack, styled, VStack } from '@/styled-system/jsx' +import { RiArrowUpSLine } from '@remixicon/react' +import { Participant } from 'livekit-client' +import { useTranslation } from 'react-i18next' + +const ToggleHeader = styled(ToggleButton, { + base: { + minHeight: '40px', //fixme hardcoded value + paddingRight: '.5rem', + cursor: 'pointer', + display: 'flex', + justifyContent: 'space-between', + width: '100%', + alignItems: 'center', + transition: 'background 200ms', + borderTopRadius: '7px', + '&[data-hovered]': { + backgroundColor: '#f5f5f5', + }, + }, +}) + +const Container = styled('div', { + base: { + border: '1px solid #dadce0', + borderRadius: '8px', + margin: '0 .625rem', + }, +}) + +const ListContainer = styled(VStack, { + base: { + borderTop: '1px solid #dadce0', + alignItems: 'start', + overflowY: 'scroll', + overflowX: 'hidden', + minHeight: 0, + flexGrow: 1, + display: 'flex', + paddingY: '0.5rem', + paddingX: '1rem', + gap: 0, + }, +}) + +type ParticipantsCollapsableListProps = { + heading: string + participants: Array + renderParticipant: (participant: Participant) => JSX.Element +} + +export const ParticipantsCollapsableList = ({ + heading, + participants, + renderParticipant, +}: ParticipantsCollapsableListProps) => { + const { t } = useTranslation('rooms') + const [isOpen, setIsOpen] = useState(true) + const label = t(`participants.collapsable.${isOpen ? 'close' : 'open'}`, { + name: heading, + }) + return ( + + setIsOpen(!isOpen)} + style={{ + borderRadius: !isOpen ? '7px' : undefined, + }} + > + +
+ {heading} +
+
{participants?.length || 0}
+
+ +
+ {isOpen && ( + + {participants.map((participant) => renderParticipant(participant))} + + )} +
+ ) +} diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Participants/ParticipantsList.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Participants/ParticipantsList.tsx index dd82ba5c..cbcba0c4 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Participants/ParticipantsList.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Participants/ParticipantsList.tsx @@ -2,14 +2,14 @@ import { css } from '@/styled-system/css' import { useParticipants } from '@livekit/components-react' import { Heading } from 'react-aria-components' -import { Box, Button, Div } from '@/primitives' +import { Box, Button, Div, H } from '@/primitives' import { text } from '@/primitives/Text' import { RiCloseLine } from '@remixicon/react' import { participantsStore } from '@/stores/participants' import { useTranslation } from 'react-i18next' import { allParticipantRoomEvents } from '@/features/rooms/livekit/constants/events' import { ParticipantListItem } from '@/features/rooms/livekit/components/controls/Participants/ParticipantListItem' -import { VStack } from '@/styled-system/jsx' +import { ParticipantsCollapsableList } from '@/features/rooms/livekit/components/controls/Participants/ParticipantsCollapsableList' // TODO: Optimize rendering performance, especially for longer participant lists, even though they are generally short. export const ParticipantsList = () => { @@ -39,25 +39,26 @@ export const ParticipantsList = () => { return ( - - {t('participants.heading')}{' '} - - {participants?.length} - + + {t('participants.heading')}
- {sortedParticipants?.length > 0 && ( - - {sortedParticipants.map((participant) => ( - - ))} - - )} + + {t('participants.subheading').toUpperCase()} + + ( + + )} + />
) } diff --git a/src/frontend/src/locales/de/rooms.json b/src/frontend/src/locales/de/rooms.json index 40a49cfc..da63ccd1 100644 --- a/src/frontend/src/locales/de/rooms.json +++ b/src/frontend/src/locales/de/rooms.json @@ -53,7 +53,13 @@ }, "participants": { "heading": "", + "subheading": "", "closeButton": "", + "contributors": "", + "collapsable": { + "open": "", + "close": "" + }, "you": "", "muteParticipant": "", "muteParticipantAlert": { diff --git a/src/frontend/src/locales/en/rooms.json b/src/frontend/src/locales/en/rooms.json index ab668143..b31a7938 100644 --- a/src/frontend/src/locales/en/rooms.json +++ b/src/frontend/src/locales/en/rooms.json @@ -53,8 +53,14 @@ }, "participants": { "heading": "Participants", + "subheading": "In room", "closeButton": "Hide participants", "you": "You", + "contributors": "Contributors", + "collapsable": { + "open": "Open {{name}} list", + "close": "Close {{name}} list" + }, "muteParticipant": "Close the mic of {{name}}", "muteParticipantAlert": { "description": "Mute {{name}} for all participants? {{name}} is the only person who can unmute themselves.", diff --git a/src/frontend/src/locales/fr/rooms.json b/src/frontend/src/locales/fr/rooms.json index 0e719b68..64186e8a 100644 --- a/src/frontend/src/locales/fr/rooms.json +++ b/src/frontend/src/locales/fr/rooms.json @@ -53,8 +53,14 @@ }, "participants": { "heading": "Participants", + "subheading": "Dans la réunion", "closeButton": "Masquer les participants", "you": "Vous", + "contributors": "Contributeurs", + "collapsable": { + "open": "Ouvrir la liste {{name}}", + "close": "Fermer la liste {{name}}" + }, "muteParticipant": "Couper le micro de {{name}}", "muteParticipantAlert": { "description": "Couper le micro de {{name}} pour tous les participants ? {{name}} est la seule personne habilitée à réactiver son micro",