Compare commits
2 Commits
develop
...
hs/safety-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be3092f484 | ||
|
|
c3e20b3385 |
49
CHANGELOG.md
@@ -1,52 +1,3 @@
|
|||||||
Changes in [1.12.7](https://github.com/element-hq/element-web/releases/tag/v1.12.7) (2025-12-16)
|
|
||||||
================================================================================================
|
|
||||||
## ✨ Features
|
|
||||||
|
|
||||||
* Replace legacy icons with compound ([#31424](https://github.com/element-hq/element-web/pull/31424)). Contributed by @t3chguy.
|
|
||||||
* Update polls UX to match EX Mobile and improve accessibility ([#31245](https://github.com/element-hq/element-web/pull/31245)). Contributed by @langleyd.
|
|
||||||
* Add option to enable read receipt and marker when user interact with UI ([#31353](https://github.com/element-hq/element-web/pull/31353)). Contributed by @florianduros.
|
|
||||||
* Introduce a hook to auto dispose view models ([#31178](https://github.com/element-hq/element-web/pull/31178)). Contributed by @MidhunSureshR.
|
|
||||||
* Update settings toggles to use consistent design across app. ([#30169](https://github.com/element-hq/element-web/pull/30169)). Contributed by @Half-Shot.
|
|
||||||
* Add ability to the room view to hide widgets ([#31400](https://github.com/element-hq/element-web/pull/31400)). Contributed by @langleyd.
|
|
||||||
* call: Pass the echo cancellation and noise suppression settings to EC ([#31317](https://github.com/element-hq/element-web/pull/31317)). Contributed by @BillCarsonFr.
|
|
||||||
* Tweak rendering of icons for a11y ([#31358](https://github.com/element-hq/element-web/pull/31358)). Contributed by @t3chguy.
|
|
||||||
* Implement new `renderNotificationDecoration` from module API ([#31389](https://github.com/element-hq/element-web/pull/31389)). Contributed by @MidhunSureshR.
|
|
||||||
* Replace more icons with compound ([#31381](https://github.com/element-hq/element-web/pull/31381)). Contributed by @t3chguy.
|
|
||||||
* Replace more icons with compound ([#31378](https://github.com/element-hq/element-web/pull/31378)). Contributed by @t3chguy.
|
|
||||||
* `<Banner/>`: Hide `Dismiss` button if `onClose` handler is not provided. ([#31362](https://github.com/element-hq/element-web/pull/31362)). Contributed by @kaylendog.
|
|
||||||
* Replace batch of legacy icons with compound design tokens ([#31360](https://github.com/element-hq/element-web/pull/31360)). Contributed by @t3chguy.
|
|
||||||
* MSC4380: Invite blocking ([#31268](https://github.com/element-hq/element-web/pull/31268)). Contributed by @richvdh.
|
|
||||||
* Tweak rendering of icons for accessibility ([#31346](https://github.com/element-hq/element-web/pull/31346)). Contributed by @t3chguy.
|
|
||||||
* Implement a shared `Banner` component. ([#31266](https://github.com/element-hq/element-web/pull/31266)). Contributed by @kaylendog.
|
|
||||||
* Allow the Login screen to use the dark theme ([#31293](https://github.com/element-hq/element-web/pull/31293)). Contributed by @richvdh.
|
|
||||||
|
|
||||||
## 🐛 Bug Fixes
|
|
||||||
|
|
||||||
* [Backport staging] Amend e2e normal icon from lock-solid to info ([#31559](https://github.com/element-hq/element-web/pull/31559)). Contributed by @t3chguy.
|
|
||||||
* [Backport staging] Fix CSS specificity causing icon issues in e2e verification ([#31548](https://github.com/element-hq/element-web/pull/31548)). Contributed by @RiotRobot.
|
|
||||||
* [Backport staging] Fix e2e icons in CompleteSecurity \& SetupEncryptionBody ([#31522](https://github.com/element-hq/element-web/pull/31522)). Contributed by @RiotRobot.
|
|
||||||
* [Backport staging] Remove an extra paragraph in advanced room settings ([#31511](https://github.com/element-hq/element-web/pull/31511)). Contributed by @RiotRobot.
|
|
||||||
* [Backport staging] Don't show the key storage out of sync toast when backup disabled ([#31507](https://github.com/element-hq/element-web/pull/31507)). Contributed by @RiotRobot.
|
|
||||||
* Fix composer button visibility in contrast colour mode ([#31255](https://github.com/element-hq/element-web/pull/31255)). Contributed by @t3chguy.
|
|
||||||
* Ensure correct room version is used and permissions are appropriately sert when creating rooms ([#31464](https://github.com/element-hq/element-web/pull/31464)). Contributed by @Half-Shot.
|
|
||||||
* Fix e2e icon rendering ([#31454](https://github.com/element-hq/element-web/pull/31454)). Contributed by @t3chguy.
|
|
||||||
* EventIndexer: ensure we add initial checkpoints when the db is first opened ([#31448](https://github.com/element-hq/element-web/pull/31448)). Contributed by @richvdh.
|
|
||||||
* Fix `/join <alias>` command failing due to race condition ([#31433](https://github.com/element-hq/element-web/pull/31433)). Contributed by @MidhunSureshR.
|
|
||||||
* MessageEventIndexDialog: distinguish indexed rooms ([#31436](https://github.com/element-hq/element-web/pull/31436)). Contributed by @richvdh.
|
|
||||||
* Move `EditInPlace` out of `Form` (Fixes: reloading EW on EC url update) ([#31434](https://github.com/element-hq/element-web/pull/31434)). Contributed by @toger5.
|
|
||||||
* Fixes issue where cursor would jump to the beginning of the input field after converting Japanese text and pressing Tab ([#31432](https://github.com/element-hq/element-web/pull/31432)). Contributed by @shinaoka.
|
|
||||||
* Fix widgets getting stuck in loading states ([#31314](https://github.com/element-hq/element-web/pull/31314)). Contributed by @robintown.
|
|
||||||
* Room list: fix room options remaining on room item after mouse leaving ([#31414](https://github.com/element-hq/element-web/pull/31414)). Contributed by @florianduros.
|
|
||||||
* Make `RoomList.showMessagePreview` configurable by `config.json` ([#31419](https://github.com/element-hq/element-web/pull/31419)). Contributed by @florianduros.
|
|
||||||
* Fix bug which caused app not to load correctly when `force_verification` is enabled ([#31265](https://github.com/element-hq/element-web/pull/31265)). Contributed by @richvdh.
|
|
||||||
* Room list: display the menu option on the room list item when clicked/opened ([#31380](https://github.com/element-hq/element-web/pull/31380)). Contributed by @florianduros.
|
|
||||||
* Fix handling of SVGs ([#31359](https://github.com/element-hq/element-web/pull/31359)). Contributed by @t3chguy.
|
|
||||||
* Fix word wrapping in expanded left panel buttons ([#31377](https://github.com/element-hq/element-web/pull/31377)). Contributed by @t3chguy.
|
|
||||||
* Fix aspect ratio on error view background ([#31361](https://github.com/element-hq/element-web/pull/31361)). Contributed by @t3chguy.
|
|
||||||
* Fix failure to request persistent storage perms ([#31299](https://github.com/element-hq/element-web/pull/31299)). Contributed by @richvdh.
|
|
||||||
* Fix calls sometimes not knowing that they're presented ([#31313](https://github.com/element-hq/element-web/pull/31313)). Contributed by @robintown.
|
|
||||||
|
|
||||||
|
|
||||||
Changes in [1.12.6](https://github.com/element-hq/element-web/releases/tag/v1.12.6) (2025-12-03)
|
Changes in [1.12.6](https://github.com/element-hq/element-web/releases/tag/v1.12.6) (2025-12-03)
|
||||||
================================================================================================
|
================================================================================================
|
||||||
This release fixes a bug where 1:1 calling was incorrectly not available if no Element Call focus was set.
|
This release fixes a bug where 1:1 calling was incorrectly not available if no Element Call focus was set.
|
||||||
|
|||||||
10
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "element-web",
|
"name": "element-web",
|
||||||
"version": "1.12.7",
|
"version": "1.12.6",
|
||||||
"description": "Element: the future of secure communication",
|
"description": "Element: the future of secure communication",
|
||||||
"author": "New Vector Ltd.",
|
"author": "New Vector Ltd.",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
"@matrix-org/spec": "^1.7.0",
|
"@matrix-org/spec": "^1.7.0",
|
||||||
"@sentry/browser": "^10.0.0",
|
"@sentry/browser": "^10.0.0",
|
||||||
"@types/png-chunks-extract": "^1.0.2",
|
"@types/png-chunks-extract": "^1.0.2",
|
||||||
"@vector-im/compound-design-tokens": "6.4.2",
|
"@vector-im/compound-design-tokens": "6.4.1",
|
||||||
"@vector-im/compound-web": "^8.3.1",
|
"@vector-im/compound-web": "^8.3.1",
|
||||||
"@vector-im/matrix-wysiwyg": "2.40.0",
|
"@vector-im/matrix-wysiwyg": "2.40.0",
|
||||||
"@zxcvbn-ts/core": "^3.0.4",
|
"@zxcvbn-ts/core": "^3.0.4",
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"maplibre-gl": "^5.0.0",
|
"maplibre-gl": "^5.0.0",
|
||||||
"matrix-encrypt-attachment": "^1.0.3",
|
"matrix-encrypt-attachment": "^1.0.3",
|
||||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
|
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#hs/safety-error-code",
|
||||||
"matrix-widget-api": "^1.14.0",
|
"matrix-widget-api": "^1.14.0",
|
||||||
"memoize-one": "^6.0.0",
|
"memoize-one": "^6.0.0",
|
||||||
"mime": "^4.0.4",
|
"mime": "^4.0.4",
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
"opus-recorder": "^8.0.3",
|
"opus-recorder": "^8.0.3",
|
||||||
"pako": "^2.0.3",
|
"pako": "^2.0.3",
|
||||||
"png-chunks-extract": "^1.0.0",
|
"png-chunks-extract": "^1.0.0",
|
||||||
"posthog-js": "1.302.2",
|
"posthog-js": "1.297.2",
|
||||||
"qrcode": "1.5.4",
|
"qrcode": "1.5.4",
|
||||||
"re-resizable": "6.11.2",
|
"re-resizable": "6.11.2",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
@@ -281,7 +281,7 @@
|
|||||||
"postcss-preset-env": "^10.0.0",
|
"postcss-preset-env": "^10.0.0",
|
||||||
"postcss-scss": "^4.0.4",
|
"postcss-scss": "^4.0.4",
|
||||||
"postcss-simple-vars": "^7.0.1",
|
"postcss-simple-vars": "^7.0.1",
|
||||||
"prettier": "3.7.4",
|
"prettier": "3.6.2",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
"rimraf": "^6.0.0",
|
"rimraf": "^6.0.0",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -19,7 +19,6 @@ export * from "./pill-input/Pill";
|
|||||||
export * from "./pill-input/PillInput";
|
export * from "./pill-input/PillInput";
|
||||||
export * from "./rich-list/RichItem";
|
export * from "./rich-list/RichItem";
|
||||||
export * from "./rich-list/RichList";
|
export * from "./rich-list/RichList";
|
||||||
export * from "./room-list/RoomListSearchView";
|
|
||||||
export * from "./utils/Box";
|
export * from "./utils/Box";
|
||||||
export * from "./utils/Flex";
|
export * from "./utils/Flex";
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2025 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
||||||
* Please see LICENSE files in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.view {
|
|
||||||
/* From figma, this should be aligned with the room header */
|
|
||||||
min-height: 64px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-bottom: var(--cpd-border-width-1) solid var(--cpd-color-bg-subtle-primary);
|
|
||||||
padding: 0 var(--cpd-space-3x);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
|
||||||
/* The search button should take all the remaining space */
|
|
||||||
flex: 1;
|
|
||||||
/* !important is needed to override compound button in EW */
|
|
||||||
font: var(--cpd-font-body-md-regular) !important;
|
|
||||||
color: var(--cpd-color-text-secondary) !important;
|
|
||||||
min-width: 0;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
fill: var(--cpd-color-icon-secondary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search_container {
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
/* Shrink and truncate the search text */
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
kbd {
|
|
||||||
font-family: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search_text {
|
|
||||||
min-width: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
text-align: start;
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2025 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
||||||
* Please see LICENSE files in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, { type JSX } from "react";
|
|
||||||
import { fn } from "storybook/test";
|
|
||||||
|
|
||||||
import type { Meta, StoryFn } from "@storybook/react-vite";
|
|
||||||
import {
|
|
||||||
RoomListSearchView,
|
|
||||||
type RoomListSearchViewActions,
|
|
||||||
type RoomListSearchViewSnapshot,
|
|
||||||
} from "./RoomListSearchView";
|
|
||||||
import { useMockedViewModel } from "../../useMockedViewModel";
|
|
||||||
|
|
||||||
type RoomListSearchProps = RoomListSearchViewSnapshot & RoomListSearchViewActions;
|
|
||||||
|
|
||||||
const RoomListSearchViewWrapper = ({
|
|
||||||
onSearchClick,
|
|
||||||
onDialPadClick,
|
|
||||||
onExploreClick,
|
|
||||||
...rest
|
|
||||||
}: RoomListSearchProps): JSX.Element => {
|
|
||||||
const vm = useMockedViewModel(rest, {
|
|
||||||
onSearchClick,
|
|
||||||
onDialPadClick,
|
|
||||||
onExploreClick,
|
|
||||||
});
|
|
||||||
return <RoomListSearchView vm={vm} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: "Room List/RoomListSearchView",
|
|
||||||
component: RoomListSearchViewWrapper,
|
|
||||||
tags: ["autodocs"],
|
|
||||||
args: {
|
|
||||||
displayExploreButton: true,
|
|
||||||
displayDialButton: false,
|
|
||||||
searchShortcut: "⌘ K",
|
|
||||||
onSearchClick: fn(),
|
|
||||||
onDialPadClick: fn(),
|
|
||||||
onExploreClick: fn(),
|
|
||||||
},
|
|
||||||
parameters: {
|
|
||||||
design: {
|
|
||||||
type: "figma",
|
|
||||||
url: "https://www.figma.com/design/vlmt46QDdE4dgXDiyBJXqp/ER-33-Left-Panel-2025?node-id=98-1979&t=vafb4zoYMNLRuAbh-4",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Meta<typeof RoomListSearchViewWrapper>;
|
|
||||||
|
|
||||||
const Template: StoryFn<typeof RoomListSearchViewWrapper> = (args) => <RoomListSearchViewWrapper {...args} />;
|
|
||||||
|
|
||||||
export const Default = Template.bind({});
|
|
||||||
|
|
||||||
export const WithDialPad = Template.bind({});
|
|
||||||
WithDialPad.args = {
|
|
||||||
displayDialButton: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const WithoutExplore = Template.bind({});
|
|
||||||
WithoutExplore.args = {
|
|
||||||
displayExploreButton: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AllButtons = Template.bind({});
|
|
||||||
AllButtons.args = {
|
|
||||||
displayExploreButton: true,
|
|
||||||
displayDialButton: true,
|
|
||||||
searchShortcut: "⌘ K",
|
|
||||||
};
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2025 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
||||||
* Please see LICENSE files in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { render, screen } from "jest-matrix-react";
|
|
||||||
import { composeStories } from "@storybook/react-vite";
|
|
||||||
import React from "react";
|
|
||||||
import userEvent from "@testing-library/user-event";
|
|
||||||
|
|
||||||
import * as stories from "./RoomListSearchView.stories";
|
|
||||||
import {
|
|
||||||
RoomListSearchView,
|
|
||||||
type RoomListSearchViewActions,
|
|
||||||
type RoomListSearchViewSnapshot,
|
|
||||||
} from "./RoomListSearchView";
|
|
||||||
import { MockViewModel } from "../../viewmodel/MockViewModel";
|
|
||||||
|
|
||||||
const { Default, WithDialPad, WithoutExplore, AllButtons } = composeStories(stories);
|
|
||||||
|
|
||||||
describe("RoomListSearchView", () => {
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Storybook snapshots", () => {
|
|
||||||
it("renders the default state", () => {
|
|
||||||
const { container } = render(<Default />);
|
|
||||||
expect(container).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("renders with dial pad button", () => {
|
|
||||||
const { container } = render(<WithDialPad />);
|
|
||||||
expect(container).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("renders without explore button", () => {
|
|
||||||
const { container } = render(<WithoutExplore />);
|
|
||||||
expect(container).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("renders with all buttons visible", () => {
|
|
||||||
const { container } = render(<AllButtons />);
|
|
||||||
expect(container).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("User interactions", () => {
|
|
||||||
const onSearchClick = jest.fn();
|
|
||||||
const onDialPadClick = jest.fn();
|
|
||||||
const onExploreClick = jest.fn();
|
|
||||||
|
|
||||||
class TestViewModel extends MockViewModel<RoomListSearchViewSnapshot> implements RoomListSearchViewActions {
|
|
||||||
public onSearchClick = onSearchClick;
|
|
||||||
public onDialPadClick = onDialPadClick;
|
|
||||||
public onExploreClick = onExploreClick;
|
|
||||||
}
|
|
||||||
|
|
||||||
it("should call onSearchClick when search button is clicked", async () => {
|
|
||||||
const user = userEvent.setup();
|
|
||||||
const vm = new TestViewModel({
|
|
||||||
displayExploreButton: false,
|
|
||||||
displayDialButton: false,
|
|
||||||
searchShortcut: "⌘ K",
|
|
||||||
});
|
|
||||||
|
|
||||||
render(<RoomListSearchView vm={vm} />);
|
|
||||||
|
|
||||||
await user.click(screen.getByRole("button", { name: "Search ⌘ K" }));
|
|
||||||
expect(onSearchClick).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call onDialPadClick when dial pad button is clicked", async () => {
|
|
||||||
const user = userEvent.setup();
|
|
||||||
const vm = new TestViewModel({
|
|
||||||
displayExploreButton: false,
|
|
||||||
displayDialButton: true,
|
|
||||||
searchShortcut: "⌘ K",
|
|
||||||
});
|
|
||||||
|
|
||||||
render(<RoomListSearchView vm={vm} />);
|
|
||||||
|
|
||||||
await user.click(screen.getByRole("button", { name: "Open dial pad" }));
|
|
||||||
expect(onDialPadClick).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call onExploreClick when explore button is clicked", async () => {
|
|
||||||
const user = userEvent.setup();
|
|
||||||
const vm = new TestViewModel({
|
|
||||||
displayExploreButton: true,
|
|
||||||
displayDialButton: false,
|
|
||||||
searchShortcut: "⌘ K",
|
|
||||||
});
|
|
||||||
|
|
||||||
render(<RoomListSearchView vm={vm} />);
|
|
||||||
|
|
||||||
await user.click(screen.getByRole("button", { name: "Explore rooms" }));
|
|
||||||
expect(onExploreClick).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2025 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
||||||
* Please see LICENSE files in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, { type JSX, type MouseEventHandler } from "react";
|
|
||||||
import { Button } from "@vector-im/compound-web";
|
|
||||||
import ExploreIcon from "@vector-im/compound-design-tokens/assets/web/icons/explore";
|
|
||||||
import SearchIcon from "@vector-im/compound-design-tokens/assets/web/icons/search";
|
|
||||||
import DialPadIcon from "@vector-im/compound-design-tokens/assets/web/icons/dial-pad";
|
|
||||||
|
|
||||||
import styles from "./RoomListSearchView.module.css";
|
|
||||||
import { type ViewModel } from "../../viewmodel/ViewModel";
|
|
||||||
import { useViewModel } from "../../useViewModel";
|
|
||||||
import { Flex } from "../../utils/Flex";
|
|
||||||
import { useI18n } from "../../utils/i18nContext";
|
|
||||||
|
|
||||||
export interface RoomListSearchViewSnapshot {
|
|
||||||
/**
|
|
||||||
* Whether to display the explore button.
|
|
||||||
*/
|
|
||||||
displayExploreButton: boolean;
|
|
||||||
/**
|
|
||||||
* Whether to display the dial pad button.
|
|
||||||
*/
|
|
||||||
displayDialButton: boolean;
|
|
||||||
/**
|
|
||||||
* The keyboard shortcut text to display for the search action.
|
|
||||||
* For example: "⌘ K" on macOS or "Ctrl K" on other platforms.
|
|
||||||
*/
|
|
||||||
searchShortcut: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RoomListSearchViewActions {
|
|
||||||
/**
|
|
||||||
* Handles the click event on the search button.
|
|
||||||
*/
|
|
||||||
onSearchClick: MouseEventHandler<HTMLButtonElement>;
|
|
||||||
/**
|
|
||||||
* Handles the click event on the dial pad button.
|
|
||||||
*/
|
|
||||||
onDialPadClick: MouseEventHandler<HTMLButtonElement>;
|
|
||||||
/**
|
|
||||||
* Handles the click event on the explore button.
|
|
||||||
*/
|
|
||||||
onExploreClick: MouseEventHandler<HTMLButtonElement>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The view model for the room list search component.
|
|
||||||
*/
|
|
||||||
export type RoomListSearchViewModel = ViewModel<RoomListSearchViewSnapshot> & RoomListSearchViewActions;
|
|
||||||
|
|
||||||
interface RoomListSearchViewProps {
|
|
||||||
/**
|
|
||||||
* The view model for the room list search component.
|
|
||||||
*/
|
|
||||||
vm: RoomListSearchViewModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A search component to be displayed at the top of the room list.
|
|
||||||
* The component provides search functionality, optional dial pad access, and optional room exploration.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* <RoomListSearchView vm={roomListSearchViewModel} />
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export function RoomListSearchView({ vm }: Readonly<RoomListSearchViewProps>): JSX.Element {
|
|
||||||
const { translate: _t } = useI18n();
|
|
||||||
const { displayExploreButton, displayDialButton, searchShortcut } = useViewModel(vm);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
data-testid="room-list-search"
|
|
||||||
className={styles.view}
|
|
||||||
role="search"
|
|
||||||
gap="var(--cpd-space-2x)"
|
|
||||||
align="center"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
id="room-list-search-button"
|
|
||||||
className={styles.search}
|
|
||||||
kind="secondary"
|
|
||||||
size="sm"
|
|
||||||
Icon={SearchIcon}
|
|
||||||
onClick={vm.onSearchClick}
|
|
||||||
>
|
|
||||||
<Flex className={styles["search_container"]} as="span" justify="space-between">
|
|
||||||
<span className={styles["search_text"]}>{_t("action|search")}</span>
|
|
||||||
<kbd>{searchShortcut}</kbd>
|
|
||||||
</Flex>
|
|
||||||
</Button>
|
|
||||||
{displayDialButton && (
|
|
||||||
<Button
|
|
||||||
kind="secondary"
|
|
||||||
size="sm"
|
|
||||||
Icon={DialPadIcon}
|
|
||||||
iconOnly={true}
|
|
||||||
aria-label={_t("left_panel|open_dial_pad")}
|
|
||||||
onClick={vm.onDialPadClick}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{displayExploreButton && (
|
|
||||||
<Button
|
|
||||||
kind="secondary"
|
|
||||||
size="sm"
|
|
||||||
Icon={ExploreIcon}
|
|
||||||
iconOnly={true}
|
|
||||||
aria-label={_t("action|explore_rooms")}
|
|
||||||
onClick={vm.onExploreClick}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
|
||||||
|
|
||||||
exports[`RoomListSearchView Storybook snapshots renders the default state 1`] = `
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
class="flex view"
|
|
||||||
data-testid="room-list-search"
|
|
||||||
role="search"
|
|
||||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x); --mx-flex-wrap: nowrap;"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="_button_187yx_8 search _has-icon_187yx_57"
|
|
||||||
data-kind="secondary"
|
|
||||||
data-size="sm"
|
|
||||||
id="room-list-search-button"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
fill="currentColor"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="20"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M15.05 16.463a7.5 7.5 0 1 1 1.414-1.414l3.243 3.244a1 1 0 0 1-1.414 1.414zM16 10.5a5.5 5.5 0 1 0-11 0 5.5 5.5 0 0 0 11 0"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span
|
|
||||||
class="flex search_container"
|
|
||||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: start; --mx-flex-justify: space-between; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="search_text"
|
|
||||||
>
|
|
||||||
Search
|
|
||||||
</span>
|
|
||||||
<kbd>
|
|
||||||
⌘ K
|
|
||||||
</kbd>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
aria-label="Explore rooms"
|
|
||||||
class="_button_187yx_8 _has-icon_187yx_57 _icon-only_187yx_50"
|
|
||||||
data-kind="secondary"
|
|
||||||
data-size="sm"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
fill="currentColor"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="20"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M12 13a.97.97 0 0 1-.713-.287A.97.97 0 0 1 11 12q0-.424.287-.713A.97.97 0 0 1 12 11q.424 0 .713.287.287.288.287.713 0 .424-.287.713A.97.97 0 0 1 12 13m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22m0-2q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4 6.325 6.325 4 12t2.325 5.675T12 20m0 0q-3.35 0-5.675-2.325T4 12t2.325-5.675T12 4t5.675 2.325T20 12t-2.325 5.675T12 20m1.675-5.85q.15-.075.275-.2t.2-.275l2.925-6.25q.125-.25-.062-.437-.188-.188-.438-.063l-6.25 2.925q-.15.075-.275.2t-.2.275l-2.925 6.25q-.125.25.063.438.186.186.437.062z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`RoomListSearchView Storybook snapshots renders with all buttons visible 1`] = `
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
class="flex view"
|
|
||||||
data-testid="room-list-search"
|
|
||||||
role="search"
|
|
||||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x); --mx-flex-wrap: nowrap;"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="_button_187yx_8 search _has-icon_187yx_57"
|
|
||||||
data-kind="secondary"
|
|
||||||
data-size="sm"
|
|
||||||
id="room-list-search-button"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
fill="currentColor"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="20"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M15.05 16.463a7.5 7.5 0 1 1 1.414-1.414l3.243 3.244a1 1 0 0 1-1.414 1.414zM16 10.5a5.5 5.5 0 1 0-11 0 5.5 5.5 0 0 0 11 0"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span
|
|
||||||
class="flex search_container"
|
|
||||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: start; --mx-flex-justify: space-between; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="search_text"
|
|
||||||
>
|
|
||||||
Search
|
|
||||||
</span>
|
|
||||||
<kbd>
|
|
||||||
⌘ K
|
|
||||||
</kbd>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
aria-label="Open dial pad"
|
|
||||||
class="_button_187yx_8 _has-icon_187yx_57 _icon-only_187yx_50"
|
|
||||||
data-kind="secondary"
|
|
||||||
data-size="sm"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
fill="currentColor"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="20"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M12 18.6c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8M6.6 2.4c-.99 0-1.8.81-1.8 1.8S5.61 6 6.6 6s1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0 5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0 5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8M17.4 6c.99 0 1.8-.81 1.8-1.8s-.81-1.8-1.8-1.8-1.8.81-1.8 1.8.81 1.8 1.8 1.8M12 13.2c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m5.4 0c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0-5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m-5.4 0c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0-5.4c-.99 0-1.8.81-1.8 1.8S11.01 6 12 6s1.8-.81 1.8-1.8-.81-1.8-1.8-1.8"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
aria-label="Explore rooms"
|
|
||||||
class="_button_187yx_8 _has-icon_187yx_57 _icon-only_187yx_50"
|
|
||||||
data-kind="secondary"
|
|
||||||
data-size="sm"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
fill="currentColor"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="20"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M12 13a.97.97 0 0 1-.713-.287A.97.97 0 0 1 11 12q0-.424.287-.713A.97.97 0 0 1 12 11q.424 0 .713.287.287.288.287.713 0 .424-.287.713A.97.97 0 0 1 12 13m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22m0-2q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4 6.325 6.325 4 12t2.325 5.675T12 20m0 0q-3.35 0-5.675-2.325T4 12t2.325-5.675T12 4t5.675 2.325T20 12t-2.325 5.675T12 20m1.675-5.85q.15-.075.275-.2t.2-.275l2.925-6.25q.125-.25-.062-.437-.188-.188-.438-.063l-6.25 2.925q-.15.075-.275.2t-.2.275l-2.925 6.25q-.125.25.063.438.186.186.437.062z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`RoomListSearchView Storybook snapshots renders with dial pad button 1`] = `
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
class="flex view"
|
|
||||||
data-testid="room-list-search"
|
|
||||||
role="search"
|
|
||||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x); --mx-flex-wrap: nowrap;"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="_button_187yx_8 search _has-icon_187yx_57"
|
|
||||||
data-kind="secondary"
|
|
||||||
data-size="sm"
|
|
||||||
id="room-list-search-button"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
fill="currentColor"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="20"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M15.05 16.463a7.5 7.5 0 1 1 1.414-1.414l3.243 3.244a1 1 0 0 1-1.414 1.414zM16 10.5a5.5 5.5 0 1 0-11 0 5.5 5.5 0 0 0 11 0"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span
|
|
||||||
class="flex search_container"
|
|
||||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: start; --mx-flex-justify: space-between; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="search_text"
|
|
||||||
>
|
|
||||||
Search
|
|
||||||
</span>
|
|
||||||
<kbd>
|
|
||||||
⌘ K
|
|
||||||
</kbd>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
aria-label="Open dial pad"
|
|
||||||
class="_button_187yx_8 _has-icon_187yx_57 _icon-only_187yx_50"
|
|
||||||
data-kind="secondary"
|
|
||||||
data-size="sm"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
fill="currentColor"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="20"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M12 18.6c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8M6.6 2.4c-.99 0-1.8.81-1.8 1.8S5.61 6 6.6 6s1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0 5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0 5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8M17.4 6c.99 0 1.8-.81 1.8-1.8s-.81-1.8-1.8-1.8-1.8.81-1.8 1.8.81 1.8 1.8 1.8M12 13.2c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m5.4 0c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0-5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m-5.4 0c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0-5.4c-.99 0-1.8.81-1.8 1.8S11.01 6 12 6s1.8-.81 1.8-1.8-.81-1.8-1.8-1.8"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
aria-label="Explore rooms"
|
|
||||||
class="_button_187yx_8 _has-icon_187yx_57 _icon-only_187yx_50"
|
|
||||||
data-kind="secondary"
|
|
||||||
data-size="sm"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
fill="currentColor"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="20"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M12 13a.97.97 0 0 1-.713-.287A.97.97 0 0 1 11 12q0-.424.287-.713A.97.97 0 0 1 12 11q.424 0 .713.287.287.288.287.713 0 .424-.287.713A.97.97 0 0 1 12 13m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22m0-2q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4 6.325 6.325 4 12t2.325 5.675T12 20m0 0q-3.35 0-5.675-2.325T4 12t2.325-5.675T12 4t5.675 2.325T20 12t-2.325 5.675T12 20m1.675-5.85q.15-.075.275-.2t.2-.275l2.925-6.25q.125-.25-.062-.437-.188-.188-.438-.063l-6.25 2.925q-.15.075-.275.2t-.2.275l-2.925 6.25q-.125.25.063.438.186.186.437.062z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`RoomListSearchView Storybook snapshots renders without explore button 1`] = `
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
class="flex view"
|
|
||||||
data-testid="room-list-search"
|
|
||||||
role="search"
|
|
||||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x); --mx-flex-wrap: nowrap;"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="_button_187yx_8 search _has-icon_187yx_57"
|
|
||||||
data-kind="secondary"
|
|
||||||
data-size="sm"
|
|
||||||
id="room-list-search-button"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
fill="currentColor"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="20"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M15.05 16.463a7.5 7.5 0 1 1 1.414-1.414l3.243 3.244a1 1 0 0 1-1.414 1.414zM16 10.5a5.5 5.5 0 1 0-11 0 5.5 5.5 0 0 0 11 0"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span
|
|
||||||
class="flex search_container"
|
|
||||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: start; --mx-flex-justify: space-between; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="search_text"
|
|
||||||
>
|
|
||||||
Search
|
|
||||||
</span>
|
|
||||||
<kbd>
|
|
||||||
⌘ K
|
|
||||||
</kbd>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2025 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
||||||
* Please see LICENSE files in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type { RoomListSearchViewModel, RoomListSearchViewSnapshot } from "./RoomListSearchView";
|
|
||||||
export { RoomListSearchView } from "./RoomListSearchView";
|
|
||||||
@@ -313,9 +313,9 @@
|
|||||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||||
|
|
||||||
"@element-hq/element-web-module-api@^1.8.0":
|
"@element-hq/element-web-module-api@^1.8.0":
|
||||||
version "1.9.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/@element-hq/element-web-module-api/-/element-web-module-api-1.9.0.tgz#2e4fcc8809418c8670d4f0576bc4a9a235bc6c50"
|
resolved "https://registry.yarnpkg.com/@element-hq/element-web-module-api/-/element-web-module-api-1.8.0.tgz#95aa4ec22609cf0f4a7f24274473af0645a16f2a"
|
||||||
integrity sha512-Ao/V9w+wysZK4bh61LlKlznF10n2ZbD6KcUI46/zUMttXbmJn3ahvbzhEpwYcD+Cjy3ag5ycxLIIGkKV/fncXg==
|
integrity sha512-lMiDA9ubP3mZZupIMT8T3wS0riX30rYZj3pFpdP4cfZhkWZa3FJFStokAy5OnaHyENC7Px1cqkBGqilOWewY/A==
|
||||||
|
|
||||||
"@element-hq/element-web-playwright-common@^2.0.0":
|
"@element-hq/element-web-playwright-common@^2.0.0":
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
@@ -2032,9 +2032,9 @@
|
|||||||
integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==
|
integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==
|
||||||
|
|
||||||
"@vector-im/compound-design-tokens@^6.3.0":
|
"@vector-im/compound-design-tokens@^6.3.0":
|
||||||
version "6.4.2"
|
version "6.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-6.4.2.tgz#29189d6480c8ccf09ce143cb4618fb13a56a7583"
|
resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-6.4.0.tgz#2e51f39f79ebda985a2f6cf80d567b9307aff03a"
|
||||||
integrity sha512-LHLGZgnatH3mQXn9TF+m/SUinPS2nKvuCT/r2AQ7HAgEIG/S/Ck6e/iV4IFQLSZnd9gU0RlMsLkP2UQ/AKUEBA==
|
integrity sha512-93nYQZMgUt6apjCwwnMhMxN8VYQXN3GYOnwovwJjavImwsCGwI/e853BV/DstrWumYh6k5pZsP9e6AF+nz3SIQ==
|
||||||
|
|
||||||
"@vitest/expect@3.2.4":
|
"@vitest/expect@3.2.4":
|
||||||
version "3.2.4"
|
version "3.2.4"
|
||||||
@@ -5855,9 +5855,9 @@ prelude-ls@^1.2.1:
|
|||||||
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
||||||
|
|
||||||
prettier@^3.6.2:
|
prettier@^3.6.2:
|
||||||
version "3.7.4"
|
version "3.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.7.4.tgz#d2f8335d4b1cec47e1c8098645411b0c9dff9c0f"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393"
|
||||||
integrity sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==
|
integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==
|
||||||
|
|
||||||
pretty-format@30.2.0, pretty-format@^30.0.0:
|
pretty-format@30.2.0, pretty-format@^30.0.0:
|
||||||
version "30.2.0"
|
version "30.2.0"
|
||||||
@@ -7088,9 +7088,9 @@ vite-plugin-node-polyfills@^0.24.0:
|
|||||||
node-stdlib-browser "^1.2.0"
|
node-stdlib-browser "^1.2.0"
|
||||||
|
|
||||||
vite@^7.1.9:
|
vite@^7.1.9:
|
||||||
version "7.2.7"
|
version "7.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/vite/-/vite-7.2.7.tgz#0789a4c3206081699f34a9ecca2dda594a07478e"
|
resolved "https://registry.yarnpkg.com/vite/-/vite-7.2.4.tgz#a3a09c7e25487612ecc1119c7d412c73da35bd4e"
|
||||||
integrity sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==
|
integrity sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.25.0"
|
esbuild "^0.25.0"
|
||||||
fdir "^6.5.0"
|
fdir "^6.5.0"
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ test.describe("Landmark navigation tests", () => {
|
|||||||
|
|
||||||
// Pressing Control+F6 again will focus room search
|
// Pressing Control+F6 again will focus room search
|
||||||
await page.keyboard.press("ControlOrMeta+F6");
|
await page.keyboard.press("ControlOrMeta+F6");
|
||||||
await expect(page.locator("#room-list-search-button")).toBeFocused();
|
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||||
|
|
||||||
// Pressing Control+F6 again will focus the message composer
|
// Pressing Control+F6 again will focus the message composer
|
||||||
await page.keyboard.press("ControlOrMeta+F6");
|
await page.keyboard.press("ControlOrMeta+F6");
|
||||||
@@ -44,7 +44,7 @@ test.describe("Landmark navigation tests", () => {
|
|||||||
await expect(page.locator(".mx_HomePage")).toBeFocused();
|
await expect(page.locator(".mx_HomePage")).toBeFocused();
|
||||||
|
|
||||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||||
await expect(page.locator("#room-list-search-button")).toBeFocused();
|
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||||
|
|
||||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||||
await expect(page.locator(".mx_SpaceButton_active")).toBeFocused();
|
await expect(page.locator(".mx_SpaceButton_active")).toBeFocused();
|
||||||
@@ -75,7 +75,7 @@ test.describe("Landmark navigation tests", () => {
|
|||||||
|
|
||||||
// Pressing Control+F6 again will focus room search
|
// Pressing Control+F6 again will focus room search
|
||||||
await page.keyboard.press("ControlOrMeta+F6");
|
await page.keyboard.press("ControlOrMeta+F6");
|
||||||
await expect(page.locator("#room-list-search-button")).toBeFocused();
|
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||||
|
|
||||||
// Pressing Control+F6 again will focus the room tile in the room list
|
// Pressing Control+F6 again will focus the room tile in the room list
|
||||||
await page.keyboard.press("ControlOrMeta+F6");
|
await page.keyboard.press("ControlOrMeta+F6");
|
||||||
@@ -97,7 +97,7 @@ test.describe("Landmark navigation tests", () => {
|
|||||||
await expect(page.locator(".mx_RoomListItemView_selected")).toBeFocused();
|
await expect(page.locator(".mx_RoomListItemView_selected")).toBeFocused();
|
||||||
|
|
||||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||||
await expect(page.locator("#room-list-search-button")).toBeFocused();
|
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||||
|
|
||||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||||
await expect(page.locator(".mx_SpaceButton_active")).toBeFocused();
|
await expect(page.locator(".mx_SpaceButton_active")).toBeFocused();
|
||||||
@@ -131,7 +131,7 @@ test.describe("Landmark navigation tests", () => {
|
|||||||
|
|
||||||
// Pressing Control+F6 again will focus room search
|
// Pressing Control+F6 again will focus room search
|
||||||
await page.keyboard.press("ControlOrMeta+F6");
|
await page.keyboard.press("ControlOrMeta+F6");
|
||||||
await expect(page.locator("#room-list-search-button")).toBeFocused();
|
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||||
|
|
||||||
// Pressing Control+F6 again will focus the room tile in the room list
|
// Pressing Control+F6 again will focus the room tile in the room list
|
||||||
await page.keyboard.press("ControlOrMeta+F6");
|
await page.keyboard.press("ControlOrMeta+F6");
|
||||||
@@ -153,7 +153,7 @@ test.describe("Landmark navigation tests", () => {
|
|||||||
await expect(page.locator(".mx_RoomListItemView")).toBeFocused();
|
await expect(page.locator(".mx_RoomListItemView")).toBeFocused();
|
||||||
|
|
||||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||||
await expect(page.locator("#room-list-search-button")).toBeFocused();
|
await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused();
|
||||||
|
|
||||||
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
await page.keyboard.press("ControlOrMeta+Shift+F6");
|
||||||
await expect(page.locator(".mx_SpaceButton_active")).toBeFocused();
|
await expect(page.locator(".mx_SpaceButton_active")).toBeFocused();
|
||||||
|
|||||||
@@ -168,19 +168,5 @@ test.describe("Composer", () => {
|
|||||||
await composer.press("Enter");
|
await composer.press("Enter");
|
||||||
await expect(page.locator(".mx_EventTile_body", { hasText: "Bob" })).toBeVisible();
|
await expect(page.locator(".mx_EventTile_body", { hasText: "Bob" })).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders emoji autocomplete", { tag: "@screenshot" }, async ({ page }) => {
|
|
||||||
const composer = page.getByRole("textbox", { name: "Send an unencrypted message…" });
|
|
||||||
|
|
||||||
// Type ":+1" to trigger emoji autocomplete
|
|
||||||
await composer.pressSequentially(":+1");
|
|
||||||
|
|
||||||
// Wait for autocomplete to appear
|
|
||||||
const autocomplete = page.locator("#mx_Autocomplete");
|
|
||||||
await expect(autocomplete).toBeVisible();
|
|
||||||
|
|
||||||
// Take a screenshot of the autocomplete
|
|
||||||
await expect(autocomplete).toMatchScreenshot("emoji-autocomplete.png");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -130,68 +130,53 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
|
|||||||
await page.unrouteAll({ behavior: "ignoreErrors" });
|
await page.unrouteAll({ behavior: "ignoreErrors" });
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test("Verify device with QR code during login", async ({ page, app, credentials, homeserver }) => {
|
||||||
"Verify device with QR code during login",
|
// A mode 0x02 verification: "self-verifying in which the current device does not yet trust the master key"
|
||||||
{ tag: "@screenshot" },
|
await logIntoElement(page, credentials);
|
||||||
async ({ page, app, credentials, homeserver }) => {
|
|
||||||
// A mode 0x02 verification: "self-verifying in which the current device does not yet trust the master key"
|
|
||||||
await logIntoElement(page, credentials);
|
|
||||||
|
|
||||||
// Launch the verification request between alice and the bot
|
// Launch the verification request between alice and the bot
|
||||||
const verificationRequest = await initiateAliceVerificationRequest(page);
|
const verificationRequest = await initiateAliceVerificationRequest(page);
|
||||||
|
|
||||||
const infoDialog = page.locator(".mx_InfoDialog");
|
const infoDialog = page.locator(".mx_InfoDialog");
|
||||||
// feed the QR code into the verification request.
|
// feed the QR code into the verification request.
|
||||||
const qrData = await readQrCode(infoDialog);
|
const qrData = await readQrCode(infoDialog);
|
||||||
await expect(page.locator(".mx_Dialog")).toMatchScreenshot("qr-code.png", {
|
const verifier = await verificationRequest.evaluateHandle(
|
||||||
mask: [infoDialog.locator("img")],
|
(request, qrData) => request.scanQRCode(new Uint8ClampedArray(qrData)),
|
||||||
});
|
[...qrData],
|
||||||
const verifier = await verificationRequest.evaluateHandle(
|
);
|
||||||
(request, qrData) => request.scanQRCode(new Uint8ClampedArray(qrData)),
|
|
||||||
[...qrData],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Confirm that the bot user scanned successfully
|
// Confirm that the bot user scanned successfully
|
||||||
await expect(
|
await expect(infoDialog.getByText("Confirm that you see a green shield on your other device")).toBeVisible();
|
||||||
infoDialog.getByText("Confirm that you see a green shield on your other device"),
|
await infoDialog.getByRole("button", { name: "Yes, I see a green shield" }).click();
|
||||||
).toBeVisible();
|
await infoDialog.getByRole("button", { name: "Got it" }).click();
|
||||||
await expect(page.locator(".mx_Dialog")).toMatchScreenshot("confirm-green-shield.png");
|
|
||||||
await infoDialog.getByRole("button", { name: "Yes, I see a green shield" }).click();
|
|
||||||
await expect(page.locator(".mx_Dialog")).toMatchScreenshot("got-it.png");
|
|
||||||
await infoDialog.getByRole("button", { name: "Got it" }).click();
|
|
||||||
|
|
||||||
// wait for the bot to see we have finished
|
// wait for the bot to see we have finished
|
||||||
await verifier.evaluate((verifier) => verifier.verify());
|
await verifier.evaluate((verifier) => verifier.verify());
|
||||||
|
|
||||||
// the bot uploads the signatures asynchronously, so wait for that to happen
|
// the bot uploads the signatures asynchronously, so wait for that to happen
|
||||||
await page.waitForTimeout(1000);
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
// our device should trust the bot device
|
// our device should trust the bot device
|
||||||
await app.client.evaluate(async (cli, aliceBotCredentials) => {
|
await app.client.evaluate(async (cli, aliceBotCredentials) => {
|
||||||
const deviceStatus = await cli
|
const deviceStatus = await cli
|
||||||
.getCrypto()!
|
.getCrypto()!
|
||||||
.getDeviceVerificationStatus(aliceBotCredentials.userId, aliceBotCredentials.deviceId);
|
.getDeviceVerificationStatus(aliceBotCredentials.userId, aliceBotCredentials.deviceId);
|
||||||
if (!deviceStatus.isVerified()) {
|
if (!deviceStatus.isVerified()) {
|
||||||
throw new Error("Bot device was not verified after QR code verification");
|
throw new Error("Bot device was not verified after QR code verification");
|
||||||
}
|
}
|
||||||
}, aliceBotClient.credentials);
|
}, aliceBotClient.credentials);
|
||||||
|
|
||||||
// Check that our device is now cross-signed
|
// Check that our device is now cross-signed
|
||||||
await checkDeviceIsCrossSigned(app);
|
await checkDeviceIsCrossSigned(app);
|
||||||
|
|
||||||
// Check that the current device is connected to key backup
|
// Check that the current device is connected to key backup
|
||||||
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
|
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
test("Verify device with Security Phrase during login", async ({ page, app, credentials, homeserver }) => {
|
||||||
"Verify device with Security Phrase during login",
|
await logIntoElement(page, credentials);
|
||||||
{ tag: "@screenshot" },
|
await enterRecoveryKeyAndCheckVerified(page, app, "new passphrase");
|
||||||
async ({ page, app, credentials, homeserver }) => {
|
});
|
||||||
await logIntoElement(page, credentials);
|
|
||||||
await enterRecoveryKeyAndCheckVerified(page, app, "new passphrase", true);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
test("Verify device with Recovery Key during login", async ({ page, app, credentials, homeserver }) => {
|
test("Verify device with Recovery Key during login", async ({ page, app, credentials, homeserver }) => {
|
||||||
const recoveryKey = (await aliceBotClient.getRecoveryKey()).encodedPrivateKey;
|
const recoveryKey = (await aliceBotClient.getRecoveryKey()).encodedPrivateKey;
|
||||||
@@ -241,12 +226,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/** Helper for the three tests above which verify by recovery key */
|
/** Helper for the three tests above which verify by recovery key */
|
||||||
async function enterRecoveryKeyAndCheckVerified(
|
async function enterRecoveryKeyAndCheckVerified(page: Page, app: ElementAppPage, recoveryKey: string) {
|
||||||
page: Page,
|
|
||||||
app: ElementAppPage,
|
|
||||||
recoveryKey: string,
|
|
||||||
screenshot = false,
|
|
||||||
) {
|
|
||||||
await page.getByRole("button", { name: "Use recovery key" }).click();
|
await page.getByRole("button", { name: "Use recovery key" }).click();
|
||||||
|
|
||||||
// Enter the recovery key
|
// Enter the recovery key
|
||||||
@@ -254,12 +234,8 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
|
|||||||
// We use `pressSequentially` here to make sure that the FocusLock isn't causing us any problems
|
// We use `pressSequentially` here to make sure that the FocusLock isn't causing us any problems
|
||||||
// (cf https://github.com/element-hq/element-web/issues/30089)
|
// (cf https://github.com/element-hq/element-web/issues/30089)
|
||||||
await dialog.getByTitle("Recovery key").pressSequentially(recoveryKey);
|
await dialog.getByTitle("Recovery key").pressSequentially(recoveryKey);
|
||||||
if (screenshot) {
|
|
||||||
await expect(page.locator(".mx_Dialog").filter({ hasText: "Enter your recovery key" })).toMatchScreenshot(
|
|
||||||
"recovery-key.png",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await dialog.getByRole("button", { name: "Continue", disabled: false }).click();
|
await dialog.getByRole("button", { name: "Continue", disabled: false }).click();
|
||||||
|
|
||||||
await page.getByRole("button", { name: "Done" }).click();
|
await page.getByRole("button", { name: "Done" }).click();
|
||||||
|
|
||||||
// Check that our device is now cross-signed
|
// Check that our device is now cross-signed
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ export const test = base.extend<{
|
|||||||
room1Name: "Room 1",
|
room1Name: "Room 1",
|
||||||
room1: async ({ room1Name: name, app, user, bot }, use) => {
|
room1: async ({ room1Name: name, app, user, bot }, use) => {
|
||||||
const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] });
|
const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] });
|
||||||
await bot.awaitRoomMembership(roomId);
|
|
||||||
await use({ name, roomId });
|
await use({ name, roomId });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -36,13 +36,11 @@ export const test = base.extend<{
|
|||||||
roomAlphaName: "Room Alpha",
|
roomAlphaName: "Room Alpha",
|
||||||
roomAlpha: async ({ roomAlphaName: name, app, user, bot }, use) => {
|
roomAlpha: async ({ roomAlphaName: name, app, user, bot }, use) => {
|
||||||
const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] });
|
const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] });
|
||||||
await bot.awaitRoomMembership(roomId);
|
|
||||||
await use({ name, roomId });
|
await use({ name, roomId });
|
||||||
},
|
},
|
||||||
roomBetaName: "Room Beta",
|
roomBetaName: "Room Beta",
|
||||||
roomBeta: async ({ roomBetaName: name, app, user, bot }, use) => {
|
roomBeta: async ({ roomBetaName: name, app, user, bot }, use) => {
|
||||||
const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] });
|
const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] });
|
||||||
await bot.awaitRoomMembership(roomId);
|
|
||||||
await use({ name, roomId });
|
await use({ name, roomId });
|
||||||
},
|
},
|
||||||
msg: async ({ page, app, util }, use) => {
|
msg: async ({ page, app, util }, use) => {
|
||||||
|
|||||||
@@ -13,30 +13,72 @@ import { test } from ".";
|
|||||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||||
test.describe("Message ordering", () => {
|
test.describe("Message ordering", () => {
|
||||||
test.describe("in the main timeline", () => {
|
test.describe("in the main timeline", () => {
|
||||||
test.fixme("A receipt for the last event in sync order (even with wrong ts) marks a room as read", () => {});
|
test.fixme(
|
||||||
test.fixme("A receipt for a non-last event in sync order (even when ts makes it last) leaves room unread", () => {});
|
"A receipt for the last event in sync order (even with wrong ts) marks a room as read",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"A receipt for a non-last event in sync order (even when ts makes it last) leaves room unread",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe("in threads", () => {
|
test.describe("in threads", () => {
|
||||||
// These don't pass yet - we need MSC4033 - we don't even know the Sync order yet
|
// These don't pass yet - we need MSC4033 - we don't even know the Sync order yet
|
||||||
test.fixme("A receipt for the last event in sync order (even with wrong ts) marks a thread as read", () => {});
|
test.fixme(
|
||||||
test.fixme("A receipt for a non-last event in sync order (even when ts makes it last) leaves thread unread", () => {});
|
"A receipt for the last event in sync order (even with wrong ts) marks a thread as read",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"A receipt for a non-last event in sync order (even when ts makes it last) leaves thread unread",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
|
||||||
// These pass now and should not later - we should use order from MSC4033 instead of ts
|
// These pass now and should not later - we should use order from MSC4033 instead of ts
|
||||||
// These are broken out
|
// These are broken out
|
||||||
test.fixme("A receipt for last threaded event in ts order (even when it was received non-last) marks a thread as read", () => {});
|
test.fixme(
|
||||||
test.fixme("A receipt for non-last threaded event in ts order (even when it was received last) leaves thread unread", () => {});
|
"A receipt for last threaded event in ts order (even when it was received non-last) marks a thread as read",
|
||||||
test.fixme("A receipt for last threaded edit in ts order (even when it was received non-last) marks a thread as read", () => {});
|
() => {},
|
||||||
test.fixme("A receipt for non-last threaded edit in ts order (even when it was received last) leaves thread unread", () => {});
|
);
|
||||||
test.fixme("A receipt for last threaded reaction in ts order (even when it was received non-last) marks a thread as read", () => {});
|
test.fixme(
|
||||||
test.fixme("A receipt for non-last threaded reaction in ts order (even when it was received last) leaves thread unread", () => {});
|
"A receipt for non-last threaded event in ts order (even when it was received last) leaves thread unread",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"A receipt for last threaded edit in ts order (even when it was received non-last) marks a thread as read",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"A receipt for non-last threaded edit in ts order (even when it was received last) leaves thread unread",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"A receipt for last threaded reaction in ts order (even when it was received non-last) marks a thread as read",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"A receipt for non-last threaded reaction in ts order (even when it was received last) leaves thread unread",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe("thread roots", () => {
|
test.describe("thread roots", () => {
|
||||||
test.fixme("A receipt for last reaction to thread root in sync order (even when ts makes it last) marks room as read", () => {});
|
test.fixme(
|
||||||
test.fixme("A receipt for non-last reaction to thread root in sync order (even when ts makes it last) leaves room unread", () => {});
|
"A receipt for last reaction to thread root in sync order (even when ts makes it last) marks room as read",
|
||||||
test.fixme("A receipt for last edit to thread root in sync order (even when ts makes it last) marks room as read", () => {});
|
() => {},
|
||||||
test.fixme("A receipt for non-last edit to thread root in sync order (even when ts makes it last) leaves room unread", () => {});
|
);
|
||||||
|
test.fixme(
|
||||||
|
"A receipt for non-last reaction to thread root in sync order (even when ts makes it last) leaves room unread",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"A receipt for last edit to thread root in sync order (even when ts makes it last) marks room as read",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"A receipt for non-last edit to thread root in sync order (even when ts makes it last) leaves room unread",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,20 +12,18 @@ import { test } from ".";
|
|||||||
|
|
||||||
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||||
test.describe("messages with missing referents", () => {
|
test.describe("messages with missing referents", () => {
|
||||||
test.fixme("A message in an unknown thread is not visible and the room is read", async ({
|
test.fixme(
|
||||||
roomAlpha: room1,
|
"A message in an unknown thread is not visible and the room is read",
|
||||||
roomBeta: room2,
|
async ({ roomAlpha: room1, roomBeta: room2, util, msg }) => {
|
||||||
util,
|
// Given a thread existed and the room is read
|
||||||
msg,
|
await util.goTo(room1);
|
||||||
}) => {
|
await util.receiveMessages(room2, ["Root1", msg.threadedOff("Root1", "T1a")]);
|
||||||
// Given a thread existed and the room is read
|
|
||||||
await util.goTo(room1);
|
|
||||||
await util.receiveMessages(room2, ["Root1", msg.threadedOff("Root1", "T1a")]);
|
|
||||||
|
|
||||||
// When I restart, forgetting the thread root
|
// When I restart, forgetting the thread root
|
||||||
// And I receive a message on that thread
|
// And I receive a message on that thread
|
||||||
// Then the message is invisible and the room remains read
|
// Then the message is invisible and the room remains read
|
||||||
});
|
},
|
||||||
|
);
|
||||||
test.fixme("When a message's thread root appears later the thread appears and the room is unread", () => {});
|
test.fixme("When a message's thread root appears later the thread appears and the room is unread", () => {});
|
||||||
test.fixme("An edit of an unknown message is not visible and the room is read", () => {});
|
test.fixme("An edit of an unknown message is not visible and the room is read", () => {});
|
||||||
test.fixme("When an edit's message appears later the edited version appears and the room is unread", () => {});
|
test.fixme("When an edit's message appears later the edited version appears and the room is unread", () => {});
|
||||||
|
|||||||
@@ -14,8 +14,14 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
|||||||
test.describe("Notifications", () => {
|
test.describe("Notifications", () => {
|
||||||
test.describe("in the main timeline", () => {
|
test.describe("in the main timeline", () => {
|
||||||
test.fixme("A new message that mentions me shows a notification", () => {});
|
test.fixme("A new message that mentions me shows a notification", () => {});
|
||||||
test.fixme("Reading a notifying message reduces the notification count in the room list, space and tab", () => {});
|
test.fixme(
|
||||||
test.fixme("Reading the last notifying message removes the notification marker from room list, space and tab", () => {});
|
"Reading a notifying message reduces the notification count in the room list, space and tab",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"Reading the last notifying message removes the notification marker from room list, space and tab",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
test.fixme("Editing a message to mentions me shows a notification", () => {});
|
test.fixme("Editing a message to mentions me shows a notification", () => {});
|
||||||
test.fixme("Reading the last notifying edited message removes the notification marker", () => {});
|
test.fixme("Reading the last notifying edited message removes the notification marker", () => {});
|
||||||
test.fixme("Redacting a notifying message removes the notification marker", () => {});
|
test.fixme("Redacting a notifying message removes the notification marker", () => {});
|
||||||
@@ -24,9 +30,18 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
|||||||
test.describe("in threads", () => {
|
test.describe("in threads", () => {
|
||||||
test.fixme("A new threaded message that mentions me shows a notification", () => {});
|
test.fixme("A new threaded message that mentions me shows a notification", () => {});
|
||||||
test.fixme("Reading a notifying threaded message removes the notification count", () => {});
|
test.fixme("Reading a notifying threaded message removes the notification count", () => {});
|
||||||
test.fixme("Notification count remains steady when reading threads that contain seen notifications", () => {});
|
test.fixme(
|
||||||
test.fixme("Notification count remains steady when paging up thread view even when threads contain seen notifications", () => {});
|
"Notification count remains steady when reading threads that contain seen notifications",
|
||||||
test.fixme("Notification count remains steady when paging up thread view after mark as unread even if older threads contain notifications", () => {});
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"Notification count remains steady when paging up thread view even when threads contain seen notifications",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
test.fixme(
|
||||||
|
"Notification count remains steady when paging up thread view after mark as unread even if older threads contain notifications",
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
test.fixme("Redacting a notifying threaded message removes the notification marker", () => {});
|
test.fixme("Redacting a notifying threaded message removes the notification marker", () => {});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ test.describe("RightPanel", () => {
|
|||||||
|
|
||||||
// \d represents the number of the space members
|
// \d represents the number of the space members
|
||||||
await page
|
await page
|
||||||
.locator(".mx_RoomInfoLine")
|
.locator(".mx_RoomInfoLine_private")
|
||||||
.getByRole("button", { name: /\d member/ })
|
.getByRole("button", { name: /\d member/ })
|
||||||
.click();
|
.click();
|
||||||
await expect(page.locator(".mx_MemberListView")).toBeVisible();
|
await expect(page.locator(".mx_MemberListView")).toBeVisible();
|
||||||
|
|||||||
@@ -264,7 +264,6 @@ test.describe("Element Call", () => {
|
|||||||
preset: "trusted_private_chat" as Preset.TrustedPrivateChat,
|
preset: "trusted_private_chat" as Preset.TrustedPrivateChat,
|
||||||
invite: [bot.credentials.userId],
|
invite: [bot.credentials.userId],
|
||||||
});
|
});
|
||||||
await bot.awaitRoomMembership(roomId);
|
|
||||||
await app.client.setAccountData("m.direct" as EventType.Direct, {
|
await app.client.setAccountData("m.direct" as EventType.Direct, {
|
||||||
[bot.credentials.userId]: [roomId],
|
[bot.credentials.userId]: [roomId],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ test.describe("PSTN", () => {
|
|||||||
await toasts.rejectToast("Notifications");
|
await toasts.rejectToast("Notifications");
|
||||||
await toasts.assertNoToasts();
|
await toasts.assertNoToasts();
|
||||||
|
|
||||||
await expect(page.getByTestId("room-list-search")).toMatchScreenshot("dialpad-trigger.png");
|
await expect(page.locator(".mx_RoomListSearch")).toMatchScreenshot("dialpad-trigger.png");
|
||||||
await page.getByLabel("Open dial pad").click();
|
await page.getByLabel("Open dial pad").click();
|
||||||
await expect(page.locator(".mx_Dialog")).toMatchScreenshot("dialpad.png");
|
await expect(page.locator(".mx_Dialog")).toMatchScreenshot("dialpad.png");
|
||||||
});
|
});
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.5 KiB |
@@ -10,7 +10,7 @@ import {
|
|||||||
type StartedPostgreSqlContainer,
|
type StartedPostgreSqlContainer,
|
||||||
} from "@element-hq/element-web-playwright-common/lib/testcontainers";
|
} from "@element-hq/element-web-playwright-common/lib/testcontainers";
|
||||||
|
|
||||||
const TAG = "main@sha256:1ffa26f3d7b1e7481e10ec23bbb65afc0394a1f0416462601b8ef5b0eaf9aced";
|
const TAG = "main@sha256:70ca0df3b7a8a92ebb6a679286c626084107b41f0fcceeb3f8ae43983d874474";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MatrixAuthenticationServiceContainer which freezes the docker digest to
|
* MatrixAuthenticationServiceContainer which freezes the docker digest to
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
|
|
||||||
import { SynapseContainer as BaseSynapseContainer } from "@element-hq/element-web-playwright-common/lib/testcontainers";
|
import { SynapseContainer as BaseSynapseContainer } from "@element-hq/element-web-playwright-common/lib/testcontainers";
|
||||||
|
|
||||||
const TAG = "develop@sha256:a2790ff0be7d8da93e26c09bcfedded2f5410affac87065cfe11309a85b4c728";
|
const TAG = "develop@sha256:ac511632cf3b91b27a2c9f2274edd9eb8777fb0a521982db7ee4e4e386dde62f";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SynapseContainer which freezes the docker digest to stabilise tests,
|
* SynapseContainer which freezes the docker digest to stabilise tests,
|
||||||
|
|||||||
@@ -79,7 +79,6 @@
|
|||||||
@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";
|
||||||
@@ -274,6 +273,7 @@
|
|||||||
@import "./views/rooms/RoomListPanel/_RoomListItemView.pcss";
|
@import "./views/rooms/RoomListPanel/_RoomListItemView.pcss";
|
||||||
@import "./views/rooms/RoomListPanel/_RoomListPanel.pcss";
|
@import "./views/rooms/RoomListPanel/_RoomListPanel.pcss";
|
||||||
@import "./views/rooms/RoomListPanel/_RoomListPrimaryFilters.pcss";
|
@import "./views/rooms/RoomListPanel/_RoomListPrimaryFilters.pcss";
|
||||||
|
@import "./views/rooms/RoomListPanel/_RoomListSearch.pcss";
|
||||||
@import "./views/rooms/RoomListPanel/_RoomListSecondaryFilters.pcss";
|
@import "./views/rooms/RoomListPanel/_RoomListSecondaryFilters.pcss";
|
||||||
@import "./views/rooms/RoomListPanel/_RoomListSkeleton.pcss";
|
@import "./views/rooms/RoomListPanel/_RoomListSkeleton.pcss";
|
||||||
@import "./views/rooms/_AppsDrawer.pcss";
|
@import "./views/rooms/_AppsDrawer.pcss";
|
||||||
@@ -281,6 +281,7 @@
|
|||||||
@import "./views/rooms/_AuxPanel.pcss";
|
@import "./views/rooms/_AuxPanel.pcss";
|
||||||
@import "./views/rooms/_BasicMessageComposer.pcss";
|
@import "./views/rooms/_BasicMessageComposer.pcss";
|
||||||
@import "./views/rooms/_CallGuestLinkButton.pcss";
|
@import "./views/rooms/_CallGuestLinkButton.pcss";
|
||||||
|
@import "./views/rooms/_DecryptionFailureBar.pcss";
|
||||||
@import "./views/rooms/_E2EIcon.pcss";
|
@import "./views/rooms/_E2EIcon.pcss";
|
||||||
@import "./views/rooms/_E2EIconView.pcss";
|
@import "./views/rooms/_E2EIconView.pcss";
|
||||||
@import "./views/rooms/_EditMessageComposer.pcss";
|
@import "./views/rooms/_EditMessageComposer.pcss";
|
||||||
@@ -382,6 +383,7 @@
|
|||||||
@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";
|
||||||
|
|||||||
@@ -114,30 +114,67 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_LeftPanel_dialPadButton,
|
.mx_LeftPanel_dialPadButton {
|
||||||
.mx_LeftPanel_exploreButton {
|
width: 32px;
|
||||||
width: 20px;
|
height: 32px;
|
||||||
height: 20px;
|
|
||||||
padding: var(--cpd-space-1-5x);
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background-color: $panel-actions;
|
background-color: $panel-actions;
|
||||||
|
position: relative;
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
width: inherit;
|
content: "";
|
||||||
height: inherit;
|
position: absolute;
|
||||||
display: block;
|
top: 6px;
|
||||||
color: $secondary-content;
|
left: 6px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/dial-pad.svg");
|
||||||
|
mask-position: center;
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
background-color: $secondary-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_LeftPanel_exploreButton,
|
||||||
|
.mx_LeftPanel_recentsButton {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: $panel-actions;
|
||||||
|
position: relative;
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
left: 8px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
mask-position: center;
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
background-color: $secondary-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $tertiary-content;
|
background-color: $tertiary-content;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
color: $background;
|
background-color: $background;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_LeftPanel_exploreButton::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/explore.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_LeftPanel_recentsButton::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/time.svg");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_LegacyRoomListHeader:first-child {
|
.mx_LegacyRoomListHeader:first-child {
|
||||||
@@ -191,7 +228,8 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_LeftPanel_exploreButton {
|
.mx_LeftPanel_exploreButton,
|
||||||
|
.mx_LeftPanel_recentsButton {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,17 +99,34 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
position: relative;
|
position: relative;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
& + .mx_AccessibleButton {
|
&:nth-child(2) {
|
||||||
border-left: 1px solid $resend-button-divider-color;
|
border-left: 1px solid $resend-button-divider-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
left: 10px; /* inset for regular button padding */
|
left: 10px; /* inset for regular button padding */
|
||||||
|
background-color: $muted-fg-color;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-position: center;
|
||||||
|
mask-size: contain;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
vertical-align: middle;
|
top: 50%; /* text sizes are dynamic */
|
||||||
color: $muted-fg-color;
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_RoomStatusBar_unsentCancelAllBtn::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/delete.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_RoomStatusBar_unsentRetry {
|
||||||
|
padding-left: 34px; /* 28px from above, but +6px to account for the wider icon */
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/restart.svg");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,8 +76,6 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
container-type: size;
|
|
||||||
container-name: roomview;
|
|
||||||
|
|
||||||
.mx_RoomView_messagePanel,
|
.mx_RoomView_messagePanel,
|
||||||
.mx_RoomView_messagePanelSpinner,
|
.mx_RoomView_messagePanelSpinner,
|
||||||
|
|||||||
@@ -17,14 +17,13 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
|
|
||||||
.mx_SearchBox_closeButton {
|
.mx_SearchBox_closeButton {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: 16px;
|
mask-image: url("@vector-im/compound-design-tokens/icons/close.svg");
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-position: center;
|
||||||
|
mask-size: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
padding: 9px;
|
padding: 9px;
|
||||||
|
background-color: var(--cpd-color-icon-secondary);
|
||||||
svg {
|
|
||||||
height: inherit;
|
|
||||||
width: inherit;
|
|
||||||
color: var(--cpd-color-icon-secondary);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,23 +44,29 @@ 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;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
height: inherit;
|
content: "";
|
||||||
|
position: absolute;
|
||||||
width: inherit;
|
width: inherit;
|
||||||
display: inline-block;
|
height: inherit;
|
||||||
color: $background;
|
mask-position: center;
|
||||||
/* Slight alignment tweak to center the asset */
|
mask-size: contain;
|
||||||
margin-left: 1px;
|
mask-repeat: no-repeat;
|
||||||
|
background-color: $background;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||||
|
transform: rotate(270deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.expanded) {
|
&:not(.expanded) {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
mask-position: center 1px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.expanded svg {
|
&.expanded::before {
|
||||||
transform: rotate(180deg);
|
transform: rotate(90deg);
|
||||||
/* Slight alignment tweak to center the asset */
|
|
||||||
margin-left: -1px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +103,7 @@ 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 {
|
||||||
@@ -159,67 +166,109 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_SpaceButton_toggleCollapse {
|
.mx_SpaceButton_toggleCollapse {
|
||||||
height: 20px;
|
|
||||||
width: var(--gutterSize);
|
width: var(--gutterSize);
|
||||||
flex-shrink: 0;
|
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
|
min-width: var(--gutterSize);
|
||||||
svg {
|
height: 20px;
|
||||||
width: 20px;
|
mask-position: center;
|
||||||
height: inherit;
|
mask-size: 20px;
|
||||||
display: inline-block;
|
mask-repeat: no-repeat;
|
||||||
color: $tertiary-content;
|
background-color: $tertiary-content;
|
||||||
/* Re-align with parent */
|
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||||
margin-left: -3px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_SpaceButton_icon {
|
.mx_SpaceButton_icon {
|
||||||
/* Calculate height excluding padding to allow svg to inherit */
|
width: var(--height-topLevel);
|
||||||
width: calc(var(--height-topLevel) - 14px);
|
min-width: var(--height-topLevel);
|
||||||
height: calc(var(--height-topLevel) - 14px);
|
height: var(--height-topLevel);
|
||||||
flex-shrink: 0;
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 7px;
|
position: relative;
|
||||||
background-color: $panel-actions;
|
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
width: inherit;
|
position: absolute;
|
||||||
height: inherit;
|
content: "";
|
||||||
display: block;
|
width: var(--height-topLevel);
|
||||||
color: $secondary-content;
|
height: var(--height-topLevel);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
mask-position: center;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-size: 18px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_SpaceButton_new .mx_SpaceButton_icon {
|
&.mx_SpaceButton_home,
|
||||||
background-color: unset;
|
&.mx_SpaceButton_favourites,
|
||||||
|
&.mx_SpaceButton_people,
|
||||||
|
&.mx_SpaceButton_orphans,
|
||||||
|
&.mx_SpaceButton_videoRooms {
|
||||||
|
.mx_SpaceButton_icon {
|
||||||
|
background-color: $panel-actions;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
color: $primary-content;
|
background-color: $secondary-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_SpaceButton_withIcon .mx_SpaceButton_icon {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_SpaceButton_new .mx_SpaceButton_icon {
|
||||||
|
&::before {
|
||||||
|
background-color: $primary-content;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/plus.svg");
|
||||||
transition: all 0.2s ease-in-out; /* TODO transition */
|
transition: all 0.2s ease-in-out; /* TODO transition */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_SpaceButton_newCancel .mx_SpaceButton_icon svg {
|
&.mx_SpaceButton_newCancel .mx_SpaceButton_icon::before {
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_SpaceButton_menuButton {
|
.mx_SpaceButton_menuButton {
|
||||||
width: 16px;
|
width: 20px;
|
||||||
height: 16px;
|
min-width: 20px; /* yay flex */
|
||||||
padding: var(--cpd-space-0-5x);
|
height: 20px;
|
||||||
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;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
width: inherit;
|
top: 3px;
|
||||||
height: inherit;
|
left: 2px;
|
||||||
display: block;
|
content: "";
|
||||||
color: $primary-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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,6 +341,18 @@ 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,51 @@ 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;
|
||||||
|
|
||||||
@@ -197,6 +242,20 @@ 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;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
/* mask to dither resulting combined gradient */
|
/* mask to dither resulting combined gradient */
|
||||||
url("$(res)/img/noise.png"),
|
url("$(res)/img/noise.png"),
|
||||||
/* gradient to apply different amounts of dithering to different parts of the gradient */
|
/* gradient to apply different amounts of dithering to different parts of the gradient */
|
||||||
linear-gradient(
|
linear-gradient(
|
||||||
to bottom,
|
to bottom,
|
||||||
/* 10% dithering at the top */ rgb(0, 0, 0, 0.9) 20%,
|
/* 10% dithering at the top */ rgb(0, 0, 0, 0.9) 20%,
|
||||||
/* 80% dithering at the bottom */ rgb(0, 0, 0, 0.2) 100%
|
/* 80% dithering at the bottom */ rgb(0, 0, 0, 0.2) 100%
|
||||||
|
|||||||
@@ -41,10 +41,42 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
padding: var(--cpd-space-3x);
|
padding: var(--cpd-space-3x);
|
||||||
|
|
||||||
&.mx_Toast_hasIcon {
|
&.mx_Toast_hasIcon {
|
||||||
svg {
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
mask-size: 100%;
|
||||||
|
mask-position: center;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
background-size: 100%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_Toast_icon_verification::after {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/lock-solid.svg");
|
||||||
|
background-color: $primary-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_Toast_icon_verification_warning {
|
||||||
|
/* white infill for the hollow svg mask */
|
||||||
|
&::before {
|
||||||
|
background-color: #ffffff;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/lock-solid.svg");
|
||||||
|
mask-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/error-solid.svg");
|
||||||
|
background-color: $e2e-warning-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_Toast_icon_key_storage::after {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/settings-solid.svg");
|
||||||
|
background-color: $primary-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Toast_title,
|
.mx_Toast_title,
|
||||||
|
|||||||
@@ -7,44 +7,12 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_UploadBar {
|
.mx_UploadBar {
|
||||||
/* line up with the shield area in the composer */
|
padding-left: 65px; /* line up with the shield area in the composer */
|
||||||
padding: 5px 21px 0;
|
padding-top: 5px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-template:
|
|
||||||
"icon filename cancel" auto
|
|
||||||
"progress progress progress" auto
|
|
||||||
/ min-content auto min-content;
|
|
||||||
gap: var(--cpd-space-1-5x);
|
|
||||||
|
|
||||||
& > svg {
|
|
||||||
grid-area: icon;
|
|
||||||
height: 18px;
|
|
||||||
width: 18px;
|
|
||||||
color: $muted-fg-color;
|
|
||||||
align-self: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_UploadBar_filename {
|
|
||||||
grid-area: filename;
|
|
||||||
color: $muted-fg-color;
|
|
||||||
position: relative;
|
|
||||||
font-size: $font-15px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_UploadBar_cancel {
|
|
||||||
grid-area: cancel;
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
color: $muted-fg-color;
|
|
||||||
align-self: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProgressBar {
|
.mx_ProgressBar {
|
||||||
grid-area: progress;
|
width: calc(100% - 40px); /* cheating at a right margin */
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,3 +21,39 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_UploadBar_filename {
|
||||||
|
color: $muted-fg-color;
|
||||||
|
position: relative;
|
||||||
|
padding-right: 38px; /* 32px for cancel icon, 6px for padding */
|
||||||
|
padding-left: 22px; /* 18px for icon, 4px for padding */
|
||||||
|
font-size: $font-15px;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-position: center;
|
||||||
|
background-color: $muted-fg-color;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/share.svg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_UploadBar_cancel {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
margin-right: 16px; /* align over rightmost button in composer */
|
||||||
|
margin-top: 5px;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-position: center;
|
||||||
|
background-color: $muted-fg-color;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/close.svg");
|
||||||
|
}
|
||||||
|
|||||||
@@ -119,4 +119,8 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
.mx_IconizedContextMenu_icon svg {
|
.mx_IconizedContextMenu_icon svg {
|
||||||
color: $icon-button-color;
|
color: $icon-button-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_UserMenu_iconMessage::before {
|
||||||
|
mask-image: url("$(res)/img/element-icons/feedback.svg");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,16 +11,17 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_E2EIcon.mx_CompleteSecurity_headerIcon {
|
.mx_CompleteSecurity_headerIcon {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
display: inline-block;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_E2EIcon.mx_CompleteSecurity_heroIcon {
|
.mx_CompleteSecurity_heroIcon {
|
||||||
width: 128px;
|
width: 128px;
|
||||||
height: 128px;
|
height: 128px;
|
||||||
|
position: relative;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,20 +32,27 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_ConfirmSpaceUserActionDialog_warning {
|
.mx_ConfirmSpaceUserActionDialog_warning {
|
||||||
|
position: relative;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 12px 8px;
|
padding: 12px 8px 12px 42px;
|
||||||
background-color: $header-panel-bg-color;
|
background-color: $header-panel-bg-color;
|
||||||
|
|
||||||
font-size: $font-12px;
|
font-size: $font-12px;
|
||||||
line-height: $font-15px;
|
line-height: $font-15px;
|
||||||
color: $secondary-content;
|
color: $secondary-content;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: calc(50% - 8px); /* vertical centering */
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
vertical-align: -4px;
|
background-color: $secondary-content;
|
||||||
margin-right: var(--cpd-space-1-5x);
|
mask-repeat: no-repeat;
|
||||||
color: $secondary-content;
|
mask-size: contain;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/info-solid.svg");
|
||||||
|
mask-position: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,17 +55,33 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > svg {
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
left: 16px;
|
left: 16px;
|
||||||
top: 12px;
|
top: 12px;
|
||||||
padding: var(--cpd-space-2x);
|
}
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
&::before {
|
||||||
background-color: $icon-button-color;
|
background-color: $icon-button-color;
|
||||||
color: $avatar-initial-color;
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
background: $avatar-initial-color; /* TODO */
|
||||||
|
mask-position: center;
|
||||||
|
mask-size: 24px;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_FeedbackDialog_reportBug {
|
||||||
|
&::after {
|
||||||
|
mask-image: url("$(res)/img/feather-customised/bug.svg");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_FeedbackDialog_rateApp {
|
.mx_FeedbackDialog_rateApp {
|
||||||
@@ -109,5 +125,9 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
border-color: var(--cpd-color-bg-action-primary-rest);
|
border-color: var(--cpd-color-bg-action-primary-rest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
mask-image: url("$(res)/img/element-icons/feedback.svg");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_InviteDialog_goButton {
|
.mx_InviteDialog_goButton {
|
||||||
min-width: 86px;
|
min-width: 48px;
|
||||||
margin-inline-start: 10px;
|
margin-inline-start: 10px;
|
||||||
height: 41px;
|
height: 25px;
|
||||||
line-height: $font-25px;
|
line-height: $font-25px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,6 +223,14 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
margin-inline-start: auto;
|
margin-inline-start: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_InviteDialog_userDirectoryIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/user-profile-solid.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_InviteDialog_dialPadIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/dial-pad.svg");
|
||||||
|
}
|
||||||
|
|
||||||
.mx_InviteDialog_tile {
|
.mx_InviteDialog_tile {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@@ -18,14 +18,19 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
padding-left: var(--cpd-space-1-5x);
|
padding-left: 30px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
width: 16px;
|
content: "";
|
||||||
|
position: absolute;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
color: $secondary-content;
|
width: 16px;
|
||||||
vertical-align: -2px;
|
left: 6px;
|
||||||
margin-right: var(--cpd-space-1-5x);
|
top: 8px;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-position: center;
|
||||||
|
background-color: $secondary-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_JoinRuleDropdown_knock::before {
|
&.mx_JoinRuleDropdown_knock::before {
|
||||||
@@ -34,6 +39,22 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_JoinRuleDropdown_invite::before {
|
||||||
|
box-sizing: border-box;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/lock-solid.svg");
|
||||||
|
mask-size: contain;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_JoinRuleDropdown_public::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/public.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_JoinRuleDropdown_restricted::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/group.svg");
|
||||||
|
mask-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_JoinRuleDropdown_icon {
|
.mx_JoinRuleDropdown_icon {
|
||||||
color: $secondary-content;
|
color: $secondary-content;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -25,21 +25,28 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
.mx_LeaveSpaceDialog_section_warning {
|
.mx_LeaveSpaceDialog_section_warning {
|
||||||
|
position: relative;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin: 12px 0 0;
|
margin: 12px 0 0;
|
||||||
padding: 12px 8px;
|
padding: 12px 8px 12px 42px;
|
||||||
background-color: $header-panel-bg-color;
|
background-color: $header-panel-bg-color;
|
||||||
|
|
||||||
font-size: $font-12px;
|
font-size: $font-12px;
|
||||||
line-height: $font-15px;
|
line-height: $font-15px;
|
||||||
color: $secondary-content;
|
color: $secondary-content;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: calc(50% - 8px); /* vertical centering */
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
color: $secondary-content;
|
background-color: $secondary-content;
|
||||||
vertical-align: middle;
|
mask-repeat: no-repeat;
|
||||||
margin: 0 var(--cpd-space-1x);
|
mask-size: contain;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/info-solid.svg");
|
||||||
|
mask-position: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,19 +87,25 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin: 12px 0;
|
margin: 12px 0;
|
||||||
padding: 8px;
|
padding: 8px 8px 8px 42px;
|
||||||
background-color: $header-panel-bg-color;
|
background-color: $header-panel-bg-color;
|
||||||
|
|
||||||
font-size: $font-12px;
|
font-size: $font-12px;
|
||||||
line-height: $font-15px;
|
line-height: $font-15px;
|
||||||
color: $secondary-content;
|
color: $secondary-content;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: calc(50% - 8px); /* vertical centering */
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
color: $secondary-content;
|
background-color: $secondary-content;
|
||||||
vertical-align: middle;
|
mask-repeat: no-repeat;
|
||||||
margin: 0 var(--cpd-space-1x);
|
mask-size: contain;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/info-solid.svg");
|
||||||
|
mask-position: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,46 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* ICONS */
|
||||||
|
/* ========================================================== */
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_settingsIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/settings-solid.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_voiceIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/voice-call-solid.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_securityIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/lock-solid.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_rolesIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/admin.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_notificationsIcon::before {
|
||||||
|
mask-image: url("$(res)/img/element-icons/notifications.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_bridgesIcon::before {
|
||||||
|
/* This icon is pants, please improve :) */
|
||||||
|
mask-image: url("$(res)/img/feather-customised/bridge.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_pollsIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/polls.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_warningIcon::before {
|
||||||
|
mask-image: url("$(res)/img/element-icons/room/settings/advanced.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomSettingsDialog_peopleIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/group.svg");
|
||||||
|
}
|
||||||
|
|
||||||
.mx_RoomSettingsDialog .mx_Dialog_title {
|
.mx_RoomSettingsDialog .mx_Dialog_title {
|
||||||
-ms-text-overflow: ellipsis;
|
-ms-text-overflow: ellipsis;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_AccessibleButton_kind_primary {
|
.mx_AccessibleButton_kind_primary {
|
||||||
width: calc(100% - 26px);
|
width: calc(100% - 64px);
|
||||||
margin: 0 8px;
|
margin: 0 8px;
|
||||||
padding: 15px 18px;
|
padding: 15px 18px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,3 +26,7 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_SpacePreferencesDialog_appearanceIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/visibility-on.svg");
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,4 +71,14 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_TabbedView_tabLabel {
|
||||||
|
.mx_SpaceSettingsDialog_generalIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/settings-solid.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_SpaceSettingsDialog_visibilityIcon::before {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/visibility-on.svg");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,20 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_KeyBackupFailedDialog_title {
|
.mx_KeyBackupFailedDialog_title {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 45px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
margin-right: var(--cpd-space-2x);
|
mask-image: url("@vector-im/compound-design-tokens/icons/error.svg");
|
||||||
vertical-align: -2px;
|
mask-repeat: no-repeat;
|
||||||
color: $primary-content;
|
background-color: $primary-content;
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: -6px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
font: var(--cpd-font-body-md-semibold);
|
font: var(--cpd-font-body-md-semibold);
|
||||||
border: none; /* override default <button /> styles */
|
border: none; /* override default <button /> styles */
|
||||||
word-break: keep-all; /* prevent button text in Chinese/Japanese/Korean (CJK) from being collapsed */
|
word-break: keep-all; /* prevent button text in Chinese/Japanese/Korean (CJK) from being collapsed */
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
&.mx_AccessibleButton_kind_primary_sm,
|
&.mx_AccessibleButton_kind_primary_sm,
|
||||||
&.mx_AccessibleButton_kind_danger_sm,
|
&.mx_AccessibleButton_kind_danger_sm,
|
||||||
@@ -48,13 +47,11 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
&.mx_AccessibleButton_kind_primary_sm {
|
&.mx_AccessibleButton_kind_primary_sm {
|
||||||
color: var(--cpd-color-text-on-solid-primary);
|
color: var(--cpd-color-text-on-solid-primary);
|
||||||
background-color: var(--cpd-color-bg-action-primary-rest);
|
background-color: var(--cpd-color-bg-action-primary-rest);
|
||||||
border: 1px solid var(--cpd-color-bg-action-primary-rest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_AccessibleButton_kind_danger_sm {
|
&.mx_AccessibleButton_kind_danger_sm {
|
||||||
color: var(--cpd-color-text-on-solid-primary);
|
color: var(--cpd-color-text-on-solid-primary);
|
||||||
background-color: var(--cpd-color-bg-critical-primary);
|
background-color: var(--cpd-color-bg-critical-primary);
|
||||||
border: 1px solid var(--cpd-color-bg-critical-primary);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_AccessibleButton_kind_link_sm {
|
&.mx_AccessibleButton_kind_link_sm {
|
||||||
|
|||||||
@@ -39,11 +39,17 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
top: 0.15em;
|
top: 0.15em;
|
||||||
background-color: $background;
|
background-color: $background;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
|
content: "";
|
||||||
|
mask-image: url($copy-button-url);
|
||||||
|
mask-position: center center;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-size: contain;
|
||||||
|
background-color: $message-action-bar-fg-color;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
color: $message-action-bar-fg-color;
|
|
||||||
display: block;
|
display: block;
|
||||||
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
|
|
||||||
.mx_ExternalLink_icon {
|
.mx_ExternalLink_icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/pop-out.svg");
|
||||||
|
background-color: currentColor;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-size: contain;
|
||||||
width: $font-11px;
|
width: $font-11px;
|
||||||
height: $font-11px;
|
height: $font-11px;
|
||||||
margin-left: 0.3rem;
|
margin-left: 0.3rem;
|
||||||
|
|||||||
@@ -23,12 +23,14 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: $secondary-content;
|
color: $secondary-content;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
width: 16px;
|
content: "";
|
||||||
height: 16px;
|
|
||||||
color: $secondary-content;
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
|
background-color: $secondary-content;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/visibility-on.svg");
|
||||||
|
display: inline-block;
|
||||||
|
width: 18px;
|
||||||
|
height: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,12 +47,16 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
background: $quinary-content;
|
background: $quinary-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
height: 20px;
|
content: "";
|
||||||
width: 20px;
|
width: 20px;
|
||||||
display: inline-block;
|
height: 20px;
|
||||||
vertical-align: bottom;
|
background: currentColor;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||||
|
mask-size: 100%;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
float: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,24 +181,25 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
}
|
}
|
||||||
|
|
||||||
&[aria-checked="true"] {
|
&[aria-checked="true"] {
|
||||||
span:first-child {
|
:first-child {
|
||||||
margin-left: -20px;
|
margin-left: -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
:first-child::before {
|
||||||
|
content: "";
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
color: $primary-content;
|
mask-image: url("@vector-im/compound-design-tokens/icons/check.svg");
|
||||||
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
span:last-child {
|
:last-child {
|
||||||
color: $secondary-content;
|
color: $secondary-content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
45
res/css/views/rooms/RoomListPanel/_RoomListSearch.pcss
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.mx_RoomListSearch {
|
||||||
|
/* From figma, this should be aligned with the room header */
|
||||||
|
flex: 0 0 64px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-bottom: var(--cpd-border-width-1) solid var(--cpd-color-bg-subtle-primary);
|
||||||
|
padding: 0 var(--cpd-space-3x);
|
||||||
|
|
||||||
|
.mx_RoomListSearch_search {
|
||||||
|
/* The search button should take all the remaining space */
|
||||||
|
flex: 1;
|
||||||
|
font: var(--cpd-font-body-md-regular);
|
||||||
|
color: var(--cpd-color-text-secondary);
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: var(--cpd-color-icon-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shrink and truncate the search text */
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
.mx_RoomListSearch_search_text {
|
||||||
|
min-width: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,12 +65,7 @@
|
|||||||
margin: 12px;
|
margin: 12px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
max-height: 35vh;
|
||||||
|
|
||||||
@container roomview (height >= 0px) {
|
|
||||||
.mx_Autocomplete_Completion_container_pill {
|
|
||||||
max-height: 40cqh;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Autocomplete_Completion_container_truncate {
|
.mx_Autocomplete_Completion_container_truncate {
|
||||||
|
|||||||
79
res/css/views/rooms/_DecryptionFailureBar.pcss
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2024 New Vector Ltd.
|
||||||
|
Copyright 2022 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_DecryptionFailureBar {
|
||||||
|
--gap-row: $spacing-8;
|
||||||
|
--gap-column: $spacing-12;
|
||||||
|
--gap: var(--gap-row) var(--gap-column);
|
||||||
|
--size-icon: 24px;
|
||||||
|
|
||||||
|
background-color: $system;
|
||||||
|
padding: $spacing-12;
|
||||||
|
margin-inline: $spacing-16;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&.mx_DecryptionFailureBar--withEnd {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
row-gap: calc(var(--gap-row) + $spacing-4); /* Increase spacing between the message and the buttons */
|
||||||
|
|
||||||
|
.mx_DecryptionFailureBar_end {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap; /* Let the buttons wrapped on a narrow column */
|
||||||
|
gap: var(--buttons-dialog-gap-row) var(--buttons-dialog-gap-column);
|
||||||
|
margin-inline-start: calc(var(--size-icon) + var(--gap-column)); /* Align the button(s) and the message */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DecryptionFailureBar_start {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--gap);
|
||||||
|
grid-template-areas:
|
||||||
|
"status headline"
|
||||||
|
". message";
|
||||||
|
grid-template-columns: var(--size-icon) auto;
|
||||||
|
|
||||||
|
.mx_DecryptionFailureBar_start_status {
|
||||||
|
grid-area: status;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--gap);
|
||||||
|
|
||||||
|
.mx_Spinner {
|
||||||
|
height: unset; /* Unset height: 100% */
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DecryptionFailureBar_start_status_icon {
|
||||||
|
min-width: var(--size-icon);
|
||||||
|
height: var(--size-icon);
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/error-solid.svg");
|
||||||
|
background-color: $e2e-warning-color;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-position: center;
|
||||||
|
mask-size: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DecryptionFailureBar_start_headline {
|
||||||
|
grid-area: headline;
|
||||||
|
|
||||||
|
font-weight: var(--cpd-font-weight-semibold);
|
||||||
|
font-size: $font-16px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_DecryptionFailureBar_start_message {
|
||||||
|
grid-area: message;
|
||||||
|
|
||||||
|
color: $secondary-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -833,6 +833,7 @@ $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;
|
||||||
@@ -843,13 +844,17 @@ $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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_EventTile_e2eIcon_normal::after {
|
&.mx_EventTile_e2eIcon_normal::after {
|
||||||
mask-image: url("@vector-im/compound-design-tokens/icons/info.svg");
|
mask-image: url("@vector-im/compound-design-tokens/icons/lock-solid.svg");
|
||||||
background-color: var(--cpd-color-icon-tertiary); /* grey */
|
background-color: var(--cpd-color-icon-tertiary); /* grey */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,21 +918,30 @@ $left-gutter: 64px;
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: $spacing-8;
|
top: $spacing-8;
|
||||||
right: $spacing-8;
|
right: $spacing-8;
|
||||||
width: 16px;
|
width: 19px;
|
||||||
height: 16px;
|
height: 19px;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
background-color: $message-action-bar-fg-color;
|
||||||
|
|
||||||
&.mx_EventTile_buttonBottom {
|
&.mx_EventTile_buttonBottom {
|
||||||
top: 33px;
|
top: 33px;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
&.mx_EventTile_collapseButton,
|
||||||
width: inherit;
|
&.mx_EventTile_expandButton {
|
||||||
height: inherit;
|
mask-size: 75%;
|
||||||
display: block;
|
|
||||||
color: $message-action-bar-fg-color;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_copyButton {
|
||||||
|
height: 17px;
|
||||||
|
mask-image: url($copy-button-url);
|
||||||
|
mask-position: center center;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-size: contain;
|
||||||
|
right: 9px;
|
||||||
|
width: 17px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -948,6 +962,20 @@ $left-gutter: 64px;
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_collapseButton,
|
||||||
|
.mx_EventTile_expandButton {
|
||||||
|
mask-position: center;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_collapseButton {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/collapse.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_EventTile_expandButton {
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/expand.svg");
|
||||||
|
}
|
||||||
|
|
||||||
.mx_EventTile_tileError {
|
.mx_EventTile_tileError {
|
||||||
color: red;
|
color: red;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -29,11 +29,16 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
|
|
||||||
.mx_ReplyPreview_header_cancel svg {
|
.mx_ReplyPreview_header_cancel {
|
||||||
color: $primary-content;
|
background-color: $primary-content;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/close.svg");
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-position: center;
|
||||||
|
mask-size: contain;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
flex-shrink: 0;
|
min-width: 20px;
|
||||||
|
min-height: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,33 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
color: $secondary-content;
|
color: $secondary-content;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
height: 1.2em;
|
||||||
|
mask-position: center;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
background-color: $tertiary-content;
|
||||||
|
vertical-align: text-bottom;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
vertical-align: -2px;
|
}
|
||||||
color: $tertiary-content;
|
|
||||||
|
&.mx_RoomInfoLine_public::before {
|
||||||
|
width: 12px;
|
||||||
|
mask-size: 12px;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/public.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_RoomInfoLine_private::before {
|
||||||
|
width: 10px;
|
||||||
|
mask-size: 10px;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/lock-solid.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mx_RoomInfoLine_video::before {
|
||||||
|
width: 16px;
|
||||||
|
mask-size: 16px;
|
||||||
|
mask-image: url("@vector-im/compound-design-tokens/icons/video-call-solid.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomInfoLine_members {
|
.mx_RoomInfoLine_members {
|
||||||
|
|||||||
@@ -22,13 +22,20 @@ 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);
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
height: 1em;
|
content: "";
|
||||||
width: 1em;
|
position: absolute;
|
||||||
margin-right: $spacing-8;
|
height: $font-24px;
|
||||||
color: $secondary-content;
|
width: 20px;
|
||||||
vertical-align: -2px;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,19 +63,25 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.mx_RoomPreviewCard_video {
|
.mx_RoomPreviewCard_video {
|
||||||
width: 22px;
|
width: 50px;
|
||||||
height: 22px;
|
height: 50px;
|
||||||
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);
|
||||||
|
|
||||||
svg {
|
&::before {
|
||||||
width: inherit;
|
content: "";
|
||||||
height: inherit;
|
background-color: $button-primary-fg-color;
|
||||||
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,18 @@ 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;
|
||||||
|
|||||||
21
res/css/views/spaces/_SpacePublicShare.pcss
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
res/img/element-icons/brands/apple.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.9803 1.2796C17.0771 2.54383 16.6773 3.79601 15.8657 4.77022C15.0784 5.74949 13.8854 6.31354 12.629 6.3006C12.5491 5.07276 12.9605 3.86352 13.7727 2.93921C14.5952 2.00238 15.7404 1.40982 16.9803 1.2796ZM20.9539 8.70795C19.5086 9.59652 18.6192 11.1635 18.5974 12.86C18.5994 14.7794 19.7489 16.5115 21.5166 17.2592C21.1766 18.3636 20.6642 19.4073 19.9982 20.3517C19.1038 21.6896 18.1661 22.9967 16.6777 23.0208C15.9698 23.0372 15.492 22.8336 14.9941 22.6215C14.4747 22.4003 13.9335 22.1697 13.0867 22.1697C12.1885 22.1697 11.6231 22.4077 11.0778 22.6372C10.6065 22.8355 10.1503 23.0275 9.50727 23.0542C8.08982 23.1067 7.00654 21.6263 6.07964 20.3009C4.22703 17.5943 2.78444 12.6733 4.71844 9.32483C5.62662 7.69286 7.32468 6.65727 9.19136 6.59696C9.99528 6.58042 10.7667 6.89028 11.443 7.16193C11.9602 7.36969 12.4219 7.5551 12.7999 7.5551C13.1321 7.5551 13.5809 7.37701 14.1038 7.16946C14.9276 6.84251 15.9356 6.44246 16.9628 6.55027C18.5589 6.60021 20.038 7.39984 20.9539 8.70795Z" fill="#17191C"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
15
res/img/element-icons/brands/linux.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_4244_203)">
|
||||||
|
<path d="M11.0054 17.2033C10.7192 17.3348 10.4074 17.405 10.0911 17.4096C9.62287 17.4048 9.1673 17.2609 8.78524 16.9971C8.65787 17.3144 8.45841 17.5995 8.20182 17.831C7.94524 18.0626 7.63819 18.2344 7.30371 18.3337C7.34816 18.3337 7.39049 18.3337 7.43494 18.3337H12.4213C12.1196 18.2476 11.8387 18.103 11.5954 17.9088C11.3522 17.7147 11.1515 17.4747 11.0054 17.2033Z" fill="black"/>
|
||||||
|
<path d="M5.59233 13.8942C5.61193 13.8889 5.63053 13.8805 5.64735 13.8694C5.6791 13.5971 5.71508 13.3352 5.7553 13.0856C5.74691 12.9449 5.77002 12.8041 5.82302 12.6731C6.11298 11.0868 6.51722 9.97294 7.07596 9.29637C7.09365 9.27503 7.1193 9.26142 7.14728 9.25851C7.17526 9.25561 7.20328 9.26367 7.22518 9.2809C7.24707 9.29813 7.26104 9.32313 7.26401 9.35041C7.26699 9.37768 7.25873 9.40498 7.24105 9.42631C7.18391 9.49645 7.12676 9.57277 7.07173 9.65322C6.64844 10.272 6.31404 11.2126 6.07277 12.477H6.09816C6.14375 12.4702 6.19014 12.4702 6.23573 12.477C6.40082 12.5121 6.65902 12.6462 7.05692 13.036C7.10771 10.7691 8.44108 8.94158 10.0919 8.94158C11.548 8.94158 12.765 10.371 13.0549 12.2729C13.1926 12.0053 13.4153 11.7882 13.6899 11.654C13.7577 11.6293 13.8293 11.6161 13.9016 11.6149C13.7518 10.9261 13.485 10.2666 13.1121 9.66353C13.0571 9.58308 13.002 9.50676 12.9449 9.43663C12.9357 9.42642 12.9287 9.41445 12.9244 9.40149C12.9201 9.38852 12.9186 9.37484 12.92 9.36128C12.9214 9.34774 12.9256 9.33461 12.9325 9.32273C12.9393 9.31085 12.9486 9.30047 12.9597 9.29224C12.9703 9.28351 12.9826 9.27695 12.9959 9.27294C13.0091 9.26893 13.0232 9.26756 13.0369 9.26891C13.0507 9.27025 13.0641 9.2743 13.0763 9.28078C13.0885 9.28727 13.0992 9.29608 13.1079 9.30668C13.5312 9.82648 13.8825 10.6041 14.145 11.6582C14.7101 11.8644 14.7248 12.7927 14.7375 13.5476C14.7375 13.9065 14.7375 14.2779 14.8243 14.3727C14.9111 14.4676 15.0952 14.447 15.3535 14.3397C15.3831 14.0118 15.3978 13.7209 15.4063 13.4755C15.4063 13.0856 15.4063 12.836 15.4063 12.836V12.574C15.4063 10.5113 12.6846 6.94487 12.6846 6.94487L12.3692 4.26334C12.3692 1.80251 10.0919 1.8252 10.0919 1.8252C10.0919 1.8252 7.80615 1.80251 7.80615 4.25302L7.50138 6.94487C7.50138 6.94487 4.77961 10.5092 4.77961 12.574V12.8319C4.77961 12.8319 4.76902 13.0814 4.77961 13.4713C4.77961 13.5311 4.77961 13.5951 4.77961 13.6611C5.1246 13.7889 5.47804 13.923 5.59233 13.8942ZM10.0813 5.21837C10.7163 5.27613 11.7279 5.42465 11.7745 5.72993C11.8084 5.96507 11.4168 6.41475 11.3385 6.50138C11.1755 6.68084 10.6083 7.26872 10.0962 7.26872C9.58397 7.26872 9.01676 6.68084 8.85591 6.50138C8.7776 6.41475 8.38606 5.96507 8.4178 5.72993C8.4559 5.41846 9.47815 5.27613 10.0813 5.21837Z" fill="black"/>
|
||||||
|
<path d="M10.0925 7.0621C10.3698 7.0621 10.7952 6.78776 11.174 6.3649C11.464 6.04518 11.5698 5.81003 11.5613 5.7564C11.5084 5.6512 10.8164 5.49237 10.0798 5.42224C9.36657 5.49237 8.67449 5.6512 8.62158 5.76052C8.69778 5.98983 8.83166 6.19689 9.01101 6.36284C9.39197 6.78776 9.81526 7.0621 10.0925 7.0621Z" fill="black"/>
|
||||||
|
<path d="M10.6623 15.9489C10.4189 13.7769 10.6432 13.3273 10.8337 13.1788C10.8804 13.1432 10.9358 13.1201 10.9945 13.1117C11.0531 13.1035 11.113 13.1102 11.1681 13.1313C11.3598 13.2237 11.5271 13.3577 11.657 13.5232C11.8962 13.7769 12.0634 13.9358 12.2179 13.8491C12.328 13.7852 12.4846 13.4366 12.6412 13.1169C12.7216 12.9456 12.8042 12.7621 12.8952 12.5868C12.6835 10.6457 11.5195 9.14819 10.0993 9.14819C8.53949 9.14819 7.27173 10.9531 7.27173 13.1705C7.27173 13.1973 7.27173 13.2241 7.27173 13.2509C7.52995 13.5149 7.83895 13.8698 8.21567 14.3338C8.36367 14.5155 8.4994 14.7064 8.62204 14.9052C8.79699 15.1841 8.909 15.4961 8.9506 15.8205C8.9922 16.1449 8.96245 16.4741 8.86331 16.7864C9.21862 17.0463 9.64882 17.1907 10.093 17.199C10.3777 17.1979 10.659 17.1382 10.9184 17.0236C10.862 16.9 10.8173 16.7716 10.7851 16.64C10.7302 16.4122 10.6892 16.1815 10.6623 15.9489Z" fill="black"/>
|
||||||
|
<path d="M8.04303 14.459C7.74673 14.0918 7.49487 13.8009 7.279 13.5658L7.17105 13.4503L7.061 13.3348C6.5721 12.8397 6.31389 12.7037 6.17843 12.681C6.15951 12.678 6.14023 12.678 6.12129 12.681C6.10076 12.6833 6.08122 12.6909 6.06454 12.7028C6.04786 12.7147 6.03461 12.7307 6.02605 12.7489C6.02565 12.7538 6.02565 12.7586 6.02605 12.7634C5.98416 12.8712 5.96753 12.9869 5.97738 13.1017C5.97738 13.1595 5.97738 13.2173 5.97738 13.2749C5.97738 13.3327 5.97738 13.341 5.97738 13.374C6.00594 13.5827 5.96198 13.7947 5.8525 13.9763C5.83155 13.9994 5.80732 14.0196 5.78055 14.0362L5.7361 14.0629C5.70773 14.0774 5.67795 14.0892 5.6472 14.098H5.62393C5.44826 14.1289 5.16254 14.0279 4.80063 13.8917L4.6948 13.8505C4.24188 13.6752 3.71276 13.473 3.32545 13.473C3.23797 13.4644 3.14967 13.4777 3.06893 13.5116C2.98819 13.5455 2.91767 13.599 2.86406 13.6669C2.58046 14.0794 3.2154 14.7271 3.72758 15.2511C4.04294 15.5749 4.29056 15.8286 4.31808 16.0184C4.36675 16.3691 3.99002 16.5031 3.65774 16.6228C3.48628 16.6669 3.32623 16.7457 3.18788 16.8538C3.13709 16.9116 3.1392 16.9508 3.14979 16.9797C3.19635 17.1384 3.57308 17.4871 5.56466 18.0502C5.78512 18.1124 6.00914 18.1621 6.23558 18.1987C6.64453 18.2591 7.06268 18.2065 7.44245 18.0468C7.82223 17.8871 8.14838 17.6267 8.38379 17.2952C8.47591 17.159 8.55187 17.0129 8.61025 16.86L8.65257 16.7589C8.65257 16.7239 8.67163 16.6847 8.68221 16.6496C8.75827 16.3728 8.77591 16.0838 8.73407 15.8002C8.69223 15.5165 8.59179 15.2441 8.43881 14.9994C8.31764 14.812 8.18549 14.6316 8.04303 14.459Z" fill="black"/>
|
||||||
|
<path d="M16.0589 14.3171C15.8816 14.3336 15.71 14.3863 15.5552 14.4717L15.3245 14.5687C15.0704 14.6635 14.8164 14.7089 14.6513 14.4903C14.6122 14.4329 14.5856 14.3683 14.573 14.3006C14.5437 14.1377 14.5282 13.9728 14.5265 13.8075C14.5265 13.723 14.5265 13.6342 14.5265 13.5393C14.5265 12.9391 14.5054 12.2171 14.2154 11.9346C14.1785 11.8974 14.1346 11.8673 14.0863 11.8459C14.0596 11.8345 14.0321 11.8255 14.0037 11.8191H13.972C13.9001 11.8109 13.8272 11.8208 13.7603 11.8479C13.5106 11.947 13.2926 12.2605 13.1022 12.6277L13.0112 12.8071C12.9772 12.8772 12.9455 12.9453 12.9138 13.0133C12.882 13.0814 12.8545 13.1392 12.827 13.2011C12.6408 13.6136 12.4947 13.9292 12.3254 14.0262C12.0122 14.2056 11.7391 13.9168 11.5 13.6611C11.3921 13.5236 11.2558 13.4098 11.1 13.3269C11.0796 13.3194 11.0582 13.3152 11.0365 13.3145C11.0108 13.3139 10.9859 13.3228 10.9666 13.3393C10.8354 13.4424 10.647 13.9148 10.8735 15.926C10.8978 16.148 10.936 16.3684 10.9878 16.586C11.0166 16.7008 11.0548 16.8133 11.1021 16.9222C11.1169 16.9532 11.1317 16.9841 11.1486 17.015C11.1656 17.0459 11.1762 17.0769 11.1931 17.1079C11.3664 17.4217 11.6184 17.6878 11.9256 17.8813C12.2328 18.0746 12.5853 18.1891 12.9501 18.214C13.3149 18.239 13.6804 18.1735 14.0122 18.0237C14.3441 17.8739 14.6317 17.6448 14.8482 17.3574C14.9843 17.1771 15.1093 16.989 15.2228 16.7943C16.2387 15.0307 16.2578 14.5254 16.1795 14.3809C16.1676 14.3603 16.15 14.3434 16.1286 14.332C16.1073 14.3208 16.0831 14.3155 16.0589 14.3171Z" fill="black"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_4244_203">
|
||||||
|
<rect width="14.4446" height="16.5081" fill="white" transform="translate(2.63892 1.8252)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.0 KiB |
6
res/img/element-icons/brands/microsoft.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="10.4908" y="2" width="7.50926" height="7.50926" fill="#1B1D22"/>
|
||||||
|
<rect x="2" y="10.4904" width="7.50926" height="7.50926" fill="#1B1D22"/>
|
||||||
|
<rect x="2" y="2" width="7.50926" height="7.50926" fill="#1B1D22"/>
|
||||||
|
<rect x="10.4908" y="10.4904" width="7.50926" height="7.50926" fill="#1B1D22"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 399 B |
@@ -1,3 +1,3 @@
|
|||||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M17 13.89C17 15.0256 16.1603 16 14.9272 16H3.08038C1.83972 16 1 15.0256 1 13.89C1 13.5371 1.09078 13.1841 1.27234 12.8542L7.20331 2.08951C7.60426 1.36061 8.30024 1 9.00378 1C9.70733 1 10.3957 1.34527 10.7967 2.08951L16.7277 12.8542C16.9092 13.1841 17 13.5371 17 13.89ZM8.92011 5.00263C8.35011 5.04263 7.93011 5.54264 7.98011 6.11264L8.28011 9.85C8.31011 10.2 8.58011 10.47 8.93011 10.5H8.99011C9.36011 10.5 9.67011 10.22 9.70011 9.85L10.0401 6.11264V5.95264C9.98011 5.38264 9.48011 4.96263 8.92011 5.00263ZM10 12.5C10 13.0523 9.55229 13.5 9 13.5C8.44772 13.5 8 13.0523 8 12.5C8 11.9477 8.44772 11.5 9 11.5C9.55229 11.5 10 11.9477 10 12.5Z" fill="currentColor"/>
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M17 13.89C17 15.0256 16.1603 16 14.9272 16H3.08038C1.83972 16 1 15.0256 1 13.89C1 13.5371 1.09078 13.1841 1.27234 12.8542L7.20331 2.08951C7.60426 1.36061 8.30024 1 9.00378 1C9.70733 1 10.3957 1.34527 10.7967 2.08951L16.7277 12.8542C16.9092 13.1841 17 13.5371 17 13.89ZM8.92011 5.00263C8.35011 5.04263 7.93011 5.54264 7.98011 6.11264L8.28011 9.85C8.31011 10.2 8.58011 10.47 8.93011 10.5H8.99011C9.36011 10.5 9.67011 10.22 9.70011 9.85L10.0401 6.11264V5.95264C9.98011 5.38264 9.48011 4.96263 8.92011 5.00263ZM10 12.5C10 13.0523 9.55229 13.5 9 13.5C8.44772 13.5 8 13.0523 8 12.5C8 11.9477 8.44772 11.5 9 11.5C9.55229 11.5 10 11.9477 10 12.5Z" fill="black"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 814 B After Width: | Height: | Size: 807 B |
@@ -1,3 +1,3 @@
|
|||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C9.23858 2 7 4.23858 7 7L17 7C17 4.23858 14.7614 2 12 2ZM2.29289 7.70711C1.90237 7.31658 1.90237 6.68342 2.29289 6.29289C2.68342 5.90237 3.31658 5.90237 3.70711 6.29289L6.41421 9H17.5858L20.2929 6.29289C20.6834 5.90237 21.3166 5.90237 21.7071 6.29289C22.0976 6.68342 22.0976 7.31658 21.7071 7.70711L19 10.4142V13H22C22.5523 13 23 13.4477 23 14C23 14.5523 22.5523 15 22 15H19C19 15.7795 18.8726 16.5292 18.6375 17.2295C18.6614 17.2493 18.6847 17.2705 18.7071 17.2929L21.7071 20.2929C22.0976 20.6834 22.0976 21.3166 21.7071 21.7071C21.3166 22.0976 20.6834 22.0976 20.2929 21.7071L17.6791 19.0933C16.5924 20.5983 14.9222 21.6542 13 21.9291L13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12V21.9291C9.07785 21.6542 7.40759 20.5983 6.32091 19.0933L3.70711 21.7071C3.31658 22.0976 2.68342 22.0976 2.29289 21.7071C1.90237 21.3166 1.90237 20.6834 2.29289 20.2929L5.29289 17.2929C5.31533 17.2705 5.33857 17.2493 5.36252 17.2295C5.1274 16.5292 5 15.7795 5 15H2C1.44772 15 1 14.5523 1 14C1 13.4477 1.44772 13 2 13H5V10.4142L2.29289 7.70711Z" fill="currentColor"/>
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C9.23858 2 7 4.23858 7 7L17 7C17 4.23858 14.7614 2 12 2ZM2.29289 7.70711C1.90237 7.31658 1.90237 6.68342 2.29289 6.29289C2.68342 5.90237 3.31658 5.90237 3.70711 6.29289L6.41421 9H17.5858L20.2929 6.29289C20.6834 5.90237 21.3166 5.90237 21.7071 6.29289C22.0976 6.68342 22.0976 7.31658 21.7071 7.70711L19 10.4142V13H22C22.5523 13 23 13.4477 23 14C23 14.5523 22.5523 15 22 15H19C19 15.7795 18.8726 16.5292 18.6375 17.2295C18.6614 17.2493 18.6847 17.2705 18.7071 17.2929L21.7071 20.2929C22.0976 20.6834 22.0976 21.3166 21.7071 21.7071C21.3166 22.0976 20.6834 22.0976 20.2929 21.7071L17.6791 19.0933C16.5924 20.5983 14.9222 21.6542 13 21.9291L13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12V21.9291C9.07785 21.6542 7.40759 20.5983 6.32091 19.0933L3.70711 21.7071C3.31658 22.0976 2.68342 22.0976 2.29289 21.7071C1.90237 21.3166 1.90237 20.6834 2.29289 20.2929L5.29289 17.2929C5.31533 17.2705 5.33857 17.2493 5.36252 17.2295C5.1274 16.5292 5 15.7795 5 15H2C1.44772 15 1 14.5523 1 14C1 13.4477 1.44772 13 2 13H5V10.4142L2.29289 7.70711Z" fill="#FF5B55"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -241,6 +241,8 @@ $event-highlight-bg-color: $yellow-background;
|
|||||||
/* event timestamp */
|
/* event timestamp */
|
||||||
$event-timestamp-color: #acacac;
|
$event-timestamp-color: #acacac;
|
||||||
|
|
||||||
|
$copy-button-url: "@vector-im/compound-design-tokens/icons/copy.svg";
|
||||||
|
|
||||||
/* e2e */
|
/* e2e */
|
||||||
$e2e-verified-color: #0dbd8b;
|
$e2e-verified-color: #0dbd8b;
|
||||||
$e2e-warning-color: #ff5b55;
|
$e2e-warning-color: #ff5b55;
|
||||||
|
|||||||
@@ -347,6 +347,11 @@ $focus-brightness: 105%;
|
|||||||
|
|
||||||
/* ******************** */
|
/* ******************** */
|
||||||
|
|
||||||
|
/* Icon URLs */
|
||||||
|
/* ******************** */
|
||||||
|
$copy-button-url: "@vector-im/compound-design-tokens/icons/copy.svg";
|
||||||
|
/* ******************** */
|
||||||
|
|
||||||
/* Location sharing */
|
/* Location sharing */
|
||||||
/* ******************** */
|
/* ******************** */
|
||||||
$location-marker-color: var(--cpd-color-icon-on-solid-primary);
|
$location-marker-color: var(--cpd-color-icon-on-solid-primary);
|
||||||
|
|||||||
@@ -751,38 +751,39 @@ export async function hydrateSession(credentials: IMatrixClientCreds): Promise<M
|
|||||||
* When we have a authenticated via OIDC-native flow and have a refresh token
|
* When we have a authenticated via OIDC-native flow and have a refresh token
|
||||||
* try to create a token refresher.
|
* try to create a token refresher.
|
||||||
* @param credentials from current session
|
* @param credentials from current session
|
||||||
* @param clientId OIDC client ID
|
* @returns Promise that resolves to a TokenRefresher, or undefined
|
||||||
* @throws If credentials.refreshToken or credentials.deviceId is falsy, or if no token issuer is stored
|
|
||||||
* @returns Promise that resolves to a TokenRefresher
|
|
||||||
*/
|
*/
|
||||||
async function createOidcTokenRefresher(
|
async function createOidcTokenRefresher(credentials: IMatrixClientCreds): Promise<OidcTokenRefresher | undefined> {
|
||||||
credentials: IMatrixClientCreds,
|
|
||||||
clientId: string,
|
|
||||||
): Promise<OidcTokenRefresher> {
|
|
||||||
if (!credentials.refreshToken) {
|
if (!credentials.refreshToken) {
|
||||||
throw new Error("A refresh token must be supplied in order to create an OIDC token refresher.");
|
return;
|
||||||
}
|
}
|
||||||
// stored token issuer indicates we authenticated via OIDC-native flow
|
// stored token issuer indicates we authenticated via OIDC-native flow
|
||||||
const tokenIssuer = getStoredOidcTokenIssuer();
|
const tokenIssuer = getStoredOidcTokenIssuer();
|
||||||
if (!tokenIssuer) {
|
if (!tokenIssuer) {
|
||||||
throw new Error("Cannot create an OIDC token refresher as no stored OIDC token issuer was found.");
|
return;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
const idTokenClaims = getStoredOidcIdTokenClaims();
|
const clientId = getStoredOidcClientId();
|
||||||
const redirectUri = PlatformPeg.get()!.getOidcCallbackUrl().href;
|
const idTokenClaims = getStoredOidcIdTokenClaims();
|
||||||
const deviceId = credentials.deviceId;
|
const redirectUri = PlatformPeg.get()!.getOidcCallbackUrl().href;
|
||||||
if (!deviceId) {
|
const deviceId = credentials.deviceId;
|
||||||
throw new Error("Expected deviceId in user credentials.");
|
if (!deviceId) {
|
||||||
|
throw new Error("Expected deviceId in user credentials.");
|
||||||
|
}
|
||||||
|
const tokenRefresher = new TokenRefresher(
|
||||||
|
tokenIssuer,
|
||||||
|
clientId,
|
||||||
|
redirectUri,
|
||||||
|
deviceId,
|
||||||
|
idTokenClaims!,
|
||||||
|
credentials.userId,
|
||||||
|
);
|
||||||
|
// wait for the OIDC client to initialise
|
||||||
|
await tokenRefresher.oidcClientReady;
|
||||||
|
return tokenRefresher;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("Failed to initialise OIDC token refresher", error);
|
||||||
}
|
}
|
||||||
const tokenRefresher = new TokenRefresher(
|
|
||||||
tokenIssuer,
|
|
||||||
clientId,
|
|
||||||
redirectUri,
|
|
||||||
deviceId,
|
|
||||||
idTokenClaims!,
|
|
||||||
credentials.userId,
|
|
||||||
);
|
|
||||||
return tokenRefresher;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -834,17 +835,7 @@ async function doSetLoggedIn(
|
|||||||
await abortLogin();
|
await abortLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
let storedClientid;
|
const tokenRefresher = await createOidcTokenRefresher(credentials);
|
||||||
try {
|
|
||||||
storedClientid = getStoredOidcClientId();
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
let tokenRefresher;
|
|
||||||
if (credentials.refreshToken && storedClientid) {
|
|
||||||
tokenRefresher = await createOidcTokenRefresher(credentials, storedClientid);
|
|
||||||
} else {
|
|
||||||
logger.debug("No refresh token was supplied: access token will not be refreshed");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the session lock just before creating the new client
|
// check the session lock just before creating the new client
|
||||||
checkSessionLock();
|
checkSessionLock();
|
||||||
|
|||||||
@@ -13,16 +13,27 @@ import {
|
|||||||
PushRuleActionName,
|
PushRuleActionName,
|
||||||
PushRuleKind,
|
PushRuleKind,
|
||||||
TweakName,
|
TweakName,
|
||||||
|
EventStatus,
|
||||||
} from "matrix-js-sdk/src/matrix";
|
} from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import type { IPushRule, Room, MatrixClient } from "matrix-js-sdk/src/matrix";
|
import type { IPushRule, Room, MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
import { NotificationLevel } from "./stores/notifications/NotificationLevel";
|
import { NotificationLevel } from "./stores/notifications/NotificationLevel";
|
||||||
import { getUnsentMessages } from "./components/structures/RoomStatusBar";
|
|
||||||
import { doesRoomHaveUnreadMessages, doesRoomOrThreadHaveUnreadMessages } from "./Unread";
|
import { doesRoomHaveUnreadMessages, doesRoomOrThreadHaveUnreadMessages } from "./Unread";
|
||||||
import { EffectiveMembership, getEffectiveMembership, isKnockDenied } from "./utils/membership";
|
import { EffectiveMembership, getEffectiveMembership, isKnockDenied } from "./utils/membership";
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import { getMarkedUnreadState } from "./utils/notifications";
|
import { getMarkedUnreadState } from "./utils/notifications";
|
||||||
|
|
||||||
|
export function getUnsentMessages(room: Room, threadId?: string): MatrixEvent[] {
|
||||||
|
if (!room) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return room.getPendingEvents().filter(function (ev) {
|
||||||
|
const isNotSent = ev.status === EventStatus.NOT_SENT;
|
||||||
|
const belongsToTheThread = threadId === ev.threadRootId;
|
||||||
|
return isNotSent && (!threadId || belongsToTheThread);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export enum RoomNotifState {
|
export enum RoomNotifState {
|
||||||
AllMessagesLoud = "all_messages_loud",
|
AllMessagesLoud = "all_messages_loud",
|
||||||
AllMessages = "all_messages",
|
AllMessages = "all_messages",
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const landmarkToDomElementMap: Record<Landmark, () => HTMLElement | null | undef
|
|||||||
|
|
||||||
[Landmark.ROOM_SEARCH]: () =>
|
[Landmark.ROOM_SEARCH]: () =>
|
||||||
SettingsStore.getValue("feature_new_room_list")
|
SettingsStore.getValue("feature_new_room_list")
|
||||||
? document.querySelector<HTMLElement>("#room-list-search-button")
|
? document.querySelector<HTMLElement>(".mx_RoomListSearch_search")
|
||||||
: document.querySelector<HTMLElement>(".mx_RoomSearch"),
|
: document.querySelector<HTMLElement>(".mx_RoomSearch"),
|
||||||
[Landmark.ROOM_LIST]: () =>
|
[Landmark.ROOM_LIST]: () =>
|
||||||
SettingsStore.getValue("feature_new_room_list")
|
SettingsStore.getValue("feature_new_room_list")
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import React, { type JSX, type ReactNode } from "react";
|
|||||||
import { Text, Heading, Button, Separator } from "@vector-im/compound-web";
|
import { Text, Heading, Button, Separator } from "@vector-im/compound-web";
|
||||||
import PopOutIcon from "@vector-im/compound-design-tokens/assets/web/icons/pop-out";
|
import PopOutIcon from "@vector-im/compound-design-tokens/assets/web/icons/pop-out";
|
||||||
import { Flex } from "@element-hq/web-shared-components";
|
import { Flex } from "@element-hq/web-shared-components";
|
||||||
import { LinuxIcon, MacIcon, WindowsIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
|
||||||
|
|
||||||
import SdkConfig from "../../SdkConfig";
|
import SdkConfig from "../../SdkConfig";
|
||||||
import { _t } from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
|
import { Icon as AppleIcon } from "../../../res/img/element-icons/brands/apple.svg";
|
||||||
|
import { Icon as MicrosoftIcon } from "../../../res/img/element-icons/brands/microsoft.svg";
|
||||||
|
import { Icon as LinuxIcon } from "../../../res/img/element-icons/brands/linux.svg";
|
||||||
|
|
||||||
// directly import the style here as this layer does not support rethemedex at this time so no matrix-react-sdk
|
// directly import the style here as this layer does not support rethemedex at this time so no matrix-react-sdk
|
||||||
// PostCSS variables will be accessible.
|
// PostCSS variables will be accessible.
|
||||||
@@ -84,17 +86,17 @@ const DesktopAppLinks: React.FC<{
|
|||||||
return (
|
return (
|
||||||
<Flex gap="var(--cpd-space-4x)" className="mx_ErrorView_flexContainer">
|
<Flex gap="var(--cpd-space-4x)" className="mx_ErrorView_flexContainer">
|
||||||
{macOsUrl && (
|
{macOsUrl && (
|
||||||
<Button as="a" href={macOsUrl} kind="secondary" Icon={MacIcon}>
|
<Button as="a" href={macOsUrl} kind="secondary" Icon={AppleIcon}>
|
||||||
{_t("incompatible_browser|macos")}
|
{_t("incompatible_browser|macos")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{win64Url && (
|
{win64Url && (
|
||||||
<Button as="a" href={win64Url} kind="secondary" Icon={WindowsIcon}>
|
<Button as="a" href={win64Url} kind="secondary" Icon={MicrosoftIcon}>
|
||||||
{_t("incompatible_browser|windows_64bit")}
|
{_t("incompatible_browser|windows_64bit")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{win64ArmUrl && (
|
{win64ArmUrl && (
|
||||||
<Button as="a" href={win64ArmUrl} kind="secondary" Icon={WindowsIcon}>
|
<Button as="a" href={win64ArmUrl} kind="secondary" Icon={MicrosoftIcon}>
|
||||||
{_t("incompatible_browser|windows_arm_64bit")}
|
{_t("incompatible_browser|windows_arm_64bit")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { type JSX, useEffect, useState } from "react";
|
import React, { type JSX, useEffect, useState } from "react";
|
||||||
import { ErrorIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
|
||||||
|
|
||||||
import dis from "../../../../dispatcher/dispatcher";
|
import dis from "../../../../dispatcher/dispatcher";
|
||||||
import { _t } from "../../../../languageHandler";
|
import { _t } from "../../../../languageHandler";
|
||||||
@@ -61,7 +60,6 @@ export default function NewRecoveryMethodDialog({ onFinished }: NewRecoveryMetho
|
|||||||
onFinished={onFinished}
|
onFinished={onFinished}
|
||||||
title={
|
title={
|
||||||
<span className="mx_KeyBackupFailedDialog_title">
|
<span className="mx_KeyBackupFailedDialog_title">
|
||||||
<ErrorIcon />
|
|
||||||
{_t("encryption|new_recovery_method_detected|title")}
|
{_t("encryption|new_recovery_method_detected|title")}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ErrorIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
|
||||||
|
|
||||||
import dis from "../../../../dispatcher/dispatcher";
|
import dis from "../../../../dispatcher/dispatcher";
|
||||||
import { _t } from "../../../../languageHandler";
|
import { _t } from "../../../../languageHandler";
|
||||||
@@ -40,10 +39,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent<IPr
|
|||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const title = (
|
const title = (
|
||||||
<span className="mx_KeyBackupFailedDialog_title">
|
<span className="mx_KeyBackupFailedDialog_title">{_t("encryption|recovery_method_removed|title")}</span>
|
||||||
<ErrorIcon />
|
|
||||||
{_t("encryption|recovery_method_removed|title")}
|
|
||||||
</span>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
import React, { type JSX } from "react";
|
import React, { type JSX } from "react";
|
||||||
import { createRef } from "react";
|
import { createRef } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { ExploreIcon, DialPadIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
|
||||||
|
|
||||||
import dis from "../../dispatcher/dispatcher";
|
import dis from "../../dispatcher/dispatcher";
|
||||||
import { _t } from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
@@ -348,9 +347,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
|||||||
className="mx_LeftPanel_dialPadButton"
|
className="mx_LeftPanel_dialPadButton"
|
||||||
onClick={this.onDialPad}
|
onClick={this.onDialPad}
|
||||||
title={_t("left_panel|open_dial_pad")}
|
title={_t("left_panel|open_dial_pad")}
|
||||||
>
|
/>
|
||||||
<DialPadIcon />
|
|
||||||
</AccessibleButton>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,9 +358,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
|||||||
className="mx_LeftPanel_exploreButton"
|
className="mx_LeftPanel_exploreButton"
|
||||||
onClick={this.onExplore}
|
onClick={this.onExplore}
|
||||||
title={_t("action|explore_rooms")}
|
title={_t("action|explore_rooms")}
|
||||||
>
|
/>
|
||||||
<ExploreIcon />
|
|
||||||
</AccessibleButton>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
HttpApiEvent,
|
HttpApiEvent,
|
||||||
type MatrixClient,
|
type MatrixClient,
|
||||||
MatrixEvent,
|
MatrixEvent,
|
||||||
|
MatrixSafetyError,
|
||||||
MsgType,
|
MsgType,
|
||||||
type RoomType,
|
type RoomType,
|
||||||
SyncState,
|
SyncState,
|
||||||
@@ -29,7 +30,6 @@ import { TooltipProvider } from "@vector-im/compound-web";
|
|||||||
import "what-input";
|
import "what-input";
|
||||||
import sanitizeHtml from "sanitize-html";
|
import sanitizeHtml from "sanitize-html";
|
||||||
import { I18nContext } from "@element-hq/web-shared-components";
|
import { I18nContext } from "@element-hq/web-shared-components";
|
||||||
import { LockSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
|
||||||
|
|
||||||
import PosthogTrackers from "../../PosthogTrackers";
|
import PosthogTrackers from "../../PosthogTrackers";
|
||||||
import { DecryptionFailureTracker } from "../../DecryptionFailureTracker";
|
import { DecryptionFailureTracker } from "../../DecryptionFailureTracker";
|
||||||
@@ -1772,7 +1772,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
ToastStore.sharedInstance().addOrReplaceToast({
|
ToastStore.sharedInstance().addOrReplaceToast({
|
||||||
key: "verifreq_" + request.transactionId,
|
key: "verifreq_" + request.transactionId,
|
||||||
title: _t("encryption|verification_requested_toast_title"),
|
title: _t("encryption|verification_requested_toast_title"),
|
||||||
icon: <LockSolidIcon color="var(--cpd-color-text-primary)" />,
|
icon: "verification",
|
||||||
props: { request },
|
props: { request },
|
||||||
component: VerificationRequestToast,
|
component: VerificationRequestToast,
|
||||||
priority: 90,
|
priority: 90,
|
||||||
|
|||||||
@@ -12,10 +12,8 @@ import { ReleaseAnnouncement as ReleaseAnnouncementCompound } from "@vector-im/c
|
|||||||
import { ReleaseAnnouncementStore, type Feature } from "../../stores/ReleaseAnnouncementStore";
|
import { ReleaseAnnouncementStore, type Feature } from "../../stores/ReleaseAnnouncementStore";
|
||||||
import { useIsReleaseAnnouncementOpen } from "../../hooks/useIsReleaseAnnouncementOpen";
|
import { useIsReleaseAnnouncementOpen } from "../../hooks/useIsReleaseAnnouncementOpen";
|
||||||
|
|
||||||
interface ReleaseAnnouncementProps extends Omit<
|
interface ReleaseAnnouncementProps
|
||||||
ComponentProps<typeof ReleaseAnnouncementCompound>,
|
extends Omit<ComponentProps<typeof ReleaseAnnouncementCompound>, "open" | "onClick"> {
|
||||||
"open" | "onClick"
|
|
||||||
> {
|
|
||||||
feature: Feature;
|
feature: Feature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
Copyright (c) 2025 Element Creations Ltd.
|
||||||
Copyright 2024 New Vector Ltd.
|
Copyright 2024 New Vector Ltd.
|
||||||
Copyright 2015-2021 The Matrix.org Foundation C.I.C.
|
Copyright 2015-2021 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
@@ -6,292 +7,83 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { type JSX, type ReactNode } from "react";
|
import React from "react";
|
||||||
import {
|
import { type Room } from "matrix-js-sdk/src/matrix";
|
||||||
ClientEvent,
|
import { WarningIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||||
EventStatus,
|
|
||||||
type MatrixError,
|
|
||||||
type MatrixEvent,
|
|
||||||
type Room,
|
|
||||||
RoomEvent,
|
|
||||||
type SyncState,
|
|
||||||
type SyncStateData,
|
|
||||||
} from "matrix-js-sdk/src/matrix";
|
|
||||||
import { RestartIcon, WarningIcon, DeleteIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
|
||||||
|
|
||||||
import { _t, _td } from "../../languageHandler";
|
import { _t, _td } from "../../languageHandler";
|
||||||
import Resend from "../../Resend";
|
|
||||||
import dis from "../../dispatcher/dispatcher";
|
|
||||||
import { messageForResourceLimitError } from "../../utils/ErrorUtils";
|
|
||||||
import { Action } from "../../dispatcher/actions";
|
|
||||||
import { StaticNotificationState } from "../../stores/notifications/StaticNotificationState";
|
import { StaticNotificationState } from "../../stores/notifications/StaticNotificationState";
|
||||||
import AccessibleButton from "../views/elements/AccessibleButton";
|
import AccessibleButton from "../views/elements/AccessibleButton";
|
||||||
import InlineSpinner from "../views/elements/InlineSpinner";
|
import InlineSpinner from "../views/elements/InlineSpinner";
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
|
||||||
import { RoomStatusBarUnsentMessages } from "./RoomStatusBarUnsentMessages";
|
import { RoomStatusBarUnsentMessages } from "./RoomStatusBarUnsentMessages";
|
||||||
import ExternalLink from "../views/elements/ExternalLink";
|
import { useRoomStatusBarViewModel } from "../viewmodels/rooms/RoomStatusBarViewModel";
|
||||||
|
|
||||||
const STATUS_BAR_HIDDEN = 0;
|
|
||||||
const STATUS_BAR_EXPANDED = 1;
|
|
||||||
const STATUS_BAR_EXPANDED_LARGE = 2;
|
|
||||||
|
|
||||||
export function getUnsentMessages(room: Room, threadId?: string): MatrixEvent[] {
|
|
||||||
if (!room) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return room.getPendingEvents().filter(function (ev) {
|
|
||||||
const isNotSent = ev.status === EventStatus.NOT_SENT;
|
|
||||||
const belongsToTheThread = threadId === ev.threadRootId;
|
|
||||||
return isNotSent && (!threadId || belongsToTheThread);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
// the room this statusbar is representing.
|
// the room this statusbar is representing.
|
||||||
room: Room;
|
room: Room;
|
||||||
|
|
||||||
// true if the room is being peeked at. This affects components that shouldn't
|
|
||||||
// logically be shown when peeking, such as a prompt to invite people to a room.
|
|
||||||
isPeeking?: boolean;
|
|
||||||
// callback for when the user clicks on the 'resend all' button in the
|
|
||||||
// 'unsent messages' bar
|
|
||||||
onResendAllClick?: () => void;
|
|
||||||
|
|
||||||
// callback for when the user clicks on the 'cancel all' button in the
|
|
||||||
// 'unsent messages' bar
|
|
||||||
onCancelAllClick?: () => void;
|
|
||||||
|
|
||||||
// callback for when the user clicks on the 'invite others' button in the
|
|
||||||
// 'you are alone' bar
|
|
||||||
onInviteClick?: () => void;
|
|
||||||
|
|
||||||
// callback for when we do something that changes the size of the
|
|
||||||
// status bar. This is used to trigger a re-layout in the parent
|
|
||||||
// component.
|
|
||||||
onResize?: () => void;
|
|
||||||
|
|
||||||
// callback for when the status bar can be hidden from view, as it is
|
|
||||||
// not displaying anything
|
|
||||||
onHidden?: () => void;
|
|
||||||
|
|
||||||
// callback for when the status bar is displaying something and should
|
|
||||||
// be visible
|
|
||||||
onVisible?: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
export function RoomStatusBar(props: IProps) {
|
||||||
syncState: SyncState | null;
|
const vm = useRoomStatusBarViewModel(props);
|
||||||
syncStateData: SyncStateData | null;
|
if (!vm.visible) {
|
||||||
unsentMessages: MatrixEvent[];
|
return null;
|
||||||
isResending: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class RoomStatusBar extends React.PureComponent<IProps, IState> {
|
|
||||||
private unmounted = false;
|
|
||||||
public static contextType = MatrixClientContext;
|
|
||||||
declare public context: React.ContextType<typeof MatrixClientContext>;
|
|
||||||
|
|
||||||
public constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
syncState: this.context.getSyncState(),
|
|
||||||
syncStateData: this.context.getSyncStateData(),
|
|
||||||
unsentMessages: getUnsentMessages(this.props.room),
|
|
||||||
isResending: false,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
if ("connectivityLost" in vm) {
|
||||||
public componentDidMount(): void {
|
|
||||||
this.unmounted = false;
|
|
||||||
|
|
||||||
const client = this.context;
|
|
||||||
client.on(ClientEvent.Sync, this.onSyncStateChange);
|
|
||||||
client.on(RoomEvent.LocalEchoUpdated, this.onRoomLocalEchoUpdated);
|
|
||||||
|
|
||||||
this.checkSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidUpdate(): void {
|
|
||||||
this.checkSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillUnmount(): void {
|
|
||||||
this.unmounted = true;
|
|
||||||
// we may have entirely lost our client as we're logging out before clicking login on the guest bar...
|
|
||||||
const client = this.context;
|
|
||||||
if (client) {
|
|
||||||
client.removeListener(ClientEvent.Sync, this.onSyncStateChange);
|
|
||||||
client.removeListener(RoomEvent.LocalEchoUpdated, this.onRoomLocalEchoUpdated);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private onSyncStateChange = (state: SyncState, prevState: SyncState | null, data?: SyncStateData): void => {
|
|
||||||
if (state === "SYNCING" && prevState === "SYNCING") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.unmounted) return;
|
|
||||||
this.setState({
|
|
||||||
syncState: state,
|
|
||||||
syncStateData: data ?? null,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
private onResendAllClick = (): void => {
|
|
||||||
Resend.resendUnsentEvents(this.props.room).then(() => {
|
|
||||||
this.setState({ isResending: false });
|
|
||||||
});
|
|
||||||
this.setState({ isResending: true });
|
|
||||||
dis.fire(Action.FocusSendMessageComposer);
|
|
||||||
};
|
|
||||||
|
|
||||||
private onCancelAllClick = (): void => {
|
|
||||||
Resend.cancelUnsentEvents(this.props.room);
|
|
||||||
dis.fire(Action.FocusSendMessageComposer);
|
|
||||||
};
|
|
||||||
|
|
||||||
private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room): void => {
|
|
||||||
if (room.roomId !== this.props.room.roomId) return;
|
|
||||||
const messages = getUnsentMessages(this.props.room);
|
|
||||||
this.setState({
|
|
||||||
unsentMessages: messages,
|
|
||||||
isResending: messages.length > 0 && this.state.isResending,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check whether current size is greater than 0, if yes call props.onVisible
|
|
||||||
private checkSize(): void {
|
|
||||||
if (this.getSize()) {
|
|
||||||
if (this.props.onVisible) this.props.onVisible();
|
|
||||||
} else {
|
|
||||||
if (this.props.onHidden) this.props.onHidden();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't need the actual height - just whether it is likely to have
|
|
||||||
// changed - so we use '0' to indicate normal size, and other values to
|
|
||||||
// indicate other sizes.
|
|
||||||
private getSize(): number {
|
|
||||||
if (this.shouldShowConnectionError()) {
|
|
||||||
return STATUS_BAR_EXPANDED;
|
|
||||||
} else if (this.state.unsentMessages.length > 0 || this.state.isResending) {
|
|
||||||
return STATUS_BAR_EXPANDED_LARGE;
|
|
||||||
}
|
|
||||||
return STATUS_BAR_HIDDEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
private shouldShowConnectionError(): boolean {
|
|
||||||
// no conn bar trumps the "some not sent" msg since you can't resend without
|
|
||||||
// a connection!
|
|
||||||
// There's one situation in which we don't show this 'no connection' bar, and that's
|
|
||||||
// if it's a resource limit exceeded error: those are shown in the top bar.
|
|
||||||
const errorIsMauError = Boolean(
|
|
||||||
this.state.syncStateData &&
|
|
||||||
this.state.syncStateData.error &&
|
|
||||||
this.state.syncStateData.error.name === "M_RESOURCE_LIMIT_EXCEEDED",
|
|
||||||
);
|
|
||||||
return this.state.syncState === "ERROR" && !errorIsMauError;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getUnsentMessageContent(): JSX.Element {
|
|
||||||
const unsentMessages = this.state.unsentMessages;
|
|
||||||
|
|
||||||
let title: ReactNode;
|
|
||||||
|
|
||||||
let consentError: MatrixError | null = null;
|
|
||||||
let resourceLimitError: MatrixError | null = null;
|
|
||||||
for (const m of unsentMessages) {
|
|
||||||
if (m.error && m.error.errcode === "M_CONSENT_NOT_GIVEN") {
|
|
||||||
consentError = m.error;
|
|
||||||
break;
|
|
||||||
} else if (m.error && m.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED") {
|
|
||||||
resourceLimitError = m.error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (consentError) {
|
|
||||||
title = _t(
|
|
||||||
"room|status_bar|requires_consent_agreement",
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
consentLink: (sub) => (
|
|
||||||
<ExternalLink href={consentError!.data?.consent_uri} target="_blank" rel="noreferrer noopener">
|
|
||||||
{sub}
|
|
||||||
</ExternalLink>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else if (resourceLimitError) {
|
|
||||||
title = messageForResourceLimitError(
|
|
||||||
resourceLimitError.data.limit_type,
|
|
||||||
resourceLimitError.data.admin_contact,
|
|
||||||
{
|
|
||||||
"monthly_active_user": _td("room|status_bar|monthly_user_limit_reached"),
|
|
||||||
"hs_disabled": _td("room|status_bar|homeserver_blocked"),
|
|
||||||
"": _td("room|status_bar|exceeded_resource_limit"),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
title = _t("room|status_bar|some_messages_not_sent");
|
|
||||||
}
|
|
||||||
|
|
||||||
let buttonRow = (
|
|
||||||
<>
|
|
||||||
<AccessibleButton onClick={this.onCancelAllClick}>
|
|
||||||
<DeleteIcon />
|
|
||||||
{_t("room|status_bar|delete_all")}
|
|
||||||
</AccessibleButton>
|
|
||||||
<AccessibleButton onClick={this.onResendAllClick} className="mx_RoomStatusBar_unsentRetry">
|
|
||||||
<RestartIcon />
|
|
||||||
{_t("room|status_bar|retry_all")}
|
|
||||||
</AccessibleButton>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
if (this.state.isResending) {
|
|
||||||
buttonRow = (
|
|
||||||
<>
|
|
||||||
<InlineSpinner w={20} h={20} />
|
|
||||||
{/* span for css */}
|
|
||||||
<span>{_t("forward|sending")}</span>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RoomStatusBarUnsentMessages
|
<div className="mx_RoomStatusBar">
|
||||||
title={title}
|
<div role="alert">
|
||||||
description={_t("room|status_bar|select_messages_to_retry")}
|
<div className="mx_RoomStatusBar_connectionLostBar">
|
||||||
notificationState={StaticNotificationState.RED_EXCLAMATION}
|
<WarningIcon width="24px" height="24px" />
|
||||||
buttons={buttonRow}
|
<div>
|
||||||
/>
|
<div className="mx_RoomStatusBar_connectionLostBar_title">
|
||||||
);
|
{_t("room|status_bar|server_connectivity_lost_title")}
|
||||||
}
|
</div>
|
||||||
|
<div className="mx_RoomStatusBar_connectionLostBar_desc">
|
||||||
public render(): React.ReactNode {
|
{_t("room|status_bar|server_connectivity_lost_description")}
|
||||||
if (this.shouldShowConnectionError()) {
|
|
||||||
return (
|
|
||||||
<div className="mx_RoomStatusBar">
|
|
||||||
<div role="alert">
|
|
||||||
<div className="mx_RoomStatusBar_connectionLostBar">
|
|
||||||
<WarningIcon width="24px" height="24px" />
|
|
||||||
<div>
|
|
||||||
<div className="mx_RoomStatusBar_connectionLostBar_title">
|
|
||||||
{_t("room|status_bar|server_connectivity_lost_title")}
|
|
||||||
</div>
|
|
||||||
<div className="mx_RoomStatusBar_connectionLostBar_desc">
|
|
||||||
{_t("room|status_bar|server_connectivity_lost_description")}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
|
|
||||||
if (this.state.unsentMessages.length > 0 || this.state.isResending) {
|
|
||||||
return this.getUnsentMessageContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vm.isResending) {
|
||||||
|
return (
|
||||||
|
<RoomStatusBarUnsentMessages
|
||||||
|
title={vm.title}
|
||||||
|
description={vm.description}
|
||||||
|
notificationState={StaticNotificationState.RED_EXCLAMATION}
|
||||||
|
buttons={
|
||||||
|
<>
|
||||||
|
<InlineSpinner w={20} h={20} />
|
||||||
|
{/* span for css */}
|
||||||
|
<span>{_t("forward|sending")}</span>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RoomStatusBarUnsentMessages
|
||||||
|
title={vm.title}
|
||||||
|
description={vm.description}
|
||||||
|
notificationState={StaticNotificationState.RED_EXCLAMATION}
|
||||||
|
buttons={
|
||||||
|
<>
|
||||||
|
{vm.onCancelAllClick && (
|
||||||
|
<AccessibleButton onClick={vm.onCancelAllClick} className="mx_RoomStatusBar_unsentCancelAllBtn">
|
||||||
|
{_t("room|status_bar|delete_all")}
|
||||||
|
</AccessibleButton>
|
||||||
|
)}
|
||||||
|
{vm.onResendAllClick && (
|
||||||
|
<AccessibleButton onClick={vm.onResendAllClick} className="mx_RoomStatusBar_unsentRetry">
|
||||||
|
{_t("room|status_bar|retry_all")}
|
||||||
|
</AccessibleButton>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ import { debounce, throttle } from "lodash";
|
|||||||
import { CryptoEvent } from "matrix-js-sdk/src/crypto-api";
|
import { CryptoEvent } from "matrix-js-sdk/src/crypto-api";
|
||||||
import { type ViewRoomOpts } from "@matrix-org/react-sdk-module-api/lib/lifecycles/RoomViewLifecycle";
|
import { type ViewRoomOpts } from "@matrix-org/react-sdk-module-api/lib/lifecycles/RoomViewLifecycle";
|
||||||
import { type RoomViewProps } from "@element-hq/element-web-module-api";
|
import { type RoomViewProps } from "@element-hq/element-web-module-api";
|
||||||
import { RestartIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
|
||||||
|
|
||||||
import shouldHideEvent from "../../shouldHideEvent";
|
import shouldHideEvent from "../../shouldHideEvent";
|
||||||
import { _t } from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
@@ -92,7 +91,7 @@ import { type IOpts } from "../../createRoom";
|
|||||||
import EditorStateTransfer from "../../utils/EditorStateTransfer";
|
import EditorStateTransfer from "../../utils/EditorStateTransfer";
|
||||||
import ErrorDialog from "../views/dialogs/ErrorDialog";
|
import ErrorDialog from "../views/dialogs/ErrorDialog";
|
||||||
import UploadBar from "./UploadBar";
|
import UploadBar from "./UploadBar";
|
||||||
import RoomStatusBar from "./RoomStatusBar";
|
import { RoomStatusBar } from "./RoomStatusBar";
|
||||||
import MessageComposer from "../views/rooms/MessageComposer";
|
import MessageComposer from "../views/rooms/MessageComposer";
|
||||||
import JumpToBottomButton from "../views/rooms/JumpToBottomButton";
|
import JumpToBottomButton from "../views/rooms/JumpToBottomButton";
|
||||||
import TopUnreadMessagesBar from "../views/rooms/TopUnreadMessagesBar";
|
import TopUnreadMessagesBar from "../views/rooms/TopUnreadMessagesBar";
|
||||||
@@ -331,8 +330,7 @@ function LocalRoomView(props: LocalRoomViewProps): ReactElement {
|
|||||||
|
|
||||||
if (room.isError) {
|
if (room.isError) {
|
||||||
const buttons = (
|
const buttons = (
|
||||||
<AccessibleButton onClick={onRetryClicked}>
|
<AccessibleButton onClick={onRetryClicked} className="mx_RoomStatusBar_unsentRetry">
|
||||||
<RestartIcon />
|
|
||||||
{_t("action|retry")}
|
{_t("action|retry")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
);
|
);
|
||||||
@@ -1678,14 +1676,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onInviteClick = (): void => {
|
|
||||||
// open the room inviter
|
|
||||||
defaultDispatcher.dispatch({
|
|
||||||
action: "view_invite",
|
|
||||||
roomId: this.getRoomId(),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
private onJoinButtonClicked = (): void => {
|
private onJoinButtonClicked = (): void => {
|
||||||
// If the user is a ROU, allow them to transition to a PWLU
|
// If the user is a ROU, allow them to transition to a PWLU
|
||||||
if (this.context.client?.isGuest()) {
|
if (this.context.client?.isGuest()) {
|
||||||
@@ -2024,17 +2014,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private onStatusBarVisible = (): void => {
|
|
||||||
if (this.unmounted || this.state.statusBarVisible) return;
|
|
||||||
this.setState({ statusBarVisible: true });
|
|
||||||
};
|
|
||||||
|
|
||||||
private onStatusBarHidden = (): void => {
|
|
||||||
// This is currently not desired as it is annoying if it keeps expanding and collapsing
|
|
||||||
if (this.unmounted || !this.state.statusBarVisible) return;
|
|
||||||
this.setState({ statusBarVisible: false });
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called by the parent component when PageUp/Down/etc is pressed.
|
* called by the parent component when PageUp/Down/etc is pressed.
|
||||||
*
|
*
|
||||||
@@ -2385,21 +2364,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let statusBar: JSX.Element | undefined;
|
let statusBar: JSX.Element | undefined;
|
||||||
let isStatusAreaExpanded = true;
|
const isStatusAreaExpanded = true;
|
||||||
|
|
||||||
if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
|
if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
|
||||||
statusBar = <UploadBar room={this.state.room} />;
|
statusBar = <UploadBar room={this.state.room} />;
|
||||||
} else if (!this.state.search) {
|
} else if (!this.state.search) {
|
||||||
isStatusAreaExpanded = this.state.statusBarVisible;
|
statusBar = <RoomStatusBar room={this.state.room} />;
|
||||||
statusBar = (
|
|
||||||
<RoomStatusBar
|
|
||||||
room={this.state.room}
|
|
||||||
isPeeking={myMembership !== KnownMembership.Join}
|
|
||||||
onInviteClick={this.onInviteClick}
|
|
||||||
onVisible={this.onStatusBarVisible}
|
|
||||||
onHidden={this.onStatusBarHidden}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusBarAreaClass = classNames("mx_RoomView_statusArea", {
|
const statusBarAreaClass = classNames("mx_RoomView_statusArea", {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
import React, { createRef, type HTMLProps } from "react";
|
import React, { createRef, type HTMLProps } from "react";
|
||||||
import { throttle } from "lodash";
|
import { throttle } from "lodash";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
|
||||||
|
|
||||||
import AccessibleButton from "../../components/views/elements/AccessibleButton";
|
import AccessibleButton from "../../components/views/elements/AccessibleButton";
|
||||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||||
@@ -125,9 +124,7 @@ export default class SearchBox extends React.Component<IProps, IState> {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.clearSearch("button");
|
this.clearSearch("button");
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<CloseIcon />
|
|
||||||
</AccessibleButton>
|
|
||||||
) : undefined;
|
) : undefined;
|
||||||
|
|
||||||
// show a shorter placeholder when blurred, if requested
|
// show a shorter placeholder when blurred, if requested
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
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;
|
|
||||||