Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

New theme ui in user settings #12576

Merged
merged 51 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
aca8b19
Add hook to get the theme
florianduros Jun 3, 2024
2d303c4
Adapt subsection settings to new ui
florianduros Jun 4, 2024
908c7bf
WIP new theme subsection
florianduros Jun 4, 2024
e89eb41
Add theme selection
florianduros Jun 5, 2024
5407a56
Fix test types
florianduros Jun 5, 2024
9de33b0
Disabled theme selector when system theme is used
florianduros Jun 5, 2024
800baa4
Update compound to `4.4.1`
florianduros Jun 5, 2024
7855896
Merge branch 'refs/heads/develop' into florianduros/settings-appearan…
florianduros Jun 7, 2024
ccaa56e
Merge branch 'refs/heads/develop' into florianduros/settings-appearan…
florianduros Jun 17, 2024
130b213
Add custom theme support
florianduros Jun 18, 2024
183c7b9
Remove old ThemChoicePanel
florianduros Jun 18, 2024
5ff7662
Fix QuickThemeSwitcher-test.tsx
florianduros Jun 18, 2024
651deaa
Fix AppearanceUserSettingsTab-test.tsx
florianduros Jun 18, 2024
1abdbc4
Update i18n
florianduros Jun 18, 2024
27188d8
Fix ThemeChoicePanel-test.tsx
florianduros Jun 18, 2024
cb917de
Update `@vector-im/compound-web`
florianduros Jun 18, 2024
c92325d
Small tweaks
florianduros Jun 18, 2024
61a7988
Fix CSS comments and use compound variable
florianduros Jun 19, 2024
41ba88c
Merge branch 'develop' into florianduros/settings-appearance-theme
florianduros Jun 19, 2024
a9b6d2e
Remove custom theme title
florianduros Jun 19, 2024
a81dd1f
Merge branch 'develop' into florianduros/settings-appearance-theme
florianduros Jun 20, 2024
e3666f3
i18n: update
florianduros Jun 20, 2024
5016eb3
test: add tests to theme selection
florianduros Jun 20, 2024
2ba8070
test: update AppearanceUserSettingsTab-test snapshot
florianduros Jun 20, 2024
f109672
test: rework custom theme
florianduros Jun 20, 2024
b0dd73a
playwright: fix audio-player.spec.ts
florianduros Jun 20, 2024
ef6f436
playwright: appearance tab
florianduros Jun 20, 2024
08aeedd
test: update snapshot
florianduros Jun 20, 2024
febc2a4
playright: add custom theme
florianduros Jun 20, 2024
9cf287a
Merge branch 'develop' into florianduros/settings-appearance-theme
florianduros Jun 20, 2024
f74d97b
i18n: use correct char for ellipsis
florianduros Jun 20, 2024
587717f
a11y: add missing aria-label to delete button
florianduros Jun 20, 2024
0bf4712
dialog: update close button tooltip
florianduros Jun 21, 2024
aba5eb0
theme: remove local state and handle custom delete
florianduros Jun 21, 2024
ad73b11
theme: don't add twice the same custom theme
florianduros Jun 21, 2024
75264cc
test: update snapshot
florianduros Jun 21, 2024
8ad39fa
playwright: update snapshot
florianduros Jun 21, 2024
2230343
custom theme: add background to custom theme list
florianduros Jun 21, 2024
ead34fb
Merge branch 'develop' into florianduros/settings-appearance-theme
florianduros Jun 21, 2024
774782d
Merge branch 'refs/heads/develop' into florianduros/settings-appearan…
florianduros Jun 24, 2024
5af55d3
update compound web
florianduros Jun 24, 2024
6905e8e
Use new destructive property on `IconButton` of theme panel
florianduros Jun 24, 2024
af26ea5
Merge branch 'develop' into florianduros/settings-appearance-theme
florianduros Jun 24, 2024
f85bf6c
test: update snapshots
florianduros Jun 24, 2024
f2eae02
rename new ui into legacy
florianduros Jun 25, 2024
1ea9a7b
remove wrong constructor doc
florianduros Jun 25, 2024
df66c29
Merge branch 'develop' into florianduros/settings-appearance-theme
florianduros Jun 25, 2024
35411cf
fix theme selector padding
florianduros Jun 25, 2024
9f6ae52
theme selector: fix key
florianduros Jun 26, 2024
aa55e9a
Merge branch 'develop' into florianduros/settings-appearance-theme
florianduros Jun 26, 2024
2272691
test: fix e2e
florianduros Jun 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion playwright/e2e/audio-player/audio-player.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ test.describe("Audio player", () => {

// Enable high contrast manually
const settings = await app.settings.openUserSettings("Appearance");
await settings.getByTestId("mx_ThemeChoicePanel").getByText("Use high contrast").click();
await settings.getByRole("radio", { name: "High contrast" }).click();

await app.closeDialog();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { test, expect } from "../../element-web-test";
import { SettingLevel } from "../../../src/settings/SettingLevel";
import { expect, test } from ".";

test.describe("Appearance user settings tab", () => {
test.use({
Expand Down Expand Up @@ -151,69 +150,68 @@ test.describe("Appearance user settings tab", () => {
});

test.describe("Theme Choice Panel", () => {
test.beforeEach(async ({ app, user }) => {
test.beforeEach(async ({ app, user, util }) => {
// Disable the default theme for consistency in case ThemeWatcher automatically chooses it
await app.settings.setValue("use_system_theme", null, SettingLevel.DEVICE, false);
await util.disableSystemTheme();
await util.openAppearanceTab();
});

test("should be rendered with the light theme selected", async ({ page, app }) => {
await app.settings.openUserSettings("Appearance");
const themePanel = page.getByTestId("mx_ThemeChoicePanel");

const useSystemTheme = themePanel.getByTestId("checkbox-use-system-theme");
await expect(useSystemTheme.getByText("Match system theme")).toBeVisible();
test("should be rendered with the light theme selected", async ({ page, app, util }) => {
// Assert that 'Match system theme' is not checked
// Note that mx_Checkbox_checkmark exists and is hidden by CSS if it is not checked
await expect(useSystemTheme.locator(".mx_Checkbox_checkmark")).not.toBeVisible();
await expect(util.getMatchSystemThemeCheckbox()).not.toBeChecked();

const selectors = themePanel.getByTestId("theme-choice-panel-selectors");
await expect(selectors.locator(".mx_ThemeSelector_light")).toBeVisible();
await expect(selectors.locator(".mx_ThemeSelector_dark")).toBeVisible();
// Assert that the light theme is selected
await expect(selectors.locator(".mx_ThemeSelector_light.mx_StyledRadioButton_enabled")).toBeVisible();
// Assert that the buttons for the light and dark theme are not enabled
await expect(selectors.locator(".mx_ThemeSelector_light.mx_StyledRadioButton_disabled")).not.toBeVisible();
await expect(selectors.locator(".mx_ThemeSelector_dark.mx_StyledRadioButton_disabled")).not.toBeVisible();
await expect(util.getLightTheme()).toBeChecked();
// Assert that the dark and high contrast themes are not selected
await expect(util.getDarkTheme()).not.toBeChecked();
await expect(util.getHighContrastTheme()).not.toBeChecked();

// Assert that the checkbox for the high contrast theme is rendered
await expect(themePanel.locator(".mx_Checkbox", { hasText: "Use high contrast" })).toBeVisible();
await expect(util.getThemePanel()).toMatchScreenshot("theme-panel-light.png");
});

test("should disable the labels for themes and the checkbox for the high contrast theme if the checkbox for the system theme is clicked", async ({
page,
app,
}) => {
await app.settings.openUserSettings("Appearance");
const themePanel = page.getByTestId("mx_ThemeChoicePanel");
test("should disable the themes when the system theme is clicked", async ({ page, app, util }) => {
await util.getMatchSystemThemeCheckbox().click();

// Assert that the themes are disabled
await expect(util.getLightTheme()).toBeDisabled();
await expect(util.getDarkTheme()).toBeDisabled();
await expect(util.getHighContrastTheme()).toBeDisabled();

await expect(util.getThemePanel()).toMatchScreenshot("theme-panel-match-system-enabled.png");
});

await themePanel.locator(".mx_Checkbox", { hasText: "Match system theme" }).click();
test("should change the theme to dark", async ({ page, app, util }) => {
// Assert that the light theme is selected
await expect(util.getLightTheme()).toBeChecked();

// Assert that the labels for the light theme and dark theme are disabled
await expect(themePanel.locator(".mx_ThemeSelector_light.mx_StyledRadioButton_disabled")).toBeVisible();
await expect(themePanel.locator(".mx_ThemeSelector_dark.mx_StyledRadioButton_disabled")).toBeVisible();
await util.getDarkTheme().click();

// Assert that there does not exist a label for an enabled theme
await expect(themePanel.locator("label.mx_StyledRadioButton_enabled")).not.toBeVisible();
// Assert that the light and high contrast themes are not selected
await expect(util.getLightTheme()).not.toBeChecked();
await expect(util.getDarkTheme()).toBeChecked();
await expect(util.getHighContrastTheme()).not.toBeChecked();

// Assert that the checkbox and label to enable the high contrast theme should not exist
await expect(themePanel.locator(".mx_Checkbox", { hasText: "Use high contrast" })).not.toBeVisible();
await expect(util.getThemePanel()).toMatchScreenshot("theme-panel-dark.png");
});

test("should not render the checkbox and the label for the high contrast theme if the dark theme is selected", async ({
page,
app,
}) => {
await app.settings.openUserSettings("Appearance");
const themePanel = page.getByTestId("mx_ThemeChoicePanel");
test.describe("custom theme", () => {
test.use({
labsFlags: ["feature_custom_themes"],
});

test("should render the custom theme section", async ({ page, app, util }) => {
await expect(util.getThemePanel()).toMatchScreenshot("theme-panel-custom-theme.png");
});

// Assert that the checkbox and the label to enable the high contrast theme should exist
await expect(themePanel.locator(".mx_Checkbox", { hasText: "Use high contrast" })).toBeVisible();
test("should be able to add and remove a custom theme", async ({ page, app, util }) => {
await util.addCustomTheme();

// Enable the dark theme
await themePanel.locator(".mx_ThemeSelector_dark").click();
await expect(util.getCustomTheme()).not.toBeChecked();
await expect(util.getThemePanel()).toMatchScreenshot("theme-panel-custom-theme-added.png");

// Assert that the checkbox and the label should not exist
await expect(themePanel.locator(".mx_Checkbox", { hasText: "Use high contrast" })).not.toBeVisible();
await util.removeCustomTheme();
await expect(util.getThemePanel()).toMatchScreenshot("theme-panel-custom-theme.png");
});
});
});
});
139 changes: 139 additions & 0 deletions playwright/e2e/settings/appearance-user-settings-tab/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2024 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Page } from "@playwright/test";

import { ElementAppPage } from "../../../pages/ElementAppPage";
import { test as base, expect } from "../../../element-web-test";
import { SettingLevel } from "../../../../src/settings/SettingLevel";

export { expect };

/**
* Set up for the appearance tab test
*/
export const test = base.extend<{
util: Helpers;
}>({
util: async ({ page, app }, use) => {
await use(new Helpers(page, app));
},
});

/**
* A collection of helper functions for the appearance tab test
* The goal is to make easier to get and interact with the button, input, or other elements of the appearance tab
*/
class Helpers {
private CUSTOM_THEME_URL = "http://custom.theme";
private CUSTOM_THEME = {
name: "Custom theme",
isDark: false,
colors: {},
};

constructor(
private page: Page,
private app: ElementAppPage,
) {}

/**
* Open the appearance tab
*/
openAppearanceTab() {
return this.app.settings.openUserSettings("Appearance");
}

// Theme Panel

/**
* Disable in the settings the system theme
*/
disableSystemTheme() {
return this.app.settings.setValue("use_system_theme", null, SettingLevel.DEVICE, false);
}

/**
* Return the theme section
*/
getThemePanel() {
return this.page.getByTestId("themePanel");
}

/**
* Return the system theme toggle
*/
getMatchSystemThemeCheckbox() {
return this.page.getByRole("checkbox", { name: "Match system theme" });
}

/**
* Return the theme radio button
* @param theme - the theme to select
* @private
*/
private getThemeRadio(theme: string) {
return this.page.getByRole("radio", { name: theme });
}

/**
* Return the light theme radio button
*/
getLightTheme() {
return this.getThemeRadio("Light");
}

/**
* Return the dark theme radio button
*/
getDarkTheme() {
return this.getThemeRadio("Dark");
}

/**
* Return the custom theme radio button
*/
getCustomTheme() {
return this.getThemeRadio(this.CUSTOM_THEME.name);
}

/**
* Return the high contrast theme radio button
*/
getHighContrastTheme() {
return this.getThemeRadio("High contrast");
}

/**
* Add a custom theme
* Mock the request to the custom and return a fake local custom theme
*/
async addCustomTheme() {
await this.page.route(this.CUSTOM_THEME_URL, (route) =>
route.fulfill({ body: JSON.stringify(this.CUSTOM_THEME) }),
);
await this.page.getByRole("textbox", { name: "Add custom theme" }).fill(this.CUSTOM_THEME_URL);
await this.page.getByRole("button", { name: "Add custom theme" }).click();
await this.page.unroute(this.CUSTOM_THEME_URL);
}

/**
* Remove the custom theme
*/
removeCustomTheme() {
return this.getThemePanel().getByRole("listitem", { name: this.CUSTOM_THEME.name }).getByRole("button").click();
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tooltip is on the bottom instead of the right so it's appearing now on the snapshot.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 8 additions & 6 deletions res/css/_common.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ legend {
.mx_Dialog
button:not(.mx_Dialog_nonDialogButton):not([class|="maplibregl"]):not(.mx_AccessibleButton):not(
.mx_UserProfileSettings button
),
):not(.mx_ThemeChoicePanel_CustomTheme button),
.mx_Dialog input[type="submit"],
.mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton),
.mx_Dialog_buttons input[type="submit"] {
Expand All @@ -624,14 +624,14 @@ legend {
.mx_Dialog
button:not(.mx_Dialog_nonDialogButton):not([class|="maplibregl"]):not(.mx_AccessibleButton):not(
.mx_UserProfileSettings button
):last-child {
):not(.mx_ThemeChoicePanel_CustomTheme button):last-child {
margin-right: 0px;
}

.mx_Dialog
button:not(.mx_Dialog_nonDialogButton):not([class|="maplibregl"]):not(.mx_AccessibleButton):not(
.mx_UserProfileSettings button
):focus,
):not(.mx_ThemeChoicePanel_CustomTheme button):focus,
.mx_Dialog input[type="submit"]:focus,
.mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton):focus,
.mx_Dialog_buttons input[type="submit"]:focus {
Expand All @@ -643,7 +643,7 @@ legend {
.mx_Dialog_buttons
button.mx_Dialog_primary:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton):not(
.mx_UserProfileSettings button
),
):not(.mx_ThemeChoicePanel_CustomTheme button),
.mx_Dialog_buttons input[type="submit"].mx_Dialog_primary {
color: var(--cpd-color-text-on-solid-primary);
background-color: var(--cpd-color-bg-action-primary-rest);
Expand All @@ -654,7 +654,9 @@ legend {
.mx_Dialog button.danger:not(.mx_Dialog_nonDialogButton):not([class|="maplibregl"]),
.mx_Dialog input[type="submit"].danger,
.mx_Dialog_buttons
button.danger:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton):not(.mx_UserProfileSettings button),
button.danger:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton):not(.mx_UserProfileSettings button):not(
.mx_ThemeChoicePanel_CustomTheme button
),
.mx_Dialog_buttons input[type="submit"].danger {
background-color: var(--cpd-color-bg-critical-primary);
border: solid 1px var(--cpd-color-bg-critical-primary);
Expand All @@ -670,7 +672,7 @@ legend {
.mx_Dialog
button:not(.mx_Dialog_nonDialogButton):not([class|="maplibregl"]):not(.mx_AccessibleButton):not(
.mx_UserProfileSettings button
):disabled,
):not(.mx_ThemeChoicePanel_CustomTheme button):disabled,
.mx_Dialog input[type="submit"]:disabled,
.mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton):disabled,
.mx_Dialog_buttons input[type="submit"]:disabled {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ limitations under the License.
.mx_SettingsSubsection {
width: 100%;
box-sizing: border-box;

&.mx_SettingsSubsection_newUi {
display: flex;
flex-direction: column;
gap: var(--cpd-space-8x);
}
}

.mx_SettingsSubsection_description {
Expand Down Expand Up @@ -54,4 +60,8 @@ limitations under the License.
&.mx_SettingsSubsection_noHeading {
margin-top: 0;
}
&.mx_SettingsSubsection_content_newUi {
gap: var(--cpd-space-6x);
margin-top: 0;
}
}
Loading
Loading