Update right panel base card styling to match Compound (#12768)

* Update base card styling to match Compound

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

* Update screenshot

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2024-07-16 10:03:35 +01:00 committed by GitHub
parent 5f10ccb5e4
commit f7a078d250
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 118 additions and 130 deletions

View file

@ -81,7 +81,7 @@
"@sentry/browser": "^8.0.0",
"@testing-library/react-hooks": "^8.0.1",
"@vector-im/compound-design-tokens": "^1.2.0",
"@vector-im/compound-web": "^5.2.3",
"@vector-im/compound-web": "^5.4.0",
"@zxcvbn-ts/core": "^3.0.4",
"@zxcvbn-ts/language-common": "^3.0.4",
"@zxcvbn-ts/language-en": "^3.0.2",

View file

@ -227,7 +227,7 @@ test.describe("Cryptography", function () {
await verify(page, bob);
// Assert that verified icon is rendered
await page.getByRole("button", { name: "Room members" }).click();
await page.getByTestId("base-card-back-button").click();
await page.locator(".mx_RightPanelTabs").getByText("Info").click();
await expect(page.locator('.mx_RoomSummaryCard_badges [data-kind="success"]')).toContainText("Encrypted");

View file

@ -132,7 +132,7 @@ test.describe("Cryptography", function () {
// wait for the logout to propagate. Workaround for https://github.com/vector-im/element-web/issues/26263 by repeatedly closing and reopening Bob's user info.
async function awaitOneDevice(iterations = 1) {
const rightPanel = page.locator(".mx_RightPanel");
await rightPanel.getByRole("button", { name: "Room members" }).click();
await rightPanel.getByTestId("base-card-back-button").click();
await rightPanel.getByText("Bob").click();
const sessionCountText = await rightPanel
.locator(".mx_UserInfo_devices")

View file

@ -538,7 +538,7 @@ class Helpers {
const threadPanel = this.page.locator(".mx_ThreadPanel");
await expect(threadPanel).toBeVisible();
await threadPanel.evaluate(($panel) => {
const $button = $panel.querySelector<HTMLElement>('.mx_BaseCard_back[aria-label="Threads"]');
const $button = $panel.querySelector<HTMLElement>('[data-testid="base-card-back-button"]');
// If the Threads back button is present then click it - the
// threads button can open either threads list or thread panel
if ($button) {

View file

@ -106,7 +106,7 @@ test.describe("RightPanel", () => {
await expect(page.locator(".mx_FilePanel")).toBeVisible();
await expect(page.locator(".mx_FilePanel_empty")).toBeVisible();
await page.getByRole("button", { name: "Room information" }).click();
await page.getByTestId("base-card-back-button").click();
await checkRoomSummaryCard(page, ROOM_NAME);
});
@ -120,7 +120,7 @@ test.describe("RightPanel", () => {
await expect(page.locator(".mx_UserInfo")).toBeVisible();
await expect(page.locator(".mx_UserInfo_profile").getByText(NAME)).toBeVisible();
await page.getByRole("button", { name: "Room members" }).click();
await page.getByTestId("base-card-back-button").click();
await expect(page.locator(".mx_MemberList")).toBeVisible();
await page.locator(".mx_RightPanelTabs").getByText("Info").click();
@ -145,7 +145,7 @@ test.describe("RightPanel", () => {
await expect(page.locator(".mx_UserInfo_profile").getByText(NAME)).toBeVisible();
await expect(page.locator(".mx_SpaceScopeHeader").getByText(SPACE_NAME)).toBeVisible();
await page.getByRole("button", { name: "Back" }).click();
await page.getByTestId("base-card-back-button").click();
await expect(page.locator(".mx_MemberList")).toBeVisible();
});
});

View file

@ -433,7 +433,7 @@ test.describe("Threads", () => {
await textbox.press("Enter");
await expect(locator.locator(".mx_EventTile_last").getByText("Hello Mr. User")).toBeAttached();
// Close thread
await locator.getByRole("button", { name: "Close" }).click();
await locator.getByTestId("base-card-close-button").click();
// Open existing thread
locator = page
@ -486,7 +486,7 @@ test.describe("Threads", () => {
await textbox.press("Enter");
await expect(threadPanel.locator(".mx_EventTile_last").getByText(threadMessage)).toBeVisible();
// Close thread
await threadPanel.getByRole("button", { name: "Close" }).click();
await threadPanel.getByTestId("base-card-close-button").click();
};
await sendMessage("Hello Mr. Bot");
@ -502,7 +502,7 @@ test.describe("Threads", () => {
).toBeVisible();
// Open threads list
await page.locator(".mx_BaseCard_back").click();
await page.getByTestId("base-card-back-button").click();
const rightPanel = page.locator(".mx_RightPanel");
// Check that the threads are listed
await expect(rightPanel.locator(".mx_EventTile").getByText("Hello Mr. User in a thread")).toBeVisible();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -27,7 +27,7 @@ limitations under the License.
.mx_BaseCard_header {
height: 64px;
padding: var(--cpd-space-3x);
padding: var(--cpd-space-4x);
box-sizing: border-box;
/* changing the color from $separator to transparent as it is
the best visual output during the transition period. This will be
@ -36,8 +36,13 @@ limitations under the License.
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--cpd-space-2x);
gap: var(--cpd-space-3x);
flex-shrink: 0;
border-block-end: var(--cpd-border-width-1) solid $separator;
.mx_BaseCard_header_spacer {
flex: 1;
}
> h2 {
margin: 0 44px;
@ -155,52 +160,6 @@ limitations under the License.
}
}
.mx_BaseCard_back,
.mx_BaseCard_close {
flex-shrink: 0;
position: relative;
/* @TODO(kerrya) background colours here are not semantic
these buttons to be replaced with IconButton after secondary variant is added
https://github.com/vector-im/compound/issues/279 */
background-color: var(--cpd-color-bg-subtle-secondary);
width: var(--BaseCard_header-button-size);
height: var(--BaseCard_header-button-size);
border-radius: 50%;
&:hover {
background-color: var(--cpd-color-bg-subtle-primary);
}
&::before {
content: "";
position: absolute;
height: inherit;
width: inherit;
top: 0;
left: 0;
mask-repeat: no-repeat;
mask-position: center;
mask-size: 20px;
background-color: var(--cpd-color-icon-secondary);
}
}
.mx_BaseCard_back {
order: 0; /* always first! */
&::before {
transform: rotate(90deg);
mask-size: 22px;
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
}
}
.mx_BaseCard_close {
order: 999; /* always last */
&::before {
mask-image: url("@vector-im/compound-design-tokens/icons/close.svg");
}
}
.mx_ContextualMenu_wrapper.mx_BaseCard_header_title {
.mx_ContextualMenu {
position: initial;
@ -235,7 +194,3 @@ limitations under the License.
}
}
}
.mx_BaseCard_headerProp {
flex: 1 1 100%;
}

View file

@ -14,7 +14,7 @@ $overlay-background: var(--cpd-color-alpha-gray-1300);
$panels: var(--cpd-color-bg-subtle-secondary);
$panel-actions: var(--cpd-color-alpha-gray-300);
$separator: var(--cpd-color-alpha-gray-400);
$separator: var(--cpd-color-gray-400);
/* ******************** */

View file

@ -105,7 +105,7 @@ $overlay-background: rgba($background, 0.85);
$panels: rgba($system, 0.9);
$panel-actions: $roomtile-selected-bg-color;
$separator: var(--cpd-color-alpha-gray-400);
$separator: var(--cpd-color-gray-400);
/**
* Creating a `semantic` color scale. This will not be needed with the new

View file

@ -163,7 +163,7 @@ $overlay-background: rgba($background, 0.85);
$panels: rgba($system, 0.9);
$panel-actions: $roomtile-selected-bg-color;
$separator: var(--cpd-color-alpha-gray-400);
$separator: var(--cpd-color-gray-400);
/* Legacy theme backports */

View file

@ -32,7 +32,7 @@ $overlay-background: var(--cpd-color-alpha-gray-1300);
$panels: var(--cpd-color-bg-subtle-secondary);
$panel-actions: var(--cpd-color-alpha-gray-300);
$separator: var(--cpd-color-alpha-gray-400);
$separator: var(--cpd-color-gray-400);
$accent: var(--cpd-color-text-action-accent);
$alert: var(--cpd-color-text-critical-primary);

View file

@ -229,7 +229,7 @@ const ThreadPanel: React.FC<IProps> = ({ roomId, onClose, permalinkCreator }) =>
const roomContext = useContext(RoomContext);
const timelinePanel = useRef<TimelinePanel | null>(null);
const card = useRef<HTMLDivElement | null>(null);
const closeButonRef = useRef<HTMLDivElement | null>(null);
const closeButonRef = useRef<HTMLButtonElement | null>(null);
const [filterOption, setFilterOption] = useState<ThreadFilterType>(ThreadFilterType.All);
const [room, setRoom] = useState<Room | null>(null);

View file

@ -14,12 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { forwardRef, ReactNode, KeyboardEvent, Ref } from "react";
import React, { forwardRef, ReactNode, KeyboardEvent, Ref, MouseEvent } from "react";
import classNames from "classnames";
import { IconButton, Text } from "@vector-im/compound-web";
import { Icon as CloseIcon } from "@vector-im/compound-design-tokens/icons/close.svg";
import { Icon as ChevronLeftIcon } from "@vector-im/compound-design-tokens/icons/chevron-left.svg";
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
import { _t } from "../../../languageHandler";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import { backLabelForPhase } from "../../../stores/right-panel/RightPanelStorePhases";
import { CardContext } from "./context";
@ -34,13 +36,13 @@ interface IProps {
ariaLabelledBy?: string;
withoutScrollContainer?: boolean;
closeLabel?: string;
onClose?(ev: ButtonEvent): void;
onBack?(ev: ButtonEvent): void;
onClose?(ev: MouseEvent<HTMLButtonElement>): void;
onBack?(ev: MouseEvent<HTMLButtonElement>): void;
onKeyDown?(ev: KeyboardEvent): void;
cardState?: any;
ref?: Ref<HTMLDivElement>;
// Ref for the 'close' button the the card
closeButtonRef?: Ref<HTMLDivElement>;
closeButtonRef?: Ref<HTMLButtonElement>;
children: ReactNode;
}
@ -81,26 +83,39 @@ const BaseCard: React.FC<IProps> = forwardRef<HTMLDivElement, IProps>(
) => {
let backButton;
const cardHistory = RightPanelStore.instance.roomPhaseHistory;
if (cardHistory.length > 1) {
if (cardHistory.length > 1 && !hideHeaderButtons) {
const prevCard = cardHistory[cardHistory.length - 2];
const onBackClick = (ev: ButtonEvent): void => {
const onBackClick = (ev: MouseEvent<HTMLButtonElement>): void => {
onBack?.(ev);
RightPanelStore.instance.popCard();
};
const label = backLabelForPhase(prevCard.phase) ?? _t("action|back");
backButton = <AccessibleButton className="mx_BaseCard_back" onClick={onBackClick} title={label} />;
backButton = (
<IconButton
size="28px"
data-testid="base-card-back-button"
onClick={onBackClick}
tooltip={label}
subtleBackground
>
<ChevronLeftIcon />
</IconButton>
);
}
let closeButton;
if (onClose) {
if (onClose && !hideHeaderButtons) {
closeButton = (
<AccessibleButton
<IconButton
size="28px"
data-testid="base-card-close-button"
className="mx_BaseCard_close"
onClick={onClose}
title={closeLabel || _t("action|close")}
ref={closeButtonRef}
/>
tooltip={closeLabel ?? _t("action|close")}
subtleBackground
>
<CloseIcon />
</IconButton>
);
}
@ -108,16 +123,6 @@ const BaseCard: React.FC<IProps> = forwardRef<HTMLDivElement, IProps>(
children = <AutoHideScrollbar>{children}</AutoHideScrollbar>;
}
let headerButtons: React.ReactElement | undefined;
if (!hideHeaderButtons) {
headerButtons = (
<>
{backButton}
{closeButton}
</>
);
}
const shouldRenderHeader = header || !hideHeaderButtons;
return (
@ -132,8 +137,15 @@ const BaseCard: React.FC<IProps> = forwardRef<HTMLDivElement, IProps>(
>
{shouldRenderHeader && (
<div className="mx_BaseCard_header">
{headerButtons}
<div className="mx_BaseCard_headerProp">{header}</div>
{backButton}
{typeof header === "string" ? (
<Text size="md" weight="medium" className="mx_BaseCard_header_title">
{header}
</Text>
) : (
header ?? <div className="mx_BaseCard_header_spacer" />
)}
{closeButton}
</div>
)}
{children}

View file

@ -1778,7 +1778,7 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
return (
<BaseCard
className={classes.join(" ")}
header={createSpaceScopeHeader(room)}
header={createSpaceScopeHeader(room) ?? _t("common|profile")}
onClose={onClose}
closeLabel={closeLabel}
cardState={cardState}

View file

@ -13,33 +13,36 @@ exports[`AppTile destroys non-persisted right panel widget on room change 1`] =
class="mx_BaseCard_header"
>
<div
aria-label="Close"
class="mx_AccessibleButton mx_BaseCard_close"
class="mx_BaseCard_header_title"
>
<h4
class="mx_Heading_h4 mx_BaseCard_header_title_heading"
>
Example 1
</h4>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="Options"
class="mx_AccessibleButton mx_BaseCard_header_title_button--option"
role="button"
tabindex="0"
/>
</div>
<button
class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
data-testid="base-card-close-button"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
/>
<div
class="mx_BaseCard_headerProp"
>
<div
class="mx_BaseCard_header_title"
class="_indicator-icon_133tf_26"
style="--cpd-icon-button-size: 100%;"
>
<h4
class="mx_Heading_h4 mx_BaseCard_header_title_heading"
>
Example 1
</h4>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="Options"
class="mx_AccessibleButton mx_BaseCard_header_title_button--option"
role="button"
tabindex="0"
/>
<div />
</div>
</div>
</button>
</div>
<div
class="mx_AppTileFullWidth"

View file

@ -77,16 +77,25 @@ exports[`<UserInfo /> with crypto enabled renders <BasicUserInfo /> 1`] = `
<div
class="mx_BaseCard_header"
>
<div
aria-label="Close"
class="mx_AccessibleButton mx_BaseCard_close"
<p
class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69 mx_BaseCard_header_title"
>
Profile
</p>
<button
class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
data-testid="base-card-close-button"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
/>
<div
class="mx_BaseCard_headerProp"
/>
>
<div
class="_indicator-icon_133tf_26"
style="--cpd-icon-button-size: 100%;"
>
<div />
</div>
</button>
</div>
<div
class="mx_AutoHideScrollbar"
@ -232,16 +241,25 @@ exports[`<UserInfo /> with crypto enabled should render a deactivate button for
<div
class="mx_BaseCard_header"
>
<div
aria-label="Close"
class="mx_AccessibleButton mx_BaseCard_close"
<p
class="_typography_yh5dq_162 _font-body-md-medium_yh5dq_69 mx_BaseCard_header_title"
>
Profile
</p>
<button
class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
data-testid="base-card-close-button"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
/>
<div
class="mx_BaseCard_headerProp"
/>
>
<div
class="_indicator-icon_133tf_26"
style="--cpd-icon-button-size: 100%;"
>
<div />
</div>
</button>
</div>
<div
class="mx_AutoHideScrollbar"

View file

@ -9,7 +9,7 @@ exports[`<ThirdPartyMemberInfo /> should render invite 1`] = `
class="mx_BaseCard_header"
>
<div
class="mx_BaseCard_headerProp"
class="mx_BaseCard_header_spacer"
/>
</div>
<div
@ -51,7 +51,7 @@ exports[`<ThirdPartyMemberInfo /> should render invite when room in not availabl
class="mx_BaseCard_header"
>
<div
class="mx_BaseCard_headerProp"
class="mx_BaseCard_header_spacer"
/>
</div>
<div

View file

@ -2977,7 +2977,7 @@
dependencies:
svg2vectordrawable "^2.9.1"
"@vector-im/compound-web@^5.2.3":
"@vector-im/compound-web@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-5.4.0.tgz#b95262197199c11931a8c6f5269514eb9461f187"
integrity sha512-+EPbr8HzlGEWSePEcPs2iQEBnjXvHGWK177SKF8IO2C7Z2Ygddxa2VTQ7oqtrUfgT+NB5IBTLyXV4Nx7FLgmMA==