diff --git a/playwright/snapshots/spaces/threads-activity-centre/threadsActivityCentre.spec.ts/tac-hovered-linux.png b/playwright/snapshots/spaces/threads-activity-centre/threadsActivityCentre.spec.ts/tac-hovered-linux.png index 5884f6f56f..40f1243619 100644 Binary files a/playwright/snapshots/spaces/threads-activity-centre/threadsActivityCentre.spec.ts/tac-hovered-linux.png and b/playwright/snapshots/spaces/threads-activity-centre/threadsActivityCentre.spec.ts/tac-hovered-linux.png differ diff --git a/playwright/snapshots/threads/threads.spec.ts/thread-panel-linux.png b/playwright/snapshots/threads/threads.spec.ts/thread-panel-linux.png index 3c78fa1679..f0871c7625 100644 Binary files a/playwright/snapshots/threads/threads.spec.ts/thread-panel-linux.png and b/playwright/snapshots/threads/threads.spec.ts/thread-panel-linux.png differ diff --git a/res/css/_components.pcss b/res/css/_components.pcss index e78c27df0f..9711c1b064 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -79,6 +79,7 @@ @import "./structures/_SearchBox.pcss"; @import "./structures/_SpaceHierarchy.pcss"; @import "./structures/_SpacePanel.pcss"; +@import "./structures/_SpacePillButton.pcss"; @import "./structures/_SpaceRoomView.pcss"; @import "./structures/_SplashPage.pcss"; @import "./structures/_TabbedView.pcss"; @@ -381,7 +382,6 @@ @import "./views/spaces/_SpaceBasicSettings.pcss"; @import "./views/spaces/_SpaceChildrenPicker.pcss"; @import "./views/spaces/_SpaceCreateMenu.pcss"; -@import "./views/spaces/_SpacePublicShare.pcss"; @import "./views/terms/_InlineTermsAgreement.pcss"; @import "./views/toasts/_AnalyticsToast.pcss"; @import "./views/toasts/_IncomingCallToast.pcss"; diff --git a/res/css/structures/_SpacePanel.pcss b/res/css/structures/_SpacePanel.pcss index 177a0752ed..a20e26403d 100644 --- a/res/css/structures/_SpacePanel.pcss +++ b/res/css/structures/_SpacePanel.pcss @@ -44,29 +44,23 @@ Please see LICENSE files in the repository root for full details. top: 19px; /* v-align with avatar */ right: -8px; - &::before { - content: ""; - position: absolute; - width: inherit; + svg { height: inherit; - mask-position: center; - mask-size: contain; - mask-repeat: no-repeat; - background-color: $background; - mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg"); - transform: rotate(270deg); + width: inherit; + display: inline-block; + color: $background; + /* Slight alignment tweak to center the asset */ + margin-left: 1px; } &:not(.expanded) { opacity: 0; - - &::before { - mask-position: center 1px; - } } - &.expanded::before { - transform: rotate(90deg); + &.expanded svg { + transform: rotate(180deg); + /* Slight alignment tweak to center the asset */ + margin-left: -1px; } } @@ -103,7 +97,6 @@ Please see LICENSE files in the repository root for full details. & > .mx_SpaceButton > .mx_SpaceButton_toggleCollapse { padding: 0 10px; margin: 0 -10px; - transform: rotate(-90deg); } & > .mx_SpaceTreeLevel { @@ -166,109 +159,67 @@ Please see LICENSE files in the repository root for full details. } .mx_SpaceButton_toggleCollapse { - width: var(--gutterSize); - padding: 10px 0; - min-width: var(--gutterSize); height: 20px; - mask-position: center; - mask-size: 20px; - mask-repeat: no-repeat; - background-color: $tertiary-content; - mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg"); + width: var(--gutterSize); + flex-shrink: 0; + padding: 10px 0; + + svg { + width: 20px; + height: inherit; + display: inline-block; + color: $tertiary-content; + /* Re-align with parent */ + margin-left: -3px; + } } .mx_SpaceButton_icon { - width: var(--height-topLevel); - min-width: var(--height-topLevel); - height: var(--height-topLevel); + /* Calculate height excluding padding to allow svg to inherit */ + width: calc(var(--height-topLevel) - 14px); + height: calc(var(--height-topLevel) - 14px); + flex-shrink: 0; border-radius: 8px; - position: relative; - - &::before { - position: absolute; - content: ""; - width: var(--height-topLevel); - height: var(--height-topLevel); - top: 0; - left: 0; - mask-position: center; - mask-repeat: no-repeat; - mask-size: 18px; - } - } - - &.mx_SpaceButton_home, - &.mx_SpaceButton_favourites, - &.mx_SpaceButton_people, - &.mx_SpaceButton_orphans, - &.mx_SpaceButton_videoRooms { - .mx_SpaceButton_icon { - background-color: $panel-actions; - - &::before { - background-color: $secondary-content; - } - } - } - - &.mx_SpaceButton_withIcon .mx_SpaceButton_icon { + padding: 7px; background-color: $panel-actions; - } - &.mx_SpaceButton_home .mx_SpaceButton_icon::before { - mask-image: url("@vector-im/compound-design-tokens/icons/home-solid.svg"); - } - - &.mx_SpaceButton_favourites .mx_SpaceButton_icon::before { - mask-image: url("@vector-im/compound-design-tokens/icons/favourite-solid.svg"); - } - - &.mx_SpaceButton_people .mx_SpaceButton_icon::before { - mask-image: url("@vector-im/compound-design-tokens/icons/user-profile-solid.svg"); - } - - &.mx_SpaceButton_orphans .mx_SpaceButton_icon::before { - mask-image: url("@vector-im/compound-design-tokens/icons/room.svg"); - } - - &.mx_SpaceButton_videoRooms .mx_SpaceButton_icon::before { - mask-image: url("@vector-im/compound-design-tokens/icons/video-call-solid.svg"); + svg { + width: inherit; + height: inherit; + display: block; + color: $secondary-content; + } } &.mx_SpaceButton_new .mx_SpaceButton_icon { - &::before { - background-color: $primary-content; - mask-image: url("@vector-im/compound-design-tokens/icons/plus.svg"); + background-color: unset; + + svg { + color: $primary-content; transition: all 0.2s ease-in-out; /* TODO transition */ } } - &.mx_SpaceButton_newCancel .mx_SpaceButton_icon::before { + &.mx_SpaceButton_newCancel .mx_SpaceButton_icon svg { transform: rotate(45deg); } .mx_SpaceButton_menuButton { - width: 20px; - min-width: 20px; /* yay flex */ - height: 20px; + width: 16px; + height: 16px; + padding: var(--cpd-space-0-5x); + flex-shrink: 0; margin-top: auto; margin-bottom: auto; display: none; position: absolute; right: 4px; - &::before { - top: 3px; - left: 2px; - content: ""; - width: 16px; - height: 16px; - position: absolute; - mask-position: center; - mask-size: contain; - mask-repeat: no-repeat; - mask-image: url("@vector-im/compound-design-tokens/icons/overflow-horizontal.svg"); - background: $primary-content; + svg { + width: inherit; + height: inherit; + display: block; + color: $primary-content; } } } @@ -341,18 +292,6 @@ Please see LICENSE files in the repository root for full details. padding: 0 0 16px 0; scrollbar-gutter: stable; - & > .mx_SpaceButton { - height: var(--height-topLevel); - - &.mx_SpaceButton_active::before { - height: var(--height-topLevel); - } - } - - & > ul { - padding-left: 0; - } - &.mx_IndicatorScrollbar_topOverflow { mask-image: linear-gradient(to bottom, transparent, black 16px); } diff --git a/res/css/structures/_SpacePillButton.pcss b/res/css/structures/_SpacePillButton.pcss new file mode 100644 index 0000000000..eed2feb48a --- /dev/null +++ b/res/css/structures/_SpacePillButton.pcss @@ -0,0 +1,48 @@ +/* +Copyright 2025 Element Creations 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_SpacePillButton { + position: relative; + padding: 16px 32px 16px 72px; + width: 432px; + box-sizing: border-box; + border-radius: 8px; + border: 1px solid $input-border-color; + font-size: $font-17px; + font-weight: var(--cpd-font-weight-semibold); + margin: 20px 0; + + > div { + margin-top: 4px; + font-weight: normal; + font-size: $font-15px; + color: $secondary-content; + } + + svg { + position: absolute; + content: ""; + width: 28px; + height: 28px; + top: 50%; + transform: translateY(-50%); + left: 22px; + color: $tertiary-content; + } + + &:hover { + border-color: var(--cpd-color-bg-action-primary-rest); + + svg { + color: var(--cpd-color-icon-primary); + } + + > span { + color: $primary-content; + } + } +} diff --git a/res/css/structures/_SpaceRoomView.pcss b/res/css/structures/_SpaceRoomView.pcss index 7f00386b85..589e30b515 100644 --- a/res/css/structures/_SpaceRoomView.pcss +++ b/res/css/structures/_SpaceRoomView.pcss @@ -6,51 +6,6 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -@define-mixin SpacePillButton { - position: relative; - padding: 16px 32px 16px 72px; - width: 432px; - box-sizing: border-box; - border-radius: 8px; - border: 1px solid $input-border-color; - font-size: $font-17px; - font-weight: var(--cpd-font-weight-semibold); - margin: 20px 0; - - > div { - margin-top: 4px; - font-weight: normal; - font-size: $font-15px; - color: $secondary-content; - } - - &::before { - position: absolute; - content: ""; - width: 28px; - height: 28px; - top: 50%; - transform: translateY(-50%); - left: 22px; - mask-position: center; - mask-repeat: no-repeat; - mask-size: 28px; - background-color: $tertiary-content; - } - - &:hover { - border-color: var(--cpd-color-bg-action-primary-rest); - - &::before { - background-color: var(--cpd-color-icon-primary); - } - - > span { - color: $primary-content; - } - } -} - .mx_SpaceRoomView { --innerWidth: 428px; @@ -242,20 +197,6 @@ Please see LICENSE files in the repository root for full details. } } - .mx_SpaceRoomView_privateScope { - > .mx_AccessibleButton { - @mixin SpacePillButton; - } - - .mx_SpaceRoomView_privateScope_justMeButton::before { - mask-image: url("@vector-im/compound-design-tokens/icons/user-profile-solid.svg"); - } - - .mx_SpaceRoomView_privateScope_meAndMyTeammatesButton::before { - mask-image: url("@vector-im/compound-design-tokens/icons/group.svg"); - } - } - .mx_SpaceRoomView_inviteTeammates { .mx_SpaceRoomView_inviteTeammates_buttons { color: $secondary-content; diff --git a/res/css/views/right_panel/_ThreadPanel.pcss b/res/css/views/right_panel/_ThreadPanel.pcss index 2a282388eb..a5a6540dda 100644 --- a/res/css/views/right_panel/_ThreadPanel.pcss +++ b/res/css/views/right_panel/_ThreadPanel.pcss @@ -47,16 +47,12 @@ Please see LICENSE files in the repository root for full details. background: $quinary-content; } - &::before { + svg { margin-left: 2px; - content: ""; - width: 20px; height: 20px; - background: currentColor; - mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg"); - mask-size: 100%; - mask-repeat: no-repeat; - float: right; + width: 20px; + display: inline-block; + vertical-align: bottom; } } } @@ -181,25 +177,24 @@ Please see LICENSE files in the repository root for full details. } &[aria-checked="true"] { - :first-child { + span:first-child { margin-left: -20px; } - :first-child::before { - content: ""; + svg { width: 12px; height: 12px; margin-right: 8px; - mask-image: url("@vector-im/compound-design-tokens/icons/check.svg"); - mask-size: 100%; - mask-repeat: no-repeat; - background-color: $primary-content; + color: $primary-content; display: inline-block; vertical-align: middle; + position: absolute; + top: 14px; + left: 10px; } } - :last-child { + span:last-child { color: $secondary-content; } } diff --git a/res/css/views/rooms/_EventTile.pcss b/res/css/views/rooms/_EventTile.pcss index f04afccb13..8b9a8f46e1 100644 --- a/res/css/views/rooms/_EventTile.pcss +++ b/res/css/views/rooms/_EventTile.pcss @@ -833,7 +833,6 @@ $left-gutter: 64px; background-repeat: no-repeat; background-size: contain; - &::before, &::after { content: ""; display: block; @@ -844,10 +843,6 @@ $left-gutter: 64px; mask-size: contain; } - &::before { - mask-size: 80%; - } - &.mx_EventTile_e2eIcon_warning::after { mask-image: url("@vector-im/compound-design-tokens/icons/error-solid.svg"); background-color: $e2e-warning-color; /* red */ diff --git a/res/css/views/rooms/_RoomPreviewCard.pcss b/res/css/views/rooms/_RoomPreviewCard.pcss index 61afe0d92b..7ad0f20e79 100644 --- a/res/css/views/rooms/_RoomPreviewCard.pcss +++ b/res/css/views/rooms/_RoomPreviewCard.pcss @@ -22,20 +22,13 @@ Please see LICENSE files in the repository root for full details. line-height: $font-24px; color: $primary-content; margin-top: $spacing-24; - position: relative; - padding-left: calc(20px + $spacing-8); - &::before { - content: ""; - position: absolute; - height: $font-24px; - width: 20px; - left: 0; - mask-repeat: no-repeat; - mask-position: center; - mask-size: contain; - mask-image: url("@vector-im/compound-design-tokens/icons/info-solid.svg"); - background-color: $secondary-content; + svg { + height: 1em; + width: 1em; + margin-right: $spacing-8; + color: $secondary-content; + vertical-align: -2px; } } @@ -63,25 +56,19 @@ Please see LICENSE files in the repository root for full details. align-items: center; .mx_RoomPreviewCard_video { - width: 50px; - height: 50px; + width: 22px; + height: 22px; + padding: 14px; border-radius: calc((50px + 2 * 3px) / 2); background-color: $accent; border: 3px solid $system; - position: relative; left: calc(-50px / 4 - 3px); - &::before { - content: ""; - background-color: $button-primary-fg-color; - position: absolute; - width: 50px; - height: 50px; - mask-size: 22px; - mask-position: center; - mask-repeat: no-repeat; - mask-image: url("@vector-im/compound-design-tokens/icons/video-call-solid.svg"); + svg { + width: inherit; + height: inherit; + color: $button-primary-fg-color; } } diff --git a/res/css/views/spaces/_SpaceCreateMenu.pcss b/res/css/views/spaces/_SpaceCreateMenu.pcss index ca2a2c8fc1..8bc7f6e3ad 100644 --- a/res/css/views/spaces/_SpaceCreateMenu.pcss +++ b/res/css/views/spaces/_SpaceCreateMenu.pcss @@ -34,18 +34,6 @@ Please see LICENSE files in the repository root for full details. } } - .mx_SpaceCreateMenuType { - @mixin SpacePillButton; - } - - .mx_SpaceCreateMenuType_public::before { - mask-image: url("@vector-im/compound-design-tokens/icons/public.svg"); - } - - .mx_SpaceCreateMenuType_private::before { - mask-image: url("@vector-im/compound-design-tokens/icons/lock-solid.svg"); - } - .mx_SpaceCreateMenu_back { width: 28px; height: 28px; diff --git a/res/css/views/spaces/_SpacePublicShare.pcss b/res/css/views/spaces/_SpacePublicShare.pcss deleted file mode 100644 index b55c0e685c..0000000000 --- a/res/css/views/spaces/_SpacePublicShare.pcss +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2021 The Matrix.org Foundation C.I.C. - -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_SpacePublicShare { - .mx_AccessibleButton { - @mixin SpacePillButton; - - &.mx_SpacePublicShare_shareButton::before { - mask-image: url("@vector-im/compound-design-tokens/icons/link.svg"); - } - - &.mx_SpacePublicShare_inviteButton::before { - mask-image: url("$(res)/img/element-icons/room/invite.svg"); - } - } -} diff --git a/src/components/structures/SpacePillButton.tsx b/src/components/structures/SpacePillButton.tsx new file mode 100644 index 0000000000..0093e2911b --- /dev/null +++ b/src/components/structures/SpacePillButton.tsx @@ -0,0 +1,27 @@ +/* +Copyright 2025 Element Creations 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 AccessibleButton from "../views/elements/AccessibleButton"; + +const SpacePillButton: React.FC<{ + title: string; + icon: JSX.Element; + description: string; + onClick(): void; +}> = ({ title, icon, description, onClick }) => { + return ( + + {icon} + {title} +
{description}
+
+ ); +}; + +export default SpacePillButton; diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index c1758a87c7..1df95439d4 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -10,7 +10,12 @@ import { EventType, RoomType, JoinRule, Preset, type Room, RoomEvent } from "mat import { KnownMembership } from "matrix-js-sdk/src/types"; import { logger } from "matrix-js-sdk/src/logger"; import React, { type JSX, useCallback, useContext, useRef, useState } from "react"; -import { PlusIcon, RoomIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; +import { + GroupIcon, + PlusIcon, + RoomIcon, + UserProfileSolidIcon, +} from "@vector-im/compound-design-tokens/assets/web/icons"; import MatrixClientContext from "../../contexts/MatrixClientContext"; import createRoom, { type IOpts } from "../../createRoom"; @@ -68,6 +73,7 @@ import RightPanel from "./RightPanel"; import SpaceHierarchy, { showRoom } from "./SpaceHierarchy"; import { type RoomPermalinkCreator } from "../../utils/permalinks/Permalinks"; import { Icon as HashVideoIcon } from "../../../res/img/element-icons/roomlist/hash-video.svg"; +import SpacePillButton from "./SpacePillButton.tsx"; interface IProps { space: Room; @@ -455,24 +461,22 @@ const SpaceSetupPrivateScope: React.FC<{ })} - } + title={_t("create_space|personal_space")} + description={_t("create_space|personal_space_description")} onClick={() => { onFinished(false); }} - > - {_t("create_space|personal_space")} -
{_t("create_space|personal_space_description")}
-
- + } + title={_t("create_space|private_space")} + description={_t("create_space|private_space_description")} onClick={() => { onFinished(true); }} - > - {_t("create_space|private_space")} -
{_t("create_space|private_space_description")}
-
+ /> ); }; diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index 0657ab64c0..61386574ea 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -10,7 +10,7 @@ import React, { useContext, useEffect, useRef, useState } from "react"; import { type EventTimelineSet, type Room, Thread } from "matrix-js-sdk/src/matrix"; import { IconButton, Tooltip } from "@vector-im/compound-web"; import { logger } from "matrix-js-sdk/src/logger"; -import ThreadsIcon from "@vector-im/compound-design-tokens/assets/web/icons/threads"; +import { ThreadsIcon, CheckIcon, ChevronDownIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { Icon as MarkAllThreadsReadIcon } from "../../../res/img/element-icons/check-all.svg"; import BaseCard from "../views/right_panel/BaseCard"; @@ -57,6 +57,7 @@ export const ThreadPanelHeaderFilterOptionItem: React.FC< > = ({ label, description, onClick, isSelected }) => { return ( + {isSelected ? : null} {label} {description} @@ -145,6 +146,7 @@ export const ThreadPanelHeader: React.FC<{ }} > {`${_t("threads|show_thread_filter")} ${value?.label}`} + {contextMenu} diff --git a/src/components/views/elements/JoinRuleDropdown.tsx b/src/components/views/elements/JoinRuleDropdown.tsx index ac94112f2b..3ba27c1988 100644 --- a/src/components/views/elements/JoinRuleDropdown.tsx +++ b/src/components/views/elements/JoinRuleDropdown.tsx @@ -57,7 +57,7 @@ const JoinRuleDropdown: React.FC = ({ options.unshift( (
- + {labelKnock}
) as ReactElement & { key: string }, diff --git a/src/components/views/rooms/RoomPreviewCard.tsx b/src/components/views/rooms/RoomPreviewCard.tsx index 21f6e09a6d..5ddce5264b 100644 --- a/src/components/views/rooms/RoomPreviewCard.tsx +++ b/src/components/views/rooms/RoomPreviewCard.tsx @@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details. import React, { type JSX, type FC, useContext, useState } from "react"; import { type Room, JoinRule } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; +import { InfoSolidIcon, VideoCallSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { _t } from "../../../languageHandler"; import defaultDispatcher from "../../../dispatcher/dispatcher"; @@ -152,7 +153,9 @@ const RoomPreviewCard: FC = ({ room, onJoinButtonClicked, onRejectButton avatarRow = ( <> -
+
+ +
); @@ -174,6 +177,7 @@ const RoomPreviewCard: FC = ({ room, onJoinButtonClicked, onRejectButton {room.getJoinRule() === "public" && } {cannotJoin ? (
+ {_t("room|join_failed_needs_invite", { roomName: room.name })}
) : null} diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index 6b881e33a8..bed090b164 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -18,7 +18,6 @@ import React, { type ReactNode, useEffect, } from "react"; -import classNames from "classnames"; import { RoomType, HistoryVisibility, @@ -28,6 +27,7 @@ import { type ICreateRoomOpts, } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; +import { LockSolidIcon, PublicIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { _t } from "../../../languageHandler"; import ContextMenu, { ChevronFace } from "../../structures/ContextMenu"; @@ -47,6 +47,7 @@ import { Filter } from "../dialogs/spotlight/Filter"; import { type OpenSpotlightPayload } from "../../../dispatcher/payloads/OpenSpotlightPayload.ts"; import { useSettingValue } from "../../../hooks/useSettings.ts"; import { UIFeature } from "../../../settings/UIFeature.ts"; +import SpacePillButton from "../../structures/SpacePillButton.tsx"; export const createSpace = async ( client: MatrixClient, @@ -86,20 +87,6 @@ export const createSpace = async ( }); }; -const SpaceCreateMenuType: React.FC<{ - title: string; - description: string; - className: string; - onClick(): void; -}> = ({ title, description, className, onClick }) => { - return ( - - {title} -
{description}
-
- ); -}; - const spaceNameValidator = withValidation({ rules: [ { @@ -285,16 +272,16 @@ const SpaceCreateMenu: React.FC<{

{_t("create_space|label")}

{_t("create_space|explainer")}

- } title={_t("common|public")} description={_t("create_space|public_description")} - className="mx_SpaceCreateMenuType_public" onClick={() => setVisibility(Visibility.Public)} /> - } title={_t("common|private")} description={_t("create_space|private_description")} - className="mx_SpaceCreateMenuType_private" onClick={() => setVisibility(Visibility.Private)} /> diff --git a/src/components/views/spaces/SpacePanel.tsx b/src/components/views/spaces/SpacePanel.tsx index 0b4b558482..fb2e4cc1df 100644 --- a/src/components/views/spaces/SpacePanel.tsx +++ b/src/components/views/spaces/SpacePanel.tsx @@ -22,6 +22,15 @@ import React, { import { DragDropContext, Draggable, Droppable, type DroppableProvidedProps } from "react-beautiful-dnd"; import classNames from "classnames"; import { type Room } from "matrix-js-sdk/src/matrix"; +import { + FavouriteSolidIcon, + HomeSolidIcon, + RoomIcon, + VideoCallSolidIcon, + UserProfileSolidIcon, + PlusIcon, + ChevronRightIcon, +} from "@vector-im/compound-design-tokens/assets/web/icons"; import { _t } from "../../../languageHandler"; import { useContextMenu } from "../../structures/ContextMenu"; @@ -114,6 +123,7 @@ export const HomeButtonContextMenu: React.FC { selected: boolean; isPanelCollapsed: boolean; + icon: JSX.Element; } type MetaSpaceButtonProps = Pick; @@ -152,7 +162,6 @@ const HomeButton: React.FC = ({ selected, isPanelCollapsed return ( = ({ selected, isPanelCollapsed ContextMenuComponent={HomeButtonContextMenu} contextMenuTooltip={_t("common|options")} size="32px" + icon={} /> ); }; @@ -168,12 +178,12 @@ const FavouritesButton: React.FC = ({ selected, isPanelCol return ( } /> ); }; @@ -182,12 +192,12 @@ const PeopleButton: React.FC = ({ selected, isPanelCollaps return ( } /> ); }; @@ -196,12 +206,12 @@ const OrphansButton: React.FC = ({ selected, isPanelCollap return ( } /> ); }; @@ -210,12 +220,12 @@ const VideoRoomsButton: React.FC = ({ selected, isPanelCol return ( } /> ); }; @@ -262,6 +272,7 @@ const CreateSpaceButton: React.FC} /> {contextMenu} @@ -449,7 +460,9 @@ const SpacePanel: React.FC = () => { className="mx_SpacePanel_Tooltip_KeyboardShortcut" /> } - /> + > + + {(provided, snapshot) => ( diff --git a/src/components/views/spaces/SpacePublicShare.tsx b/src/components/views/spaces/SpacePublicShare.tsx index c3a9fae562..4bb2bdb78d 100644 --- a/src/components/views/spaces/SpacePublicShare.tsx +++ b/src/components/views/spaces/SpacePublicShare.tsx @@ -9,15 +9,17 @@ Please see LICENSE files in the repository root for full details. import React, { useState } from "react"; import { type Room } from "matrix-js-sdk/src/matrix"; import { sleep } from "matrix-js-sdk/src/utils"; +import { LinkIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { _t } from "../../../languageHandler"; -import AccessibleButton from "../elements/AccessibleButton"; import { copyPlaintext } from "../../../utils/strings"; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { showRoomInviteDialog } from "../../../RoomInvite"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; import { UIComponent } from "../../../settings/UIFeature"; +import { Icon as InviteIcon } from "../../../../res/img/element-icons/room/invite.svg"; +import SpacePillButton from "../../structures/SpacePillButton.tsx"; interface IProps { space: Room; @@ -29,8 +31,10 @@ const SpacePublicShare: React.FC = ({ space, onFinished }) => { return (
- } + title={_t("space|invite_link")} + description={copiedText} onClick={async (): Promise => { const permalinkCreator = new RoomPermalinkCreator(space); permalinkCreator.load(); @@ -43,22 +47,18 @@ const SpacePublicShare: React.FC = ({ space, onFinished }) => { setCopiedText(_t("action|click_to_copy")); } }} - > - {_t("space|invite_link")} -
{copiedText}
-
+ /> {space.canInvite(MatrixClientPeg.safeGet().getSafeUserId()) && shouldShowComponent(UIComponent.InviteUsers) ? ( - } + title={_t("space|invite")} + description={_t("space|invite_description")} onClick={() => { if (onFinished) onFinished(); showRoomInviteDialog(space.roomId); }} - > - {_t("space|invite")} -
{_t("space|invite_description")}
-
+ /> ) : null}
); diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index f2c41c367f..94ba7cff3e 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -20,6 +20,11 @@ import classNames from "classnames"; import { type Room, RoomEvent } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; import { type DraggableProvidedDragHandleProps } from "react-beautiful-dnd"; +import { + ChevronDownIcon, + ChevronRightIcon, + OverflowHorizontalIcon, +} from "@vector-im/compound-design-tokens/assets/web/icons"; import RoomAvatar from "../avatars/RoomAvatar"; import SpaceStore from "../../../stores/spaces/SpaceStore"; @@ -169,7 +174,9 @@ export const SpaceButton = ({ onClick={openMenu} title={contextMenuTooltip} isExpanded={menuDisplayed} - /> + > + + )} {contextMenu} @@ -349,7 +356,9 @@ export class SpaceItem extends React.PureComponent { onClick={this.toggleCollapse} tabIndex={-1} aria-label={collapsed ? _t("action|expand") : _t("action|collapse")} - /> + > + {collapsed ? : } + ) : null; // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/test/unit-tests/components/structures/__snapshots__/ThreadPanel-test.tsx.snap b/test/unit-tests/components/structures/__snapshots__/ThreadPanel-test.tsx.snap index f7487da90c..84ee81bdd5 100644 --- a/test/unit-tests/components/structures/__snapshots__/ThreadPanel-test.tsx.snap +++ b/test/unit-tests/components/structures/__snapshots__/ThreadPanel-test.tsx.snap @@ -34,6 +34,17 @@ exports[`ThreadPanel Header expect that All filter for ThreadPanelHeader properl tabindex="0" > Show: All threads + + +
@@ -73,6 +84,17 @@ exports[`ThreadPanel Header expect that My filter for ThreadPanelHeader properly tabindex="0" > Show: My threads + + + @@ -85,6 +107,17 @@ exports[`ThreadPanel Header expect that ThreadPanelHeader has the correct option role="menuitemradio" tabindex="0" > + + + All threads diff --git a/test/unit-tests/components/views/spaces/SpaceTreeLevel-test.tsx b/test/unit-tests/components/views/spaces/SpaceTreeLevel-test.tsx index c46b9681a9..2dd6ac5016 100644 --- a/test/unit-tests/components/views/spaces/SpaceTreeLevel-test.tsx +++ b/test/unit-tests/components/views/spaces/SpaceTreeLevel-test.tsx @@ -8,13 +8,14 @@ Please see LICENSE files in the repository root for full details. import React from "react"; import { fireEvent, getByTestId, render } from "jest-matrix-react"; +import { mocked } from "jest-mock"; import { mkRoom, stubClient } from "../../../../test-utils"; import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg"; import DMRoomMap from "../../../../../src/utils/DMRoomMap"; import defaultDispatcher from "../../../../../src/dispatcher/dispatcher"; import { Action } from "../../../../../src/dispatcher/actions"; -import { SpaceButton } from "../../../../../src/components/views/spaces/SpaceTreeLevel"; +import { SpaceItem, SpaceButton } from "../../../../../src/components/views/spaces/SpaceTreeLevel"; import { MetaSpace, type SpaceKey } from "../../../../../src/stores/spaces"; import SpaceStore from "../../../../../src/stores/spaces/SpaceStore"; import { StaticNotificationState } from "../../../../../src/stores/notifications/StaticNotificationState"; @@ -26,6 +27,8 @@ jest.mock("../../../../../src/stores/spaces/SpaceStore", () => { class MockSpaceStore extends EventEmitter { activeSpace: SpaceKey = "!space1"; setActiveSpace = jest.fn(); + getChildSpaces = jest.fn(); + getNotificationState = jest.fn(); } return { instance: new MockSpaceStore() }; @@ -127,3 +130,28 @@ describe("SpaceButton", () => { }); }); }); + +describe("SpaceItem", () => { + const cli = stubClient(); + const space = mkRoom(cli, "!1:example.org"); + space.name = "Root Space"; + const subspace = mkRoom(cli, "!2:example.org"); + subspace.name = "Subspace"; + + it("should render a space with subspaces", () => { + mocked(SpaceStore.instance.getChildSpaces).mockImplementation((spaceId) => + spaceId === space.roomId ? [subspace] : [], + ); + + const { asFragment, queryByText, getByLabelText } = render(); + + expect(queryByText("Root Space")).toBeVisible(); + expect(queryByText("Subspace")).toBeNull(); + expect(asFragment()).toMatchSnapshot(); + + fireEvent.click(getByLabelText("Expand")); + expect(queryByText("Root Space")).toBeVisible(); + expect(queryByText("Subspace")).toBeVisible(); + expect(asFragment()).toMatchSnapshot(); + }); +}); diff --git a/test/unit-tests/components/views/spaces/__snapshots__/SpacePanel-test.tsx.snap b/test/unit-tests/components/views/spaces/__snapshots__/SpacePanel-test.tsx.snap index c6fdc70948..a72f55978c 100644 --- a/test/unit-tests/components/views/spaces/__snapshots__/SpacePanel-test.tsx.snap +++ b/test/unit-tests/components/views/spaces/__snapshots__/SpacePanel-test.tsx.snap @@ -41,7 +41,19 @@ exports[` should show all activated MetaSpaces in the correct orde class="mx_AccessibleButton mx_SpacePanel_toggleCollapse" role="button" tabindex="0" - /> + > + + + +
    should show all activated MetaSpaces in the correct orde >
    @@ -73,7 +85,19 @@ exports[` should show all activated MetaSpaces in the correct orde >
    + > + + + +
    should show all activated MetaSpaces in the correct orde class="mx_AccessibleButton mx_SpaceButton_menuButton" role="button" tabindex="0" - /> + > + + + +
    @@ -94,7 +130,7 @@ exports[` should show all activated MetaSpaces in the correct orde >
    @@ -109,7 +145,19 @@ exports[` should show all activated MetaSpaces in the correct orde >
    + > + + + +
    @@ -122,7 +170,7 @@ exports[` should show all activated MetaSpaces in the correct orde >
    @@ -137,7 +185,22 @@ exports[` should show all activated MetaSpaces in the correct orde >
    + > + + + + +
    @@ -150,7 +213,7 @@ exports[` should show all activated MetaSpaces in the correct orde >
    @@ -165,7 +228,19 @@ exports[` should show all activated MetaSpaces in the correct orde >
    + > + + + +
    @@ -178,7 +253,7 @@ exports[` should show all activated MetaSpaces in the correct orde >
    @@ -193,7 +268,19 @@ exports[` should show all activated MetaSpaces in the correct orde >
    + > + + + +
    @@ -206,7 +293,7 @@ exports[` should show all activated MetaSpaces in the correct orde >
    should show all activated MetaSpaces in the correct orde >
    + > + + + +
    diff --git a/test/unit-tests/components/views/spaces/__snapshots__/SpaceTreeLevel-test.tsx.snap b/test/unit-tests/components/views/spaces/__snapshots__/SpaceTreeLevel-test.tsx.snap index e1f470f70a..64e735bb66 100644 --- a/test/unit-tests/components/views/spaces/__snapshots__/SpaceTreeLevel-test.tsx.snap +++ b/test/unit-tests/components/views/spaces/__snapshots__/SpaceTreeLevel-test.tsx.snap @@ -47,3 +47,251 @@ exports[`SpaceButton metaspace should render notificationState if one is provide `; + +exports[`SpaceItem should render a space with subspaces 1`] = ` + + + +`; + +exports[`SpaceItem should render a space with subspaces 2`] = ` + +
  • +
    +
    + + + +
    +
    +
    + + + +
    + + Root Space + + +
    +
    +
      +
    • +
      +
      +
      + + + +
      + + Subspace + + +
      +
      +
    • +
    +
  • +
    +`;