Switch to rendering svg icons rather than masking them (#31550)

* Switch to rendering svg icons rather than masking them in SpacePanel

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix badly rendered icon in JoinRuleDropdown

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix badly rendered icon in RoomPreviewCard

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix badly rendered icon in Space menus

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix badly rendered icon in ThreadPanel

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update snapshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update screenshot

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove unused icon underfill

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update screenshot

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add test

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add missing snapshot

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2025-12-16 13:56:36 +00:00
committed by GitHub
parent 773662e018
commit 7e3a6d9c42
24 changed files with 645 additions and 319 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -79,6 +79,7 @@
@import "./structures/_SearchBox.pcss"; @import "./structures/_SearchBox.pcss";
@import "./structures/_SpaceHierarchy.pcss"; @import "./structures/_SpaceHierarchy.pcss";
@import "./structures/_SpacePanel.pcss"; @import "./structures/_SpacePanel.pcss";
@import "./structures/_SpacePillButton.pcss";
@import "./structures/_SpaceRoomView.pcss"; @import "./structures/_SpaceRoomView.pcss";
@import "./structures/_SplashPage.pcss"; @import "./structures/_SplashPage.pcss";
@import "./structures/_TabbedView.pcss"; @import "./structures/_TabbedView.pcss";
@@ -381,7 +382,6 @@
@import "./views/spaces/_SpaceBasicSettings.pcss"; @import "./views/spaces/_SpaceBasicSettings.pcss";
@import "./views/spaces/_SpaceChildrenPicker.pcss"; @import "./views/spaces/_SpaceChildrenPicker.pcss";
@import "./views/spaces/_SpaceCreateMenu.pcss"; @import "./views/spaces/_SpaceCreateMenu.pcss";
@import "./views/spaces/_SpacePublicShare.pcss";
@import "./views/terms/_InlineTermsAgreement.pcss"; @import "./views/terms/_InlineTermsAgreement.pcss";
@import "./views/toasts/_AnalyticsToast.pcss"; @import "./views/toasts/_AnalyticsToast.pcss";
@import "./views/toasts/_IncomingCallToast.pcss"; @import "./views/toasts/_IncomingCallToast.pcss";

View File

@@ -44,29 +44,23 @@ Please see LICENSE files in the repository root for full details.
top: 19px; /* v-align with avatar */ top: 19px; /* v-align with avatar */
right: -8px; right: -8px;
&::before { svg {
content: "";
position: absolute;
width: inherit;
height: inherit; height: inherit;
mask-position: center; width: inherit;
mask-size: contain; display: inline-block;
mask-repeat: no-repeat; color: $background;
background-color: $background; /* Slight alignment tweak to center the asset */
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg"); margin-left: 1px;
transform: rotate(270deg);
} }
&:not(.expanded) { &:not(.expanded) {
opacity: 0; opacity: 0;
&::before {
mask-position: center 1px;
}
} }
&.expanded::before { &.expanded svg {
transform: rotate(90deg); 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 { & > .mx_SpaceButton > .mx_SpaceButton_toggleCollapse {
padding: 0 10px; padding: 0 10px;
margin: 0 -10px; margin: 0 -10px;
transform: rotate(-90deg);
} }
& > .mx_SpaceTreeLevel { & > .mx_SpaceTreeLevel {
@@ -166,109 +159,67 @@ Please see LICENSE files in the repository root for full details.
} }
.mx_SpaceButton_toggleCollapse { .mx_SpaceButton_toggleCollapse {
width: var(--gutterSize);
padding: 10px 0;
min-width: var(--gutterSize);
height: 20px; height: 20px;
mask-position: center; width: var(--gutterSize);
mask-size: 20px; flex-shrink: 0;
mask-repeat: no-repeat; padding: 10px 0;
background-color: $tertiary-content;
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg"); svg {
width: 20px;
height: inherit;
display: inline-block;
color: $tertiary-content;
/* Re-align with parent */
margin-left: -3px;
}
} }
.mx_SpaceButton_icon { .mx_SpaceButton_icon {
width: var(--height-topLevel); /* Calculate height excluding padding to allow svg to inherit */
min-width: var(--height-topLevel); width: calc(var(--height-topLevel) - 14px);
height: var(--height-topLevel); height: calc(var(--height-topLevel) - 14px);
flex-shrink: 0;
border-radius: 8px; border-radius: 8px;
position: relative; padding: 7px;
&::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 {
background-color: $panel-actions; background-color: $panel-actions;
}
&.mx_SpaceButton_home .mx_SpaceButton_icon::before { svg {
mask-image: url("@vector-im/compound-design-tokens/icons/home-solid.svg"); width: inherit;
} height: inherit;
display: block;
&.mx_SpaceButton_favourites .mx_SpaceButton_icon::before { color: $secondary-content;
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");
} }
&.mx_SpaceButton_new .mx_SpaceButton_icon { &.mx_SpaceButton_new .mx_SpaceButton_icon {
&::before { background-color: unset;
background-color: $primary-content;
mask-image: url("@vector-im/compound-design-tokens/icons/plus.svg"); svg {
color: $primary-content;
transition: all 0.2s ease-in-out; /* TODO transition */ 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); transform: rotate(45deg);
} }
.mx_SpaceButton_menuButton { .mx_SpaceButton_menuButton {
width: 20px; width: 16px;
min-width: 20px; /* yay flex */ height: 16px;
height: 20px; padding: var(--cpd-space-0-5x);
flex-shrink: 0;
margin-top: auto; margin-top: auto;
margin-bottom: auto; margin-bottom: auto;
display: none; display: none;
position: absolute; position: absolute;
right: 4px; right: 4px;
&::before { svg {
top: 3px; width: inherit;
left: 2px; height: inherit;
content: ""; display: block;
width: 16px; color: $primary-content;
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;
} }
} }
} }
@@ -341,18 +292,6 @@ Please see LICENSE files in the repository root for full details.
padding: 0 0 16px 0; padding: 0 0 16px 0;
scrollbar-gutter: stable; scrollbar-gutter: stable;
& > .mx_SpaceButton {
height: var(--height-topLevel);
&.mx_SpaceButton_active::before {
height: var(--height-topLevel);
}
}
& > ul {
padding-left: 0;
}
&.mx_IndicatorScrollbar_topOverflow { &.mx_IndicatorScrollbar_topOverflow {
mask-image: linear-gradient(to bottom, transparent, black 16px); mask-image: linear-gradient(to bottom, transparent, black 16px);
} }

View File

@@ -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;
}
}
}

View File

@@ -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. 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 { .mx_SpaceRoomView {
--innerWidth: 428px; --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 {
.mx_SpaceRoomView_inviteTeammates_buttons { .mx_SpaceRoomView_inviteTeammates_buttons {
color: $secondary-content; color: $secondary-content;

View File

@@ -47,16 +47,12 @@ Please see LICENSE files in the repository root for full details.
background: $quinary-content; background: $quinary-content;
} }
&::before { svg {
margin-left: 2px; margin-left: 2px;
content: "";
width: 20px;
height: 20px; height: 20px;
background: currentColor; width: 20px;
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg"); display: inline-block;
mask-size: 100%; vertical-align: bottom;
mask-repeat: no-repeat;
float: right;
} }
} }
} }
@@ -181,25 +177,24 @@ Please see LICENSE files in the repository root for full details.
} }
&[aria-checked="true"] { &[aria-checked="true"] {
:first-child { span:first-child {
margin-left: -20px; margin-left: -20px;
} }
:first-child::before { svg {
content: "";
width: 12px; width: 12px;
height: 12px; height: 12px;
margin-right: 8px; margin-right: 8px;
mask-image: url("@vector-im/compound-design-tokens/icons/check.svg"); color: $primary-content;
mask-size: 100%;
mask-repeat: no-repeat;
background-color: $primary-content;
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
position: absolute;
top: 14px;
left: 10px;
} }
} }
:last-child { span:last-child {
color: $secondary-content; color: $secondary-content;
} }
} }

View File

@@ -833,7 +833,6 @@ $left-gutter: 64px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: contain; background-size: contain;
&::before,
&::after { &::after {
content: ""; content: "";
display: block; display: block;
@@ -844,10 +843,6 @@ $left-gutter: 64px;
mask-size: contain; mask-size: contain;
} }
&::before {
mask-size: 80%;
}
&.mx_EventTile_e2eIcon_warning::after { &.mx_EventTile_e2eIcon_warning::after {
mask-image: url("@vector-im/compound-design-tokens/icons/error-solid.svg"); mask-image: url("@vector-im/compound-design-tokens/icons/error-solid.svg");
background-color: $e2e-warning-color; /* red */ background-color: $e2e-warning-color; /* red */

View File

@@ -22,20 +22,13 @@ Please see LICENSE files in the repository root for full details.
line-height: $font-24px; line-height: $font-24px;
color: $primary-content; color: $primary-content;
margin-top: $spacing-24; margin-top: $spacing-24;
position: relative;
padding-left: calc(20px + $spacing-8);
&::before { svg {
content: ""; height: 1em;
position: absolute; width: 1em;
height: $font-24px; margin-right: $spacing-8;
width: 20px; color: $secondary-content;
left: 0; vertical-align: -2px;
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;
} }
} }
@@ -63,25 +56,19 @@ Please see LICENSE files in the repository root for full details.
align-items: center; align-items: center;
.mx_RoomPreviewCard_video { .mx_RoomPreviewCard_video {
width: 50px; width: 22px;
height: 50px; height: 22px;
padding: 14px;
border-radius: calc((50px + 2 * 3px) / 2); border-radius: calc((50px + 2 * 3px) / 2);
background-color: $accent; background-color: $accent;
border: 3px solid $system; border: 3px solid $system;
position: relative;
left: calc(-50px / 4 - 3px); left: calc(-50px / 4 - 3px);
&::before { svg {
content: ""; width: inherit;
background-color: $button-primary-fg-color; height: inherit;
position: absolute; color: $button-primary-fg-color;
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");
} }
} }

View File

@@ -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 { .mx_SpaceCreateMenu_back {
width: 28px; width: 28px;
height: 28px; height: 28px;

View File

@@ -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");
}
}
}

View File

@@ -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 (
<AccessibleButton className="mx_SpacePillButton" onClick={onClick}>
{icon}
{title}
<div>{description}</div>
</AccessibleButton>
);
};
export default SpacePillButton;

View File

@@ -10,7 +10,12 @@ import { EventType, RoomType, JoinRule, Preset, type Room, RoomEvent } from "mat
import { KnownMembership } from "matrix-js-sdk/src/types"; import { KnownMembership } from "matrix-js-sdk/src/types";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import React, { type JSX, useCallback, useContext, useRef, useState } from "react"; 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 MatrixClientContext from "../../contexts/MatrixClientContext";
import createRoom, { type IOpts } from "../../createRoom"; import createRoom, { type IOpts } from "../../createRoom";
@@ -68,6 +73,7 @@ import RightPanel from "./RightPanel";
import SpaceHierarchy, { showRoom } from "./SpaceHierarchy"; import SpaceHierarchy, { showRoom } from "./SpaceHierarchy";
import { type RoomPermalinkCreator } from "../../utils/permalinks/Permalinks"; import { type RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
import { Icon as HashVideoIcon } from "../../../res/img/element-icons/roomlist/hash-video.svg"; import { Icon as HashVideoIcon } from "../../../res/img/element-icons/roomlist/hash-video.svg";
import SpacePillButton from "./SpacePillButton.tsx";
interface IProps { interface IProps {
space: Room; space: Room;
@@ -455,24 +461,22 @@ const SpaceSetupPrivateScope: React.FC<{
})} })}
</div> </div>
<AccessibleButton <SpacePillButton
className="mx_SpaceRoomView_privateScope_justMeButton" icon={<UserProfileSolidIcon />}
title={_t("create_space|personal_space")}
description={_t("create_space|personal_space_description")}
onClick={() => { onClick={() => {
onFinished(false); onFinished(false);
}} }}
> />
{_t("create_space|personal_space")} <SpacePillButton
<div>{_t("create_space|personal_space_description")}</div> icon={<GroupIcon />}
</AccessibleButton> title={_t("create_space|private_space")}
<AccessibleButton description={_t("create_space|private_space_description")}
className="mx_SpaceRoomView_privateScope_meAndMyTeammatesButton"
onClick={() => { onClick={() => {
onFinished(true); onFinished(true);
}} }}
> />
{_t("create_space|private_space")}
<div>{_t("create_space|private_space_description")}</div>
</AccessibleButton>
</div> </div>
); );
}; };

View File

@@ -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 { type EventTimelineSet, type Room, Thread } from "matrix-js-sdk/src/matrix";
import { IconButton, Tooltip } from "@vector-im/compound-web"; import { IconButton, Tooltip } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger"; 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 { Icon as MarkAllThreadsReadIcon } from "../../../res/img/element-icons/check-all.svg";
import BaseCard from "../views/right_panel/BaseCard"; import BaseCard from "../views/right_panel/BaseCard";
@@ -57,6 +57,7 @@ export const ThreadPanelHeaderFilterOptionItem: React.FC<
> = ({ label, description, onClick, isSelected }) => { > = ({ label, description, onClick, isSelected }) => {
return ( return (
<MenuItemRadio active={isSelected} className="mx_ThreadPanel_Header_FilterOptionItem" onClick={onClick}> <MenuItemRadio active={isSelected} className="mx_ThreadPanel_Header_FilterOptionItem" onClick={onClick}>
{isSelected ? <CheckIcon /> : null}
<span>{label}</span> <span>{label}</span>
<span>{description}</span> <span>{description}</span>
</MenuItemRadio> </MenuItemRadio>
@@ -145,6 +146,7 @@ export const ThreadPanelHeader: React.FC<{
}} }}
> >
{`${_t("threads|show_thread_filter")} ${value?.label}`} {`${_t("threads|show_thread_filter")} ${value?.label}`}
<ChevronDownIcon />
</ContextMenuButton> </ContextMenuButton>
{contextMenu} {contextMenu}
</div> </div>

View File

@@ -57,7 +57,7 @@ const JoinRuleDropdown: React.FC<IProps> = ({
options.unshift( options.unshift(
( (
<div key={JoinRule.Knock} className="mx_JoinRuleDropdown_knock"> <div key={JoinRule.Knock} className="mx_JoinRuleDropdown_knock">
<AskToJoinIcon className="mx_Icon mx_Icon_16 mx_JoinRuleDropdown_icon" /> <AskToJoinIcon />
{labelKnock} {labelKnock}
</div> </div>
) as ReactElement & { key: string }, ) as ReactElement & { key: string },

View File

@@ -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 React, { type JSX, type FC, useContext, useState } from "react";
import { type Room, JoinRule } from "matrix-js-sdk/src/matrix"; import { type Room, JoinRule } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types"; 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 { _t } from "../../../languageHandler";
import defaultDispatcher from "../../../dispatcher/dispatcher"; import defaultDispatcher from "../../../dispatcher/dispatcher";
@@ -152,7 +153,9 @@ const RoomPreviewCard: FC<IProps> = ({ room, onJoinButtonClicked, onRejectButton
avatarRow = ( avatarRow = (
<> <>
<RoomAvatar room={room} size="50px" viewAvatarOnClick /> <RoomAvatar room={room} size="50px" viewAvatarOnClick />
<div className="mx_RoomPreviewCard_video" /> <div className="mx_RoomPreviewCard_video">
<VideoCallSolidIcon />
</div>
<BetaPill onClick={viewLabs} tooltipTitle={_t("labs|video_rooms_beta")} /> <BetaPill onClick={viewLabs} tooltipTitle={_t("labs|video_rooms_beta")} />
</> </>
); );
@@ -174,6 +177,7 @@ const RoomPreviewCard: FC<IProps> = ({ room, onJoinButtonClicked, onRejectButton
{room.getJoinRule() === "public" && <RoomFacePile room={room} />} {room.getJoinRule() === "public" && <RoomFacePile room={room} />}
{cannotJoin ? ( {cannotJoin ? (
<div className="mx_RoomPreviewCard_notice"> <div className="mx_RoomPreviewCard_notice">
<InfoSolidIcon />
{_t("room|join_failed_needs_invite", { roomName: room.name })} {_t("room|join_failed_needs_invite", { roomName: room.name })}
</div> </div>
) : null} ) : null}

View File

@@ -18,7 +18,6 @@ import React, {
type ReactNode, type ReactNode,
useEffect, useEffect,
} from "react"; } from "react";
import classNames from "classnames";
import { import {
RoomType, RoomType,
HistoryVisibility, HistoryVisibility,
@@ -28,6 +27,7 @@ import {
type ICreateRoomOpts, type ICreateRoomOpts,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; 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 { _t } from "../../../languageHandler";
import ContextMenu, { ChevronFace } from "../../structures/ContextMenu"; 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 { type OpenSpotlightPayload } from "../../../dispatcher/payloads/OpenSpotlightPayload.ts";
import { useSettingValue } from "../../../hooks/useSettings.ts"; import { useSettingValue } from "../../../hooks/useSettings.ts";
import { UIFeature } from "../../../settings/UIFeature.ts"; import { UIFeature } from "../../../settings/UIFeature.ts";
import SpacePillButton from "../../structures/SpacePillButton.tsx";
export const createSpace = async ( export const createSpace = async (
client: MatrixClient, 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 (
<AccessibleButton className={classNames("mx_SpaceCreateMenuType", className)} onClick={onClick}>
{title}
<div>{description}</div>
</AccessibleButton>
);
};
const spaceNameValidator = withValidation({ const spaceNameValidator = withValidation({
rules: [ rules: [
{ {
@@ -285,16 +272,16 @@ const SpaceCreateMenu: React.FC<{
<h2>{_t("create_space|label")}</h2> <h2>{_t("create_space|label")}</h2>
<p>{_t("create_space|explainer")}</p> <p>{_t("create_space|explainer")}</p>
<SpaceCreateMenuType <SpacePillButton
icon={<PublicIcon />}
title={_t("common|public")} title={_t("common|public")}
description={_t("create_space|public_description")} description={_t("create_space|public_description")}
className="mx_SpaceCreateMenuType_public"
onClick={() => setVisibility(Visibility.Public)} onClick={() => setVisibility(Visibility.Public)}
/> />
<SpaceCreateMenuType <SpacePillButton
icon={<LockSolidIcon />}
title={_t("common|private")} title={_t("common|private")}
description={_t("create_space|private_description")} description={_t("create_space|private_description")}
className="mx_SpaceCreateMenuType_private"
onClick={() => setVisibility(Visibility.Private)} onClick={() => setVisibility(Visibility.Private)}
/> />

View File

@@ -22,6 +22,15 @@ import React, {
import { DragDropContext, Draggable, Droppable, type DroppableProvidedProps } from "react-beautiful-dnd"; import { DragDropContext, Draggable, Droppable, type DroppableProvidedProps } from "react-beautiful-dnd";
import classNames from "classnames"; import classNames from "classnames";
import { type Room } from "matrix-js-sdk/src/matrix"; 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 { _t } from "../../../languageHandler";
import { useContextMenu } from "../../structures/ContextMenu"; import { useContextMenu } from "../../structures/ContextMenu";
@@ -114,6 +123,7 @@ export const HomeButtonContextMenu: React.FC<ComponentProps<typeof SpaceContextM
interface IMetaSpaceButtonProps extends ComponentProps<typeof SpaceButton> { interface IMetaSpaceButtonProps extends ComponentProps<typeof SpaceButton> {
selected: boolean; selected: boolean;
isPanelCollapsed: boolean; isPanelCollapsed: boolean;
icon: JSX.Element;
} }
type MetaSpaceButtonProps = Pick<IMetaSpaceButtonProps, "selected" | "isPanelCollapsed">; type MetaSpaceButtonProps = Pick<IMetaSpaceButtonProps, "selected" | "isPanelCollapsed">;
@@ -152,7 +162,6 @@ const HomeButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollapsed
return ( return (
<MetaSpaceButton <MetaSpaceButton
spaceKey={MetaSpace.Home} spaceKey={MetaSpace.Home}
className="mx_SpaceButton_home"
selected={selected} selected={selected}
isPanelCollapsed={isPanelCollapsed} isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.Home, allRoomsInHome)} label={getMetaSpaceName(MetaSpace.Home, allRoomsInHome)}
@@ -160,6 +169,7 @@ const HomeButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollapsed
ContextMenuComponent={HomeButtonContextMenu} ContextMenuComponent={HomeButtonContextMenu}
contextMenuTooltip={_t("common|options")} contextMenuTooltip={_t("common|options")}
size="32px" size="32px"
icon={<HomeSolidIcon />}
/> />
); );
}; };
@@ -168,12 +178,12 @@ const FavouritesButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCol
return ( return (
<MetaSpaceButton <MetaSpaceButton
spaceKey={MetaSpace.Favourites} spaceKey={MetaSpace.Favourites}
className="mx_SpaceButton_favourites"
selected={selected} selected={selected}
isPanelCollapsed={isPanelCollapsed} isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.Favourites)} label={getMetaSpaceName(MetaSpace.Favourites)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.Favourites)} notificationState={SpaceStore.instance.getNotificationState(MetaSpace.Favourites)}
size="32px" size="32px"
icon={<FavouriteSolidIcon />}
/> />
); );
}; };
@@ -182,12 +192,12 @@ const PeopleButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollaps
return ( return (
<MetaSpaceButton <MetaSpaceButton
spaceKey={MetaSpace.People} spaceKey={MetaSpace.People}
className="mx_SpaceButton_people"
selected={selected} selected={selected}
isPanelCollapsed={isPanelCollapsed} isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.People)} label={getMetaSpaceName(MetaSpace.People)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.People)} notificationState={SpaceStore.instance.getNotificationState(MetaSpace.People)}
size="32px" size="32px"
icon={<UserProfileSolidIcon />}
/> />
); );
}; };
@@ -196,12 +206,12 @@ const OrphansButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollap
return ( return (
<MetaSpaceButton <MetaSpaceButton
spaceKey={MetaSpace.Orphans} spaceKey={MetaSpace.Orphans}
className="mx_SpaceButton_orphans"
selected={selected} selected={selected}
isPanelCollapsed={isPanelCollapsed} isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.Orphans)} label={getMetaSpaceName(MetaSpace.Orphans)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.Orphans)} notificationState={SpaceStore.instance.getNotificationState(MetaSpace.Orphans)}
size="32px" size="32px"
icon={<RoomIcon />}
/> />
); );
}; };
@@ -210,12 +220,12 @@ const VideoRoomsButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCol
return ( return (
<MetaSpaceButton <MetaSpaceButton
spaceKey={MetaSpace.VideoRooms} spaceKey={MetaSpace.VideoRooms}
className="mx_SpaceButton_videoRooms"
selected={selected} selected={selected}
isPanelCollapsed={isPanelCollapsed} isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.VideoRooms)} label={getMetaSpaceName(MetaSpace.VideoRooms)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.VideoRooms)} notificationState={SpaceStore.instance.getNotificationState(MetaSpace.VideoRooms)}
size="32px" size="32px"
icon={<VideoCallSolidIcon />}
/> />
); );
}; };
@@ -262,6 +272,7 @@ const CreateSpaceButton: React.FC<Pick<IInnerSpacePanelProps, "isPanelCollapsed"
isNarrow={isPanelCollapsed} isNarrow={isPanelCollapsed}
innerRef={handle} innerRef={handle}
size="32px" size="32px"
icon={<PlusIcon />}
/> />
{contextMenu} {contextMenu}
@@ -449,7 +460,9 @@ const SpacePanel: React.FC = () => {
className="mx_SpacePanel_Tooltip_KeyboardShortcut" className="mx_SpacePanel_Tooltip_KeyboardShortcut"
/> />
} }
/> >
<ChevronRightIcon />
</AccessibleButton>
</UserMenu> </UserMenu>
<Droppable droppableId="top-level-spaces"> <Droppable droppableId="top-level-spaces">
{(provided, snapshot) => ( {(provided, snapshot) => (

View File

@@ -9,15 +9,17 @@ Please see LICENSE files in the repository root for full details.
import React, { useState } from "react"; import React, { useState } from "react";
import { type Room } from "matrix-js-sdk/src/matrix"; import { type Room } from "matrix-js-sdk/src/matrix";
import { sleep } from "matrix-js-sdk/src/utils"; import { sleep } from "matrix-js-sdk/src/utils";
import { LinkIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import AccessibleButton from "../elements/AccessibleButton";
import { copyPlaintext } from "../../../utils/strings"; import { copyPlaintext } from "../../../utils/strings";
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import { showRoomInviteDialog } from "../../../RoomInvite"; import { showRoomInviteDialog } from "../../../RoomInvite";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { UIComponent } from "../../../settings/UIFeature"; 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 { interface IProps {
space: Room; space: Room;
@@ -29,8 +31,10 @@ const SpacePublicShare: React.FC<IProps> = ({ space, onFinished }) => {
return ( return (
<div className="mx_SpacePublicShare"> <div className="mx_SpacePublicShare">
<AccessibleButton <SpacePillButton
className="mx_SpacePublicShare_shareButton" icon={<LinkIcon />}
title={_t("space|invite_link")}
description={copiedText}
onClick={async (): Promise<void> => { onClick={async (): Promise<void> => {
const permalinkCreator = new RoomPermalinkCreator(space); const permalinkCreator = new RoomPermalinkCreator(space);
permalinkCreator.load(); permalinkCreator.load();
@@ -43,22 +47,18 @@ const SpacePublicShare: React.FC<IProps> = ({ space, onFinished }) => {
setCopiedText(_t("action|click_to_copy")); setCopiedText(_t("action|click_to_copy"));
} }
}} }}
> />
{_t("space|invite_link")}
<div>{copiedText}</div>
</AccessibleButton>
{space.canInvite(MatrixClientPeg.safeGet().getSafeUserId()) && {space.canInvite(MatrixClientPeg.safeGet().getSafeUserId()) &&
shouldShowComponent(UIComponent.InviteUsers) ? ( shouldShowComponent(UIComponent.InviteUsers) ? (
<AccessibleButton <SpacePillButton
className="mx_SpacePublicShare_inviteButton" icon={<InviteIcon />}
title={_t("space|invite")}
description={_t("space|invite_description")}
onClick={() => { onClick={() => {
if (onFinished) onFinished(); if (onFinished) onFinished();
showRoomInviteDialog(space.roomId); showRoomInviteDialog(space.roomId);
}} }}
> />
{_t("space|invite")}
<div>{_t("space|invite_description")}</div>
</AccessibleButton>
) : null} ) : null}
</div> </div>
); );

View File

@@ -20,6 +20,11 @@ import classNames from "classnames";
import { type Room, RoomEvent } from "matrix-js-sdk/src/matrix"; import { type Room, RoomEvent } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types"; import { KnownMembership } from "matrix-js-sdk/src/types";
import { type DraggableProvidedDragHandleProps } from "react-beautiful-dnd"; 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 RoomAvatar from "../avatars/RoomAvatar";
import SpaceStore from "../../../stores/spaces/SpaceStore"; import SpaceStore from "../../../stores/spaces/SpaceStore";
@@ -169,7 +174,9 @@ export const SpaceButton = <T extends keyof HTMLElementTagNameMap>({
onClick={openMenu} onClick={openMenu}
title={contextMenuTooltip} title={contextMenuTooltip}
isExpanded={menuDisplayed} isExpanded={menuDisplayed}
/> >
<OverflowHorizontalIcon />
</ContextMenuTooltipButton>
)} )}
{contextMenu} {contextMenu}
@@ -349,7 +356,9 @@ export class SpaceItem extends React.PureComponent<IItemProps, IItemState> {
onClick={this.toggleCollapse} onClick={this.toggleCollapse}
tabIndex={-1} tabIndex={-1}
aria-label={collapsed ? _t("action|expand") : _t("action|collapse")} aria-label={collapsed ? _t("action|expand") : _t("action|collapse")}
/> >
{collapsed ? <ChevronRightIcon /> : <ChevronDownIcon />}
</AccessibleButton>
) : null; ) : null;
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars

View File

@@ -34,6 +34,17 @@ exports[`ThreadPanel Header expect that All filter for ThreadPanelHeader properl
tabindex="0" tabindex="0"
> >
Show: All threads Show: All threads
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 14.95q-.2 0-.375-.062a.9.9 0 0 1-.325-.213l-4.6-4.6a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l3.9 3.9 3.9-3.9a.95.95 0 0 1 .7-.275q.425 0 .7.275a.95.95 0 0 1 .275.7.95.95 0 0 1-.275.7l-4.6 4.6q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</div> </div>
</div> </div>
</DocumentFragment> </DocumentFragment>
@@ -73,6 +84,17 @@ exports[`ThreadPanel Header expect that My filter for ThreadPanelHeader properly
tabindex="0" tabindex="0"
> >
Show: My threads Show: My threads
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 14.95q-.2 0-.375-.062a.9.9 0 0 1-.325-.213l-4.6-4.6a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l3.9 3.9 3.9-3.9a.95.95 0 0 1 .7-.275q.425 0 .7.275a.95.95 0 0 1 .275.7.95.95 0 0 1-.275.7l-4.6 4.6q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</div> </div>
</div> </div>
</DocumentFragment> </DocumentFragment>
@@ -85,6 +107,17 @@ exports[`ThreadPanel Header expect that ThreadPanelHeader has the correct option
role="menuitemradio" role="menuitemradio"
tabindex="0" tabindex="0"
> >
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
<span> <span>
All threads All threads
</span> </span>

View File

@@ -8,13 +8,14 @@ Please see LICENSE files in the repository root for full details.
import React from "react"; import React from "react";
import { fireEvent, getByTestId, render } from "jest-matrix-react"; import { fireEvent, getByTestId, render } from "jest-matrix-react";
import { mocked } from "jest-mock";
import { mkRoom, stubClient } from "../../../../test-utils"; import { mkRoom, stubClient } from "../../../../test-utils";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg"; import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import DMRoomMap from "../../../../../src/utils/DMRoomMap"; import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import defaultDispatcher from "../../../../../src/dispatcher/dispatcher"; import defaultDispatcher from "../../../../../src/dispatcher/dispatcher";
import { Action } from "../../../../../src/dispatcher/actions"; 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 { MetaSpace, type SpaceKey } from "../../../../../src/stores/spaces";
import SpaceStore from "../../../../../src/stores/spaces/SpaceStore"; import SpaceStore from "../../../../../src/stores/spaces/SpaceStore";
import { StaticNotificationState } from "../../../../../src/stores/notifications/StaticNotificationState"; import { StaticNotificationState } from "../../../../../src/stores/notifications/StaticNotificationState";
@@ -26,6 +27,8 @@ jest.mock("../../../../../src/stores/spaces/SpaceStore", () => {
class MockSpaceStore extends EventEmitter { class MockSpaceStore extends EventEmitter {
activeSpace: SpaceKey = "!space1"; activeSpace: SpaceKey = "!space1";
setActiveSpace = jest.fn(); setActiveSpace = jest.fn();
getChildSpaces = jest.fn();
getNotificationState = jest.fn();
} }
return { instance: new MockSpaceStore() }; 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(<SpaceItem space={space} activeSpaces={[]} />);
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();
});
});

View File

@@ -41,7 +41,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
class="mx_AccessibleButton mx_SpacePanel_toggleCollapse" class="mx_AccessibleButton mx_SpacePanel_toggleCollapse"
role="button" role="button"
tabindex="0" tabindex="0"
/> >
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.7 17.3a.95.95 0 0 1-.275-.7q0-.425.275-.7l3.9-3.9-3.9-3.9a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l4.6 4.6q.15.15.213.325.062.175.062.375t-.062.375a.9.9 0 0 1-.213.325l-4.6 4.6a.95.95 0 0 1-.7.275.95.95 0 0 1-.7-.275"
/>
</svg>
</div>
</div> </div>
<ul <ul
aria-label="Spaces" aria-label="Spaces"
@@ -58,7 +70,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
aria-label="Home" aria-label="Home"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_home mx_SpaceButton_narrow" class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_narrow mx_SpaceButton_withIcon"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -73,7 +85,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
class="mx_SpaceButton_icon" class="mx_SpaceButton_icon"
/> >
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m12.971 3.54 7 3.889A2 2 0 0 1 21 9.177V19a2 2 0 0 1-2 2h-4v-9H9v9H5a2 2 0 0 1-2-2V9.177a2 2 0 0 1 1.029-1.748l7-3.89a2 2 0 0 1 1.942 0"
/>
</svg>
</div>
</div> </div>
</div> </div>
<div <div
@@ -83,7 +107,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
class="mx_AccessibleButton mx_SpaceButton_menuButton" class="mx_AccessibleButton mx_SpaceButton_menuButton"
role="button" role="button"
tabindex="0" tabindex="0"
/> >
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 14q-.824 0-1.412-.588A1.93 1.93 0 0 1 4 12q0-.825.588-1.412A1.93 1.93 0 0 1 6 10q.824 0 1.412.588Q8 11.175 8 12t-.588 1.412A1.93 1.93 0 0 1 6 14m6 0q-.825 0-1.412-.588A1.93 1.93 0 0 1 10 12q0-.825.588-1.412A1.93 1.93 0 0 1 12 10q.825 0 1.412.588Q14 11.175 14 12t-.588 1.412A1.93 1.93 0 0 1 12 14m6 0q-.824 0-1.413-.588A1.93 1.93 0 0 1 16 12q0-.825.587-1.412A1.93 1.93 0 0 1 18 10q.824 0 1.413.588Q20 11.175 20 12t-.587 1.412A1.93 1.93 0 0 1 18 14"
/>
</svg>
</div>
</div> </div>
</div> </div>
</li> </li>
@@ -94,7 +130,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
aria-label="Favourites" aria-label="Favourites"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_favourites mx_SpaceButton_narrow" class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_narrow mx_SpaceButton_withIcon"
role="button" role="button"
tabindex="-1" tabindex="-1"
> >
@@ -109,7 +145,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
class="mx_SpaceButton_icon" class="mx_SpaceButton_icon"
/> >
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m12.897 2.817 2.336 4.733 5.223.76a1 1 0 0 1 .555 1.705L17.23 13.7l.892 5.202a1 1 0 0 1-1.45 1.054L12 17.5l-4.672 2.456a1 1 0 0 1-1.451-1.054l.892-5.202-3.78-3.685a1 1 0 0 1 .555-1.706l5.223-.759 2.336-4.733a1 1 0 0 1 1.794 0"
/>
</svg>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -122,7 +170,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
aria-label="People" aria-label="People"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_people mx_SpaceButton_narrow" class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_narrow mx_SpaceButton_withIcon"
role="button" role="button"
tabindex="-1" tabindex="-1"
> >
@@ -137,7 +185,22 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
class="mx_SpaceButton_icon" class="mx_SpaceButton_icon"
/> >
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 15q-1.65 0-2.825-1.175T8 11t1.175-2.825T12 7t2.825 1.175T16 11t-1.175 2.825T12 15"
/>
<path
d="M19.528 18.583A9.96 9.96 0 0 0 22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 2.52.933 4.824 2.472 6.583A9.98 9.98 0 0 0 12 22a9.98 9.98 0 0 0 7.528-3.417M8.75 16.388q-1.373.332-2.709.95a8 8 0 1 1 11.918 0 14.7 14.7 0 0 0-2.709-.95A13.8 13.8 0 0 0 12 16q-1.65 0-3.25.387"
/>
</svg>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -150,7 +213,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
aria-label="Other rooms" aria-label="Other rooms"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_orphans mx_SpaceButton_narrow" class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_narrow mx_SpaceButton_withIcon"
role="button" role="button"
tabindex="-1" tabindex="-1"
> >
@@ -165,7 +228,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
class="mx_SpaceButton_icon" class="mx_SpaceButton_icon"
/> >
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m8.566 17-.944 4.094q-.086.406-.372.656t-.687.25q-.543 0-.887-.469a1.18 1.18 0 0 1-.2-1.031l.801-3.5H3.158q-.572 0-.916-.484a1.27 1.27 0 0 1-.2-1.078 1.12 1.12 0 0 1 1.116-.938H6.85l1.145-5h-3.12q-.57 0-.915-.484a1.27 1.27 0 0 1-.2-1.078A1.12 1.12 0 0 1 4.875 7h3.691l.945-4.094q.085-.406.372-.656.286-.25.686-.25.544 0 .887.469.345.468.2 1.031l-.8 3.5h4.578l.944-4.094q.085-.406.372-.656.286-.25.687-.25.543 0 .887.469t.2 1.031L17.723 7h3.119q.573 0 .916.484.343.485.2 1.079a1.12 1.12 0 0 1-1.116.937H17.15l-1.145 5h3.12q.57 0 .915.484.343.485.2 1.079a1.12 1.12 0 0 1-1.116.937h-3.691l-.944 4.094q-.087.406-.373.656t-.686.25q-.544 0-.887-.469a1.18 1.18 0 0 1-.2-1.031l.8-3.5zm.573-2.5h4.578l1.144-5h-4.578z"
/>
</svg>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -178,7 +253,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
aria-label="Conferences" aria-label="Conferences"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_videoRooms mx_SpaceButton_narrow" class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_narrow mx_SpaceButton_withIcon"
role="button" role="button"
tabindex="-1" tabindex="-1"
> >
@@ -193,7 +268,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
class="mx_SpaceButton_icon" class="mx_SpaceButton_icon"
/> >
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4"
/>
</svg>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -206,7 +293,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
aria-label="Create a space" aria-label="Create a space"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_new mx_SpaceButton_narrow" class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_new mx_SpaceButton_narrow mx_SpaceButton_withIcon"
data-testid="create-space-button" data-testid="create-space-button"
role="button" role="button"
tabindex="-1" tabindex="-1"
@@ -222,7 +309,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
> >
<div <div
class="mx_SpaceButton_icon" class="mx_SpaceButton_icon"
/> >
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11 13H6a.97.97 0 0 1-.713-.287A.97.97 0 0 1 5 12q0-.424.287-.713A.97.97 0 0 1 6 11h5V6q0-.424.287-.713A.97.97 0 0 1 12 5q.424 0 .713.287Q13 5.576 13 6v5h5q.424 0 .712.287.288.288.288.713 0 .424-.288.713A.97.97 0 0 1 18 13h-5v5q0 .424-.287.712A.97.97 0 0 1 12 19a.97.97 0 0 1-.713-.288A.97.97 0 0 1 11 18z"
/>
</svg>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -47,3 +47,251 @@ exports[`SpaceButton metaspace should render notificationState if one is provide
</div> </div>
</DocumentFragment> </DocumentFragment>
`; `;
exports[`SpaceItem should render a space with subspaces 1`] = `
<DocumentFragment>
<li
aria-expanded="false"
aria-selected="false"
class="mx_SpaceItem collapsed hasSubSpaces"
role="treeitem"
>
<div
aria-label="Root Space"
class="mx_AccessibleButton mx_SpaceButton"
role="button"
tabindex="-1"
>
<div
aria-label="Expand"
class="mx_AccessibleButton mx_SpaceButton_toggleCollapse"
role="button"
tabindex="-1"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.7 17.3a.95.95 0 0 1-.275-.7q0-.425.275-.7l3.9-3.9-3.9-3.9a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l4.6 4.6q.15.15.213.325.062.175.062.375t-.062.375a.9.9 0 0 1-.213.325l-4.6 4.6a.95.95 0 0 1-.7.275.95.95 0 0 1-.7-.275"
/>
</svg>
</div>
<div
class="mx_SpaceButton_selectionWrapper"
>
<div
class="mx_SpaceButton_avatarWrapper"
>
<span
aria-label="Avatar"
class="_avatar_zysgz_8 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
style="--cpd-avatar-size: 32px;"
>
<img
alt=""
class="_image_zysgz_43"
data-type="round"
height="32px"
loading="lazy"
referrerpolicy="no-referrer"
src="http://this.is.a.url/avatar.url/room.png"
width="32px"
/>
</span>
</div>
<span
class="mx_SpaceButton_name"
>
Root Space
</span>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="Space options"
class="mx_AccessibleButton mx_SpaceButton_menuButton"
role="button"
tabindex="0"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 14q-.824 0-1.412-.588A1.93 1.93 0 0 1 4 12q0-.825.588-1.412A1.93 1.93 0 0 1 6 10q.824 0 1.412.588Q8 11.175 8 12t-.588 1.412A1.93 1.93 0 0 1 6 14m6 0q-.825 0-1.412-.588A1.93 1.93 0 0 1 10 12q0-.825.588-1.412A1.93 1.93 0 0 1 12 10q.825 0 1.412.588Q14 11.175 14 12t-.588 1.412A1.93 1.93 0 0 1 12 14m6 0q-.824 0-1.413-.588A1.93 1.93 0 0 1 16 12q0-.825.587-1.412A1.93 1.93 0 0 1 18 10q.824 0 1.413.588Q20 11.175 20 12t-.587 1.412A1.93 1.93 0 0 1 18 14"
/>
</svg>
</div>
</div>
</div>
</li>
</DocumentFragment>
`;
exports[`SpaceItem should render a space with subspaces 2`] = `
<DocumentFragment>
<li
aria-expanded="true"
aria-selected="false"
class="mx_SpaceItem hasSubSpaces"
role="treeitem"
>
<div
aria-label="Root Space"
class="mx_AccessibleButton mx_SpaceButton"
role="button"
tabindex="-1"
>
<div
aria-label="Collapse"
class="mx_AccessibleButton mx_SpaceButton_toggleCollapse"
role="button"
tabindex="-1"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 14.95q-.2 0-.375-.062a.9.9 0 0 1-.325-.213l-4.6-4.6a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l3.9 3.9 3.9-3.9a.95.95 0 0 1 .7-.275q.425 0 .7.275a.95.95 0 0 1 .275.7.95.95 0 0 1-.275.7l-4.6 4.6q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</div>
<div
class="mx_SpaceButton_selectionWrapper"
>
<div
class="mx_SpaceButton_avatarWrapper"
>
<span
aria-label="Avatar"
class="_avatar_zysgz_8 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
style="--cpd-avatar-size: 32px;"
>
<img
alt=""
class="_image_zysgz_43"
data-type="round"
height="32px"
loading="lazy"
referrerpolicy="no-referrer"
src="http://this.is.a.url/avatar.url/room.png"
width="32px"
/>
</span>
</div>
<span
class="mx_SpaceButton_name"
>
Root Space
</span>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="Space options"
class="mx_AccessibleButton mx_SpaceButton_menuButton"
role="button"
tabindex="0"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 14q-.824 0-1.412-.588A1.93 1.93 0 0 1 4 12q0-.825.588-1.412A1.93 1.93 0 0 1 6 10q.824 0 1.412.588Q8 11.175 8 12t-.588 1.412A1.93 1.93 0 0 1 6 14m6 0q-.825 0-1.412-.588A1.93 1.93 0 0 1 10 12q0-.825.588-1.412A1.93 1.93 0 0 1 12 10q.825 0 1.412.588Q14 11.175 14 12t-.588 1.412A1.93 1.93 0 0 1 12 14m6 0q-.824 0-1.413-.588A1.93 1.93 0 0 1 16 12q0-.825.587-1.412A1.93 1.93 0 0 1 18 10q.824 0 1.413.588Q20 11.175 20 12t-.587 1.412A1.93 1.93 0 0 1 18 14"
/>
</svg>
</div>
</div>
</div>
<ul
class="mx_SpaceTreeLevel"
role="group"
>
<li
aria-selected="false"
class="mx_SpaceItem"
role="treeitem"
>
<div
aria-label="Subspace"
class="mx_AccessibleButton mx_SpaceButton"
role="button"
tabindex="-1"
>
<div
class="mx_SpaceButton_selectionWrapper"
>
<div
class="mx_SpaceButton_avatarWrapper"
>
<span
aria-label="Avatar"
class="_avatar_zysgz_8 mx_BaseAvatar"
data-color="4"
data-testid="avatar-img"
data-type="round"
style="--cpd-avatar-size: 24px;"
>
<img
alt=""
class="_image_zysgz_43"
data-type="round"
height="24px"
loading="lazy"
referrerpolicy="no-referrer"
src="http://this.is.a.url/avatar.url/room.png"
width="24px"
/>
</span>
</div>
<span
class="mx_SpaceButton_name"
>
Subspace
</span>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="Space options"
class="mx_AccessibleButton mx_SpaceButton_menuButton"
role="button"
tabindex="0"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 14q-.824 0-1.412-.588A1.93 1.93 0 0 1 4 12q0-.825.588-1.412A1.93 1.93 0 0 1 6 10q.824 0 1.412.588Q8 11.175 8 12t-.588 1.412A1.93 1.93 0 0 1 6 14m6 0q-.825 0-1.412-.588A1.93 1.93 0 0 1 10 12q0-.825.588-1.412A1.93 1.93 0 0 1 12 10q.825 0 1.412.588Q14 11.175 14 12t-.588 1.412A1.93 1.93 0 0 1 12 14m6 0q-.824 0-1.413-.588A1.93 1.93 0 0 1 16 12q0-.825.587-1.412A1.93 1.93 0 0 1 18 10q.824 0 1.413.588Q20 11.175 20 12t-.587 1.412A1.93 1.93 0 0 1 18 14"
/>
</svg>
</div>
</div>
</div>
</li>
</ul>
</li>
</DocumentFragment>
`;