New right panel visual language (#11664)

* New right panel visual language

* Upgrade Compound

* Align old room header with right panel

* Rigth panel look and feel

* Fix linting and e2e tests

* Update snapshot

* Add test

* Lint

* Remove screenshot local script

* Update snapshots and UI based on feedback

* fix i18n key

* Update right panel visuals

* Fix tests

* lintfixes

* fix tests

* fix tests

* Add tests for search icon

* Fix invite dialog spec
This commit is contained in:
Germain 2023-10-20 14:30:37 +01:00 committed by GitHub
parent a63b99f687
commit f784a085fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 331 additions and 342 deletions

View file

@ -308,7 +308,7 @@ export default class RightPanel extends React.Component<Props, IState> {
}
return (
<aside className="mx_RightPanel dark-panel" id="mx_RightPanel">
<aside className="mx_RightPanel" id="mx_RightPanel">
{card}
</aside>
);

View file

@ -2587,27 +2587,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
<EffectsOverlay roomWidth={this.roomView.current.offsetWidth} />
)}
<ErrorBoundary>
{SettingsStore.getValue("feature_new_room_decoration_ui") ? (
<RoomHeader room={this.state.room} />
) : (
<LegacyRoomHeader
room={this.state.room}
searchInfo={this.state.search}
oobData={this.props.oobData}
inRoom={myMembership === "join"}
onSearchClick={onSearchClick}
onInviteClick={onInviteClick}
onForgetClick={showForgetButton ? onForgetClick : null}
e2eStatus={this.state.e2eStatus}
onAppsClick={this.state.hasPinnedWidgets ? onAppsClick : null}
appsShown={this.state.showApps}
excludedRightPanelPhaseButtons={excludedRightPanelPhaseButtons}
showButtons={!this.viewsLocalRoom}
enableRoomOptionsMenu={!this.viewsLocalRoom}
viewingCall={viewingCall}
activeCall={this.state.activeCall}
/>
)}
<MainSplit
panel={rightPanel}
resizeNotifier={this.props.resizeNotifier}
@ -2621,6 +2600,27 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
ref={this.roomViewBody}
data-layout={this.state.layout}
>
{SettingsStore.getValue("feature_new_room_decoration_ui") ? (
<RoomHeader room={this.state.room} />
) : (
<LegacyRoomHeader
room={this.state.room}
searchInfo={this.state.search}
oobData={this.props.oobData}
inRoom={myMembership === "join"}
onSearchClick={onSearchClick}
onInviteClick={onInviteClick}
onForgetClick={showForgetButton ? onForgetClick : null}
e2eStatus={this.state.e2eStatus}
onAppsClick={this.state.hasPinnedWidgets ? onAppsClick : null}
appsShown={this.state.showApps}
excludedRightPanelPhaseButtons={excludedRightPanelPhaseButtons}
showButtons={!this.viewsLocalRoom}
enableRoomOptionsMenu={!this.viewsLocalRoom}
viewingCall={viewingCall}
activeCall={this.state.activeCall}
/>
)}
{mainSplitBody}
</div>
</MainSplit>

View file

@ -46,7 +46,7 @@ type FlexProps = {
* The justification of the flex children
* @default start
*/
justify?: "start" | "center" | "end" | "between";
justify?: "start" | "center" | "end" | "space-between";
/**
* The spacing between the flex children, expressed with the CSS unit
* @default 0

View file

@ -25,7 +25,7 @@ import { backLabelForPhase } from "../../../stores/right-panel/RightPanelStorePh
import { CardContext } from "./context";
interface IProps {
header?: ReactNode;
header?: ReactNode | null;
footer?: ReactNode;
className?: string;
withoutScrollContainer?: boolean;
@ -86,11 +86,13 @@ const BaseCard: React.FC<IProps> = forwardRef<HTMLDivElement, IProps>(
return (
<CardContext.Provider value={{ isCard: true }}>
<div className={classNames("mx_BaseCard", className)} ref={ref} onKeyDown={onKeyDown}>
<div className="mx_BaseCard_header">
{backButton}
{closeButton}
{header}
</div>
{header !== null && (
<div className="mx_BaseCard_header">
{backButton}
{closeButton}
{header}
</div>
)}
{children}
{footer && <div className="mx_BaseCard_footer">{footer}</div>}
</div>

View file

@ -17,6 +17,8 @@ limitations under the License.
import React, { useCallback, useContext, useEffect, useMemo, useState } from "react";
import classNames from "classnames";
import { Room } from "matrix-js-sdk/src/matrix";
import { Tooltip } from "@vector-im/compound-web";
import { Icon as SearchIcon } from "@vector-im/compound-design-tokens/icons/search.svg";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { useIsEncrypted } from "../../../hooks/useIsEncrypted";
@ -53,6 +55,7 @@ import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import PosthogTrackers from "../../../PosthogTrackers";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { PollHistoryDialog } from "../dialogs/PollHistoryDialog";
import { Flex } from "../../utils/Flex";
interface IProps {
room: Room;
@ -306,7 +309,7 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, permalinkCreator, onClose, on
const alias = room.getCanonicalAlias() || room.getAltAliases()[0] || "";
const header = (
<React.Fragment>
<header className="mx_RoomSummaryCard_container">
<div className="mx_RoomSummaryCard_avatar" role="presentation">
<RoomAvatar room={room} size="54px" viewAvatarOnClick />
<TextWithTooltip
@ -329,7 +332,7 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, permalinkCreator, onClose, on
<div className="mx_RoomSummaryCard_alias" title={alias}>
{alias}
</div>
</React.Fragment>
</header>
);
const memberCount = useRoomMemberCount(room);
@ -337,22 +340,40 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, permalinkCreator, onClose, on
const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length;
return (
<BaseCard header={header} className="mx_RoomSummaryCard" onClose={onClose}>
<BaseCard header={null} className="mx_RoomSummaryCard" onClose={onClose}>
<Flex
as="header"
className="mx_RoomSummaryCard_header"
gap="var(--cpd-space-3x)"
align="center"
justify="space-between"
>
<Tooltip label={_t("action|search")} side="right">
<button
className="mx_RoomSummaryCard_searchBtn"
data-testid="summary-search"
onClick={() => {
onSearchClick?.();
}}
aria-label={_t("action|search")}
>
<SearchIcon width="100%" height="100%" />
</button>
</Tooltip>
<AccessibleButton
data-testid="base-card-close-button"
className="mx_BaseCard_close"
onClick={onClose}
title={_t("action|close")}
/>
</Flex>
{header}
<Group title={_t("common|about")} className="mx_RoomSummaryCard_aboutGroup">
<Button className="mx_RoomSummaryCard_icon_people" onClick={onRoomMembersClick}>
{_t("common|people")}
<span className="mx_BaseCard_Button_sublabel">{memberCount}</span>
</Button>
{SettingsStore.getValue("feature_new_room_decoration_ui") && (
<Button
className="mx_RoomSummaryCard_icon_search"
onClick={() => {
onSearchClick?.();
}}
>
{_t("right_panel|search_button")}
</Button>
)}
{!isVideoRoom && (
<Button className="mx_RoomSummaryCard_icon_files" onClick={onRoomFilesClick}>
{_t("right_panel|files_button")}

View file

@ -1763,7 +1763,7 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
return (
<BaseCard
className={classes.join(" ")}
header={header}
header={<span />}
onClose={onClose}
closeLabel={closeLabel}
cardState={cardState}
@ -1773,6 +1773,7 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
}
}}
>
{header}
{content}
</BaseCard>
);

View file

@ -33,6 +33,8 @@ import {
ClientEvent,
} from "matrix-js-sdk/src/matrix";
import { throttle } from "lodash";
import { Button, Tooltip } from "@vector-im/compound-web";
import { Icon as UserAddIcon } from "@vector-im/compound-design-tokens/icons/user-add-solid.svg";
import { _t } from "../../../languageHandler";
import dis from "../../../dispatcher/dispatcher";
@ -44,7 +46,7 @@ import RoomName from "../elements/RoomName";
import TruncatedList from "../elements/TruncatedList";
import Spinner from "../elements/Spinner";
import SearchBox from "../../structures/SearchBox";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import { ButtonEvent } from "../elements/AccessibleButton";
import EntityTile from "./EntityTile";
import MemberTile from "./MemberTile";
import BaseAvatar from "../avatars/BaseAvatar";
@ -52,7 +54,6 @@ import { shouldShowComponent } from "../../../customisations/helpers/UIComponent
import { UIComponent } from "../../../settings/UIFeature";
import PosthogTrackers from "../../../PosthogTrackers";
import { SDKContext } from "../../../contexts/SDKContext";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
const INITIAL_LOAD_NUM_MEMBERS = 30;
const INITIAL_LOAD_NUM_INVITED = 5;
@ -361,20 +362,24 @@ export default class MemberList extends React.Component<IProps, IState> {
if (this.state.canInvite) {
inviteButton = (
<AccessibleButton className="mx_MemberList_invite" onClick={this.onInviteButtonClick}>
<span>{inviteButtonText}</span>
</AccessibleButton>
<Button
size="sm"
kind="secondary"
className="mx_MemberList_invite"
onClick={this.onInviteButtonClick}
>
<UserAddIcon width="1em" height="1em" />
{inviteButtonText}
</Button>
);
} else {
inviteButton = (
<AccessibleTooltipButton
className="mx_MemberList_invite"
onClick={null}
disabled
tooltip={_t("member_list|invite_button_no_perms_tooltip")}
>
<span>{inviteButtonText}</span>
</AccessibleTooltipButton>
<Tooltip label={_t("member_list|invite_button_no_perms_tooltip")}>
<Button size="sm" kind="secondary" className="mx_MemberList_invite" onClick={() => {}}>
<UserAddIcon width="1em" height="1em" />
{inviteButtonText}
</Button>
</Tooltip>
);
}
}
@ -416,15 +421,11 @@ export default class MemberList extends React.Component<IProps, IState> {
return (
<BaseCard
className="mx_MemberList"
header={
<React.Fragment>
{scopeHeader}
{inviteButton}
</React.Fragment>
}
header={<React.Fragment>{scopeHeader}</React.Fragment>}
footer={footer}
onClose={this.props.onClose}
>
{inviteButton}
<div className="mx_MemberList_wrapper">
<TruncatedList
className="mx_MemberList_section mx_MemberList_joined"

View file

@ -127,7 +127,7 @@ export default function RoomHeader({ room }: { room: Room }): JSX.Element {
aria-level={1}
className="mx_RoomHeader_heading"
>
<span className="mx_RoomHeader_truncated">{roomName}</span>
<span className="mx_RoomHeader_truncated mx_lineClamp">{roomName}</span>
{!isDirectMessage && roomState.getJoinRule() === JoinRule.Public && (
<Tooltip label={_t("common|public_room")} side="right">
@ -163,7 +163,7 @@ export default function RoomHeader({ room }: { room: Room }): JSX.Element {
)}
</BodyText>
{roomTopic && (
<BodyText as="div" size="sm" className="mx_RoomHeader_topic mx_RoomHeader_truncated">
<BodyText as="div" size="sm" className="mx_RoomHeader_topic mx_RoomHeader_truncated mx_lineClamp">
<Linkify>{roomTopicBody}</Linkify>
</BodyText>
)}

View file

@ -696,7 +696,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
const isPanel = this.props.canPreview;
const classes = classNames("mx_RoomPreviewBar", "dark-panel", `mx_RoomPreviewBar_${messageCase}`, {
const classes = classNames("mx_RoomPreviewBar", `mx_RoomPreviewBar_${messageCase}`, {
mx_RoomPreviewBar_panel: isPanel,
mx_RoomPreviewBar_dialog: !isPanel,
});

View file

@ -1850,7 +1850,6 @@
"room_summary_card": {
"title": "Room info"
},
"search_button": "Search",
"settings_button": "Room settings",
"share_button": "Share room",
"thread_list": {