diff --git a/res/css/_components.pcss b/res/css/_components.pcss index 9012960195..298e13b09f 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -269,6 +269,8 @@ @import "./views/right_panel/_VerificationPanel.pcss"; @import "./views/right_panel/_WidgetCard.pcss"; @import "./views/room_settings/_AliasSettings.pcss"; +@import "./views/rooms/RoomListPanel/_RoomList.pcss"; +@import "./views/rooms/RoomListPanel/_RoomListCell.pcss"; @import "./views/rooms/RoomListPanel/_RoomListHeaderView.pcss"; @import "./views/rooms/RoomListPanel/_RoomListPanel.pcss"; @import "./views/rooms/RoomListPanel/_RoomListSearch.pcss"; diff --git a/res/css/views/rooms/RoomListPanel/_RoomList.pcss b/res/css/views/rooms/RoomListPanel/_RoomList.pcss new file mode 100644 index 0000000000..2563c1b675 --- /dev/null +++ b/res/css/views/rooms/RoomListPanel/_RoomList.pcss @@ -0,0 +1,15 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +.mx_RoomList { + height: 100%; + + .mx_RoomList_List { + /* Avoid when on hover, the background color to be on top of the right border */ + padding-right: 1px; + } +} diff --git a/res/css/views/rooms/RoomListPanel/_RoomListCell.pcss b/res/css/views/rooms/RoomListPanel/_RoomListCell.pcss new file mode 100644 index 0000000000..812145a73e --- /dev/null +++ b/res/css/views/rooms/RoomListPanel/_RoomListCell.pcss @@ -0,0 +1,44 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +/** + * The RoomCell has the following structure: + * button----------------------------------------| + * | <-12px-> container--------------------------| + * | | room avatar <-12px-> content-----| + * | | | room_name | + * | | | ----------| <-- border + * |---------------------------------------------| + */ +.mx_RoomListCell { + all: unset; + + &:hover { + background-color: var(--cpd-color-bg-action-secondary-hovered); + } + + .mx_RoomListCell_container { + padding-left: var(--cpd-space-3x); + font: var(--cpd-font-body-md-regular); + height: 100%; + + .mx_RoomListCell_content { + height: 100%; + flex: 1; + /* The border is only under the room name and the future hover menu */ + border-bottom: var(--cpd-border-width-0-5) solid var(--cpd-color-bg-subtle-secondary); + box-sizing: border-box; + min-width: 0; + + span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + } +} diff --git a/src/components/views/rooms/RoomListPanel/RoomList.tsx b/src/components/views/rooms/RoomListPanel/RoomList.tsx new file mode 100644 index 0000000000..3645a72bb9 --- /dev/null +++ b/src/components/views/rooms/RoomListPanel/RoomList.tsx @@ -0,0 +1,51 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import React, { useCallback, type JSX } from "react"; +import { AutoSizer, List, type ListRowProps } from "react-virtualized"; + +import { type RoomListViewState } from "../../../viewmodels/roomlist/RoomListViewModel"; +import { _t } from "../../../../languageHandler"; +import { RoomListCell } from "./RoomListCell"; + +interface RoomListProps { + /** + * The view model state for the room list. + */ + vm: RoomListViewState; +} + +/** + * A virtualized list of rooms. + */ +export function RoomList({ vm: { rooms, openRoom } }: RoomListProps): JSX.Element { + const roomRendererMemoized = useCallback( + ({ key, index, style }: ListRowProps) => ( + openRoom(rooms[index].roomId)} /> + ), + [rooms, openRoom], + ); + + // The first div is needed to make the virtualized list take all the remaining space and scroll correctly + return ( +
+ + {({ height, width }) => ( + + )} + +
+ ); +} diff --git a/src/components/views/rooms/RoomListPanel/RoomListCell.tsx b/src/components/views/rooms/RoomListPanel/RoomListCell.tsx new file mode 100644 index 0000000000..a5e9cc5df2 --- /dev/null +++ b/src/components/views/rooms/RoomListPanel/RoomListCell.tsx @@ -0,0 +1,44 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import React, { type JSX } from "react"; +import { type Room } from "matrix-js-sdk/src/matrix"; + +import { _t } from "../../../../languageHandler"; +import { Flex } from "../../../utils/Flex"; +import DecoratedRoomAvatar from "../../avatars/DecoratedRoomAvatar"; + +interface RoomListCellProps extends React.HTMLAttributes { + /** + * The room to display + */ + room: Room; +} + +/** + * A cell in the room list + */ +export function RoomListCell({ room, ...props }: RoomListCellProps): JSX.Element { + return ( + + ); +} diff --git a/src/components/views/rooms/RoomListPanel/RoomListPanel.tsx b/src/components/views/rooms/RoomListPanel/RoomListPanel.tsx index caa6241de7..291794399f 100644 --- a/src/components/views/rooms/RoomListPanel/RoomListPanel.tsx +++ b/src/components/views/rooms/RoomListPanel/RoomListPanel.tsx @@ -6,15 +6,13 @@ Please see LICENSE files in the repository root for full details. */ import React from "react"; -import { AutoSizer, List } from "react-virtualized"; -import type { ListRowProps } from "react-virtualized"; import { shouldShowComponent } from "../../../../customisations/helpers/UIComponents"; import { UIComponent } from "../../../../settings/UIFeature"; import { RoomListSearch } from "./RoomListSearch"; import { RoomListHeaderView } from "./RoomListHeaderView"; +import { RoomListView } from "./RoomListView"; import { Flex } from "../../../utils/Flex"; -import { useRoomListViewModel } from "../../../viewmodels/roomlist/RoomListViewModel"; type RoomListPanelProps = { /** @@ -29,15 +27,6 @@ type RoomListPanelProps = { */ export const RoomListPanel: React.FC = ({ activeSpace }) => { const displayRoomSearch = shouldShowComponent(UIComponent.FilterContainer); - const { rooms } = useRoomListViewModel(); - - const rowRenderer = ({ key, index, style }: ListRowProps): React.JSX.Element => { - return ( -
- {rooms[index].name} -
- ); - }; return ( = ({ activeSpace }) => > {displayRoomSearch && } - - {({ height, width }) => ( - - )} - + ); }; diff --git a/src/components/views/rooms/RoomListPanel/RoomListView.tsx b/src/components/views/rooms/RoomListPanel/RoomListView.tsx new file mode 100644 index 0000000000..6e7734c91a --- /dev/null +++ b/src/components/views/rooms/RoomListPanel/RoomListView.tsx @@ -0,0 +1,17 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import React, { type JSX } from "react"; + +import { useRoomListViewModel } from "../../../viewmodels/roomlist/RoomListViewModel"; +import { RoomList } from "./RoomList"; + +export function RoomListView(): JSX.Element { + const vm = useRoomListViewModel(); + // Room filters will be added soon + return ; +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 624beab0b8..c97a9ee331 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2097,12 +2097,16 @@ "one": "Currently joining %(count)s room", "other": "Currently joining %(count)s rooms" }, + "list_title": "Room list", "notification_options": "Notification options", "open_space_menu": "Open space menu", "redacting_messages_status": { "one": "Currently removing messages in %(count)s room", "other": "Currently removing messages in %(count)s rooms" }, + "room": { + "open_room": "Open room %(roomName)s" + }, "show_less": "Show less", "show_n_more": { "one": "Show %(count)s more",