Use semantic headings in user settings Appearance (#10827)

* split SettingsSection out of SettingsTab, replace usage

* correct copyright

* use semantic headings in GeneralRoomSettingsTab

* use SettingsTab and SettingsSubsection in room settings

* fix VoipRoomSettingsTab

* use SettingsSection components in space settings

* settingssubsection text component

* use semantic headings in HelpUserSetttings tab

* use ExternalLink components for external links

* test

* strict

* lint

* semantic heading in labs settings

* semantic headings in keyboard settings tab

* semantic heading in preferencesusersettingstab

* tidying

* use new settings components in eventindexpanel

* findByTestId

* prettier

* semantic headings and style refresh for crypto settings

* e2e panel

* use semantic headings in User settings appearance tab

* update selectors in tests

* tidy
This commit is contained in:
Kerry 2023-05-22 09:12:11 +12:00 committed by GitHub
parent e652177706
commit b3b03e5dcb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 765 additions and 770 deletions

View file

@ -176,7 +176,7 @@ describe("Audio player", () => {
// Enable high contrast manually // Enable high contrast manually
cy.openUserSettings("Appearance") cy.openUserSettings("Appearance")
.get(".mx_ThemeChoicePanel") .findByTestId("mx_ThemeChoicePanel")
.findByLabelText("Use high contrast") .findByLabelText("Use high contrast")
.click({ force: true }); // force click because the size of the checkbox is zero .click({ force: true }); // force click because the size of the checkbox is zero

View file

@ -36,12 +36,11 @@ describe("Appearance user settings tab", () => {
it("should be rendered properly", () => { it("should be rendered properly", () => {
cy.openUserSettings("Appearance"); cy.openUserSettings("Appearance");
cy.get(".mx_SettingsTab.mx_AppearanceUserSettingsTab").within(() => { cy.findByTestId("mx_AppearanceUserSettingsTab").within(() => {
// Assert that the top heading is rendered cy.get("h2").should("have.text", "Customise your appearance").should("be.visible");
cy.findByTestId("appearance").should("have.text", "Customise your appearance").should("be.visible");
}); });
cy.get(".mx_SettingsTab.mx_AppearanceUserSettingsTab").percySnapshotElement( cy.findByTestId("mx_AppearanceUserSettingsTab").percySnapshotElement(
"User settings tab - Appearance (advanced options collapsed)", "User settings tab - Appearance (advanced options collapsed)",
{ {
// Emulate TabbedView's actual min and max widths // Emulate TabbedView's actual min and max widths
@ -57,7 +56,7 @@ describe("Appearance user settings tab", () => {
// Assert that "Hide advanced" link button is rendered // Assert that "Hide advanced" link button is rendered
cy.findByRole("button", { name: "Hide advanced" }).should("exist"); cy.findByRole("button", { name: "Hide advanced" }).should("exist");
cy.get(".mx_SettingsTab.mx_AppearanceUserSettingsTab").percySnapshotElement( cy.findByTestId("mx_AppearanceUserSettingsTab").percySnapshotElement(
"User settings tab - Appearance (advanced options expanded)", "User settings tab - Appearance (advanced options expanded)",
{ {
// Emulate TabbedView's actual min and max widths // Emulate TabbedView's actual min and max widths
@ -74,7 +73,7 @@ describe("Appearance user settings tab", () => {
cy.openUserSettings("Appearance"); cy.openUserSettings("Appearance");
cy.get(".mx_AppearanceUserSettingsTab .mx_LayoutSwitcher_RadioButtons").within(() => { cy.get(".mx_LayoutSwitcher_RadioButtons").within(() => {
// Assert that the layout selected by default is "Modern" // Assert that the layout selected by default is "Modern"
cy.get(".mx_LayoutSwitcher_RadioButton_selected .mx_StyledRadioButton_enabled").within(() => { cy.get(".mx_LayoutSwitcher_RadioButton_selected .mx_StyledRadioButton_enabled").within(() => {
cy.findByLabelText("Modern").should("exist"); cy.findByLabelText("Modern").should("exist");
@ -84,7 +83,7 @@ describe("Appearance user settings tab", () => {
// Assert that the room layout is set to group (modern) layout // Assert that the room layout is set to group (modern) layout
cy.get(".mx_RoomView_body[data-layout='group']").should("exist"); cy.get(".mx_RoomView_body[data-layout='group']").should("exist");
cy.get(".mx_AppearanceUserSettingsTab .mx_LayoutSwitcher_RadioButtons").within(() => { cy.get(".mx_LayoutSwitcher_RadioButtons").within(() => {
// Select the first layout // Select the first layout
cy.get(".mx_LayoutSwitcher_RadioButton").first().click(); cy.get(".mx_LayoutSwitcher_RadioButton").first().click();
@ -97,7 +96,7 @@ describe("Appearance user settings tab", () => {
// Assert that the room layout is set to IRC layout // Assert that the room layout is set to IRC layout
cy.get(".mx_RoomView_body[data-layout='irc']").should("exist"); cy.get(".mx_RoomView_body[data-layout='irc']").should("exist");
cy.get(".mx_AppearanceUserSettingsTab .mx_LayoutSwitcher_RadioButtons").within(() => { cy.get(".mx_LayoutSwitcher_RadioButtons").within(() => {
// Select the last layout // Select the last layout
cy.get(".mx_LayoutSwitcher_RadioButton").last().click(); cy.get(".mx_LayoutSwitcher_RadioButton").last().click();
@ -114,7 +113,7 @@ describe("Appearance user settings tab", () => {
it("should support changing font size by clicking the font slider", () => { it("should support changing font size by clicking the font slider", () => {
cy.openUserSettings("Appearance"); cy.openUserSettings("Appearance");
cy.get(".mx_SettingsTab.mx_AppearanceUserSettingsTab").within(() => { cy.findByTestId("mx_AppearanceUserSettingsTab").within(() => {
cy.get(".mx_FontScalingPanel_fontSlider").within(() => { cy.get(".mx_FontScalingPanel_fontSlider").within(() => {
cy.findByLabelText("Font size").should("exist"); cy.findByLabelText("Font size").should("exist");
}); });
@ -150,7 +149,7 @@ describe("Appearance user settings tab", () => {
it("should disable font size slider when custom font size is used", () => { it("should disable font size slider when custom font size is used", () => {
cy.openUserSettings("Appearance"); cy.openUserSettings("Appearance");
cy.get(".mx_FontScalingPanel").within(() => { cy.findByTestId("mx_FontScalingPanel").within(() => {
cy.findByLabelText("Use custom size").click({ force: true }); // force click as checkbox size is zero cy.findByLabelText("Use custom size").click({ force: true }); // force click as checkbox size is zero
// Assert that the font slider is disabled // Assert that the font slider is disabled
@ -167,10 +166,8 @@ describe("Appearance user settings tab", () => {
// Click "Show advanced" link button // Click "Show advanced" link button
cy.findByRole("button", { name: "Show advanced" }).click(); cy.findByRole("button", { name: "Show advanced" }).click();
cy.get(".mx_AppearanceUserSettingsTab_Advanced").within(() => { // force click as checkbox size is zero
// force click as checkbox size is zero cy.findByLabelText("Use a more compact 'Modern' layout").click({ force: true });
cy.findByLabelText("Use a more compact 'Modern' layout").click({ force: true });
});
// Assert that the room layout is set to compact group (modern) layout // Assert that the room layout is set to compact group (modern) layout
cy.get("#matrixchat .mx_MatrixChat_wrapper.mx_MatrixChat_useCompactLayout").should("exist"); cy.get("#matrixchat .mx_MatrixChat_wrapper.mx_MatrixChat_useCompactLayout").should("exist");
@ -178,13 +175,7 @@ describe("Appearance user settings tab", () => {
it("should disable compact group (modern) layout option on IRC layout and bubble layout", () => { it("should disable compact group (modern) layout option on IRC layout and bubble layout", () => {
const checkDisabled = () => { const checkDisabled = () => {
cy.get(".mx_AppearanceUserSettingsTab_Advanced").within(() => { cy.findByLabelText("Use a more compact 'Modern' layout").should("be.disabled");
cy.get(".mx_Checkbox")
.first()
.within(() => {
cy.get("input[type='checkbox'][disabled]").should("exist");
});
});
}; };
cy.openUserSettings("Appearance"); cy.openUserSettings("Appearance");
@ -193,7 +184,7 @@ describe("Appearance user settings tab", () => {
cy.findByRole("button", { name: "Show advanced" }).click(); cy.findByRole("button", { name: "Show advanced" }).click();
// Enable IRC layout // Enable IRC layout
cy.get(".mx_AppearanceUserSettingsTab .mx_LayoutSwitcher_RadioButtons").within(() => { cy.get(".mx_LayoutSwitcher_RadioButtons").within(() => {
// Select the first layout // Select the first layout
cy.get(".mx_LayoutSwitcher_RadioButton").first().click(); cy.get(".mx_LayoutSwitcher_RadioButton").first().click();
@ -206,7 +197,7 @@ describe("Appearance user settings tab", () => {
checkDisabled(); checkDisabled();
// Enable bubble layout // Enable bubble layout
cy.get(".mx_AppearanceUserSettingsTab .mx_LayoutSwitcher_RadioButtons").within(() => { cy.get(".mx_LayoutSwitcher_RadioButtons").within(() => {
// Select the first layout // Select the first layout
cy.get(".mx_LayoutSwitcher_RadioButton").last().click(); cy.get(".mx_LayoutSwitcher_RadioButton").last().click();
@ -225,10 +216,8 @@ describe("Appearance user settings tab", () => {
// Click "Show advanced" link button // Click "Show advanced" link button
cy.findByRole("button", { name: "Show advanced" }).click(); cy.findByRole("button", { name: "Show advanced" }).click();
cy.get(".mx_AppearanceUserSettingsTab_Advanced").within(() => { // force click as checkbox size is zero
// force click as checkbox size is zero cy.findByLabelText("Use a system font").click({ force: true });
cy.findByLabelText("Use a system font").click({ force: true });
});
// Assert that the font-family value was removed // Assert that the font-family value was removed
cy.get("body").should("have.css", "font-family", '""'); cy.get("body").should("have.css", "font-family", '""');
@ -242,7 +231,7 @@ describe("Appearance user settings tab", () => {
it("should be rendered with the light theme selected", () => { it("should be rendered with the light theme selected", () => {
cy.openUserSettings("Appearance") cy.openUserSettings("Appearance")
.get(".mx_ThemeChoicePanel") .findByTestId("mx_ThemeChoicePanel")
.within(() => { .within(() => {
cy.findByTestId("checkbox-use-system-theme").within(() => { cy.findByTestId("checkbox-use-system-theme").within(() => {
cy.findByText("Match system theme").should("be.visible"); cy.findByText("Match system theme").should("be.visible");
@ -252,7 +241,7 @@ describe("Appearance user settings tab", () => {
cy.get(".mx_Checkbox_checkmark").should("not.be.visible"); cy.get(".mx_Checkbox_checkmark").should("not.be.visible");
}); });
cy.get(".mx_ThemeSelectors").within(() => { cy.findByTestId("theme-choice-panel-selectors").within(() => {
cy.get(".mx_ThemeSelector_light").should("exist"); cy.get(".mx_ThemeSelector_light").should("exist");
cy.get(".mx_ThemeSelector_dark").should("exist"); cy.get(".mx_ThemeSelector_dark").should("exist");
@ -274,11 +263,11 @@ describe("Appearance user settings tab", () => {
"the system theme is clicked", "the system theme is clicked",
() => { () => {
cy.openUserSettings("Appearance") cy.openUserSettings("Appearance")
.get(".mx_ThemeChoicePanel") .findByTestId("mx_ThemeChoicePanel")
.findByLabelText("Match system theme") .findByLabelText("Match system theme")
.click({ force: true }); // force click because the size of the checkbox is zero .click({ force: true }); // force click because the size of the checkbox is zero
cy.get(".mx_ThemeChoicePanel").within(() => { cy.findByTestId("mx_ThemeChoicePanel").within(() => {
// Assert that the labels for the light theme and dark theme are disabled // Assert that the labels for the light theme and dark theme are disabled
cy.get(".mx_ThemeSelector_light.mx_StyledRadioButton_disabled").should("exist"); cy.get(".mx_ThemeSelector_light.mx_StyledRadioButton_disabled").should("exist");
cy.get(".mx_ThemeSelector_dark.mx_StyledRadioButton_disabled").should("exist"); cy.get(".mx_ThemeSelector_dark.mx_StyledRadioButton_disabled").should("exist");
@ -321,7 +310,7 @@ describe("Appearance user settings tab", () => {
}); });
cy.openUserSettings("Appearance") cy.openUserSettings("Appearance")
.get(".mx_ThemeChoicePanel") .findByTestId("mx_ThemeChoicePanel")
.findByLabelText("Use high contrast") .findByLabelText("Use high contrast")
.click({ force: true }); // force click because the size of the checkbox is zero .click({ force: true }); // force click because the size of the checkbox is zero

View file

@ -179,7 +179,6 @@
@import "./views/elements/_Dropdown.pcss"; @import "./views/elements/_Dropdown.pcss";
@import "./views/elements/_EditableItemList.pcss"; @import "./views/elements/_EditableItemList.pcss";
@import "./views/elements/_ErrorBoundary.pcss"; @import "./views/elements/_ErrorBoundary.pcss";
@import "./views/elements/_EventTilePreview.pcss";
@import "./views/elements/_ExternalLink.pcss"; @import "./views/elements/_ExternalLink.pcss";
@import "./views/elements/_FacePile.pcss"; @import "./views/elements/_FacePile.pcss";
@import "./views/elements/_Field.pcss"; @import "./views/elements/_Field.pcss";

View file

@ -1,21 +0,0 @@
/*
Copyright 2021 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.
*/
.mx_FontScalingPanel {
.mx_FontScalingPanel_preview.mx_EventTilePreview_loader {
padding: var(--FontScalingPanel_preview-padding-block) 0;
}
}

View file

@ -14,63 +14,48 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.mx_FontScalingPanel { .mx_FontScalingPanel_preview {
color: $primary-content; --FontScalingPanel_preview-padding-block: 9px;
.mx_FontScalingPanel_preview, border: 1px solid $quinary-content;
.mx_FontScalingPanel_fontSlider { border-radius: 10px;
margin-inline-end: var(--SettingsTab_fullWidthField-margin-inline-end); padding: 0 $spacing-16 var(--FontScalingPanel_preview-padding-block) $spacing-16;
pointer-events: none;
display: flow-root;
&.mx_IRCLayout {
padding-top: 9px; /* TODO: Use a spacing variable */
} }
.mx_FontScalingPanel_preview { .mx_EventTile[data-layout="bubble"] {
--FontScalingPanel_preview-padding-block: 9px; margin-top: 30px; /* TODO: Use a spacing variable */
border: 1px solid $quinary-content;
border-radius: 10px;
padding: 0 $spacing-16 var(--FontScalingPanel_preview-padding-block) $spacing-16;
pointer-events: none;
display: flow-root;
&.mx_IRCLayout {
padding-top: 9px; /* TODO: Use a spacing variable */
}
.mx_EventTile[data-layout="bubble"] {
margin-top: 30px; /* TODO: Use a spacing variable */
}
.mx_EventTile_msgOption {
display: none;
}
} }
.mx_FontScalingPanel_fontSlider { .mx_EventTile_msgOption {
display: flex; display: none;
align-items: center; }
padding: 15px $spacing-20 35px; /* TODO: Use spacing variables */ }
background: rgba($quinary-content, 0.2);
border-radius: 10px; .mx_FontScalingPanel_fontSlider {
font-size: $font-10px; display: flex;
margin-top: $spacing-24; align-items: center;
margin-bottom: $spacing-24; padding: 15px $spacing-20 35px; /* TODO: Use spacing variables */
background: rgba($quinary-content, 0.2);
.mx_FontScalingPanel_fontSlider_smallText, border-radius: 10px;
.mx_FontScalingPanel_fontSlider_largeText { font-size: $font-10px;
font-weight: 500;
} .mx_FontScalingPanel_fontSlider_smallText,
.mx_FontScalingPanel_fontSlider_largeText {
.mx_FontScalingPanel_fontSlider_smallText { font-weight: 500;
font-size: $font-15px; }
padding-inline-end: $spacing-20;
} .mx_FontScalingPanel_fontSlider_smallText {
font-size: $font-15px;
.mx_FontScalingPanel_fontSlider_largeText { padding-inline-end: $spacing-20;
font-size: $font-18px; }
padding-inline-start: $spacing-20;
} .mx_FontScalingPanel_fontSlider_largeText {
} font-size: $font-18px;
padding-inline-start: $spacing-20;
.mx_FontScalingPanel_customFontSizeField {
margin-inline-start: var(--AppearanceUserSettingsTab_Field-margin-inline-start);
} }
} }

View file

@ -14,34 +14,31 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.mx_ImageSizePanel { .mx_ImageSizePanel_radios {
color: $primary-content; display: flex;
flex-direction: row;
gap: $spacing-16;
.mx_ImageSizePanel_radios { > label {
display: flex; margin-right: 68px; /* keep the boxes separate */
margin-top: 16px; /* move away from header a bit */ cursor: pointer;
}
> label { .mx_ImageSizePanel_size {
margin-right: 68px; /* keep the boxes separate */ background-color: $quinary-content;
cursor: pointer; mask-repeat: no-repeat;
mask-size: 221px;
mask-position: center;
width: 221px;
height: 148px;
margin-bottom: 14px; /* move radio button away from bottom edge a bit */
&.mx_ImageSizePanel_sizeDefault {
mask: url("$(res)/img/element-icons/settings/img-size-normal.svg");
} }
.mx_ImageSizePanel_size { &.mx_ImageSizePanel_sizeLarge {
background-color: $quinary-content; mask: url("$(res)/img/element-icons/settings/img-size-large.svg");
mask-repeat: no-repeat;
mask-size: 221px;
mask-position: center;
width: 221px;
height: 148px;
margin-bottom: 14px; /* move radio button away from bottom edge a bit */
&.mx_ImageSizePanel_sizeDefault {
mask: url("$(res)/img/element-icons/settings/img-size-normal.svg");
}
&.mx_ImageSizePanel_sizeLarge {
mask: url("$(res)/img/element-icons/settings/img-size-large.svg");
}
} }
} }
} }

View file

@ -15,79 +15,77 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.mx_LayoutSwitcher { .mx_LayoutSwitcher_RadioButtons {
.mx_LayoutSwitcher_RadioButtons { display: flex;
flex-direction: row;
gap: 24px;
color: $primary-content;
> .mx_LayoutSwitcher_RadioButton {
flex-grow: 0;
flex-shrink: 1;
display: flex; display: flex;
flex-direction: row; flex-direction: column;
gap: 24px;
color: $primary-content; flex-basis: 33%;
min-width: 0;
> .mx_LayoutSwitcher_RadioButton { border: 1px solid $quinary-content;
flex-grow: 0; border-radius: 10px;
flex-shrink: 1;
.mx_EventTile_msgOption,
.mx_MessageActionBar {
display: none;
}
.mx_LayoutSwitcher_RadioButton_preview {
flex-grow: 1;
display: flex; display: flex;
flex-direction: column; align-items: center;
padding: 10px;
pointer-events: none;
width: 300px; .mx_EventTile[data-layout="bubble"] .mx_EventTile_line {
min-width: 0; padding-right: 11px;
border: 1px solid $quinary-content;
border-radius: 10px;
.mx_EventTile_msgOption,
.mx_MessageActionBar {
display: none;
}
.mx_LayoutSwitcher_RadioButton_preview {
flex-grow: 1;
display: flex;
align-items: center;
padding: 10px;
pointer-events: none;
.mx_EventTile[data-layout="bubble"] .mx_EventTile_line {
padding-right: 11px;
}
}
.mx_StyledRadioButton {
flex-grow: 0;
padding: 10px;
}
.mx_EventTile_content {
margin-right: 0;
}
&.mx_LayoutSwitcher_RadioButton_selected {
border-color: $accent;
} }
} }
.mx_StyledRadioButton { .mx_StyledRadioButton {
border-top: 1px solid $quinary-content; flex-grow: 0;
padding: 10px;
} }
.mx_StyledRadioButton_checked { .mx_EventTile_content {
background-color: rgba($accent, 0.08); margin-right: 0;
} }
.mx_EventTile { &.mx_LayoutSwitcher_RadioButton_selected {
margin: 0; border-color: $accent;
&[data-layout="bubble"] { }
margin-right: 40px; }
flex-shrink: 1;
} .mx_StyledRadioButton {
&[data-layout="irc"] { border-top: 1px solid $quinary-content;
> a { }
display: none;
} .mx_StyledRadioButton_checked {
} background-color: rgba($accent, 0.08);
.mx_EventTile_line { }
max-width: 90%;
.mx_EventTile {
margin: 0;
&[data-layout="bubble"] {
margin-right: 40px;
flex-shrink: 1;
}
&[data-layout="irc"] {
> a {
display: none;
} }
} }
.mx_EventTile_line {
max-width: 90%;
}
} }
} }

View file

@ -14,53 +14,47 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.mx_ThemeChoicePanel { .mx_ThemeChoicePanel_themeSelectors {
color: $primary-content; color: $primary-content;
display: flex;
flex-direction: row;
flex-wrap: wrap;
> .mx_ThemeSelectors { > .mx_StyledRadioButton {
display: flex; padding: $font-16px;
flex-direction: row; box-sizing: border-box;
flex-wrap: wrap; border-radius: 10px;
width: 180px;
margin-top: 4px; background: $quinary-content;
margin-bottom: 30px; opacity: 0.4;
> .mx_StyledRadioButton { flex-shrink: 1;
padding: $font-16px; flex-grow: 0;
box-sizing: border-box;
border-radius: 10px;
width: 180px;
background: $quinary-content; margin-right: 15px;
opacity: 0.4; margin-top: 10px;
flex-shrink: 1; font-weight: var(--font-semi-bold);
flex-grow: 0;
margin-right: 15px; > span {
margin-top: 10px; justify-content: center;
}
}
font-weight: var(--font-semi-bold); > .mx_StyledRadioButton_enabled {
opacity: 1;
> span { /* These colors need to be hardcoded because they don't change with the theme */
justify-content: center; &.mx_ThemeSelector_light {
} background-color: #f3f8fd;
color: #2e2f32;
} }
> .mx_StyledRadioButton_enabled { &.mx_ThemeSelector_dark {
opacity: 1; /* 5% lightened version of 181b21 */
background-color: #25282e;
/* These colors need to be hardcoded because they don't change with the theme */ color: #f3f8fd;
&.mx_ThemeSelector_light {
background-color: #f3f8fd;
color: #2e2f32;
}
&.mx_ThemeSelector_dark {
/* 5% lightened version of 181b21 */
background-color: #25282e;
color: #f3f8fd;
}
} }
} }
} }

View file

@ -14,25 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.mx_AppearanceUserSettingsTab { .mx_Field.mx_AppearanceUserSettingsTab_checkboxControlledField {
--AppearanceUserSettingsTab_Field-margin-inline-start: calc($font-16px + 10px); width: 256px;
// matches checkbox box + padding
.mx_SettingsTab_subsectionText { // to align with checkbox label
margin-block: $spacing-12 $spacing-32; margin-inline-start: calc($font-16px + 10px);
color: $primary-content; /* Same as mx_SettingsTab */
}
.mx_Field {
width: 256px;
}
.mx_AppearanceUserSettingsTab_Advanced {
.mx_Checkbox {
margin-block: $spacing-16;
}
.mx_AppearanceUserSettingsTab_systemFont {
margin-inline-start: var(--AppearanceUserSettingsTab_Field-margin-inline-start);
}
}
} }

View file

@ -82,11 +82,11 @@ $roomtopic-color: $secondary-content;
background-color: $panel-actions !important; background-color: $panel-actions !important;
} }
.mx_ThemeChoicePanel > .mx_ThemeSelectors > .mx_StyledRadioButton input[type="radio"]:disabled + div { .mx_ThemeChoicePanel_themeSelectors > .mx_StyledRadioButton input[type="radio"]:disabled + div {
border-color: $primary-content; border-color: $primary-content;
} }
.mx_ThemeChoicePanel > .mx_ThemeSelectors > .mx_StyledRadioButton.mx_StyledRadioButton_disabled { .mx_ThemeChoicePanel_themeSelectors > .mx_StyledRadioButton.mx_StyledRadioButton_disabled {
color: $primary-content; color: $primary-content;
} }

View file

@ -28,6 +28,7 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { SettingLevel } from "../../../settings/SettingLevel"; import { SettingLevel } from "../../../settings/SettingLevel";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { clamp } from "../../../utils/numbers"; import { clamp } from "../../../utils/numbers";
import SettingsSubsection from "./shared/SettingsSubsection";
interface IProps {} interface IProps {}
@ -108,8 +109,7 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
const max = 18; const max = 18;
return ( return (
<div className="mx_SettingsTab_section mx_FontScalingPanel"> <SettingsSubsection heading={_t("Font size")} stretchContent data-testid="mx_FontScalingPanel">
<span className="mx_SettingsTab_subheading">{_t("Font size")}</span>
<EventTilePreview <EventTilePreview
className="mx_FontScalingPanel_preview" className="mx_FontScalingPanel_preview"
message={this.MESSAGE_PREVIEW_TEXT} message={this.MESSAGE_PREVIEW_TEXT}
@ -159,9 +159,9 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
onValidate={this.onValidateFontSize} onValidate={this.onValidateFontSize}
onChange={(value: ChangeEvent<HTMLInputElement>) => this.setState({ fontSize: value.target.value })} onChange={(value: ChangeEvent<HTMLInputElement>) => this.setState({ fontSize: value.target.value })}
disabled={!this.state.useCustomFontSize} disabled={!this.state.useCustomFontSize}
className="mx_FontScalingPanel_customFontSizeField" className="mx_AppearanceUserSettingsTab_checkboxControlledField"
/> />
</div> </SettingsSubsection>
); );
} }
} }

View file

@ -21,6 +21,7 @@ import StyledRadioButton from "../elements/StyledRadioButton";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { SettingLevel } from "../../../settings/SettingLevel"; import { SettingLevel } from "../../../settings/SettingLevel";
import { ImageSize } from "../../../settings/enums/ImageSize"; import { ImageSize } from "../../../settings/enums/ImageSize";
import SettingsSubsection from "./shared/SettingsSubsection";
interface IProps { interface IProps {
// none // none
@ -49,9 +50,7 @@ export default class ImageSizePanel extends React.Component<IProps, IState> {
public render(): React.ReactNode { public render(): React.ReactNode {
return ( return (
<div className="mx_SettingsTab_section mx_ImageSizePanel"> <SettingsSubsection heading={_t("Image size in the timeline")}>
<span className="mx_SettingsTab_subheading">{_t("Image size in the timeline")}</span>
<div className="mx_ImageSizePanel_radios"> <div className="mx_ImageSizePanel_radios">
<label> <label>
<div className="mx_ImageSizePanel_size mx_ImageSizePanel_sizeDefault" /> <div className="mx_ImageSizePanel_size mx_ImageSizePanel_sizeDefault" />
@ -76,7 +75,7 @@ export default class ImageSizePanel extends React.Component<IProps, IState> {
</StyledRadioButton> </StyledRadioButton>
</label> </label>
</div> </div>
</div> </SettingsSubsection>
); );
} }
} }

View file

@ -25,6 +25,7 @@ import StyledRadioButton from "../elements/StyledRadioButton";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { Layout } from "../../../settings/enums/Layout"; import { Layout } from "../../../settings/enums/Layout";
import { SettingLevel } from "../../../settings/SettingLevel"; import { SettingLevel } from "../../../settings/SettingLevel";
import SettingsSubsection from "./shared/SettingsSubsection";
interface IProps { interface IProps {
userId?: string; userId?: string;
@ -67,9 +68,7 @@ export default class LayoutSwitcher extends React.Component<IProps, IState> {
}); });
return ( return (
<div className="mx_SettingsTab_section mx_LayoutSwitcher"> <SettingsSubsection heading={_t("Message layout")}>
<span className="mx_SettingsTab_subheading">{_t("Message layout")}</span>
<div className="mx_LayoutSwitcher_RadioButtons"> <div className="mx_LayoutSwitcher_RadioButtons">
<label className={ircClasses}> <label className={ircClasses}>
<EventTilePreview <EventTilePreview
@ -126,7 +125,7 @@ export default class LayoutSwitcher extends React.Component<IProps, IState> {
</StyledRadioButton> </StyledRadioButton>
</label> </label>
</div> </div>
</div> </SettingsSubsection>
); );
} }
} }

View file

@ -30,6 +30,7 @@ import Field from "../elements/Field";
import StyledRadioGroup from "../elements/StyledRadioGroup"; import StyledRadioGroup from "../elements/StyledRadioGroup";
import { SettingLevel } from "../../../settings/SettingLevel"; import { SettingLevel } from "../../../settings/SettingLevel";
import PosthogTrackers from "../../../PosthogTrackers"; import PosthogTrackers from "../../../PosthogTrackers";
import SettingsSubsection from "./shared/SettingsSubsection";
interface IProps {} interface IProps {}
@ -245,10 +246,9 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
const orderedThemes = getOrderedThemes(); const orderedThemes = getOrderedThemes();
return ( return (
<div className="mx_SettingsTab_section mx_ThemeChoicePanel"> <SettingsSubsection heading={_t("Theme")} data-testid="mx_ThemeChoicePanel">
<span className="mx_SettingsTab_subheading">{_t("Theme")}</span>
{systemThemeSection} {systemThemeSection}
<div className="mx_ThemeSelectors"> <div className="mx_ThemeChoicePanel_themeSelectors" data-testid="theme-choice-panel-selectors">
<StyledRadioGroup <StyledRadioGroup
name="theme" name="theme"
definitions={orderedThemes.map((t) => ({ definitions={orderedThemes.map((t) => ({
@ -264,7 +264,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
</div> </div>
{this.renderHighContrastCheckbox()} {this.renderHighContrastCheckbox()}
{customThemeForm} {customThemeForm}
</div> </SettingsSubsection>
); );
} }

View file

@ -31,6 +31,9 @@ import LayoutSwitcher from "../../LayoutSwitcher";
import FontScalingPanel from "../../FontScalingPanel"; import FontScalingPanel from "../../FontScalingPanel";
import ThemeChoicePanel from "../../ThemeChoicePanel"; import ThemeChoicePanel from "../../ThemeChoicePanel";
import ImageSizePanel from "../../ImageSizePanel"; import ImageSizePanel from "../../ImageSizePanel";
import SettingsTab from "../SettingsTab";
import { SettingsSection } from "../../shared/SettingsSection";
import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection";
interface IProps {} interface IProps {}
@ -115,7 +118,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
onChange={(checked) => this.setState({ useSystemFont: checked })} onChange={(checked) => this.setState({ useSystemFont: checked })}
/> />
<Field <Field
className="mx_AppearanceUserSettingsTab_systemFont" className="mx_AppearanceUserSettingsTab_checkboxControlledField"
label={SettingsStore.getDisplayName("systemFont")!} label={SettingsStore.getDisplayName("systemFont")!}
onChange={(value: ChangeEvent<HTMLInputElement>) => { onChange={(value: ChangeEvent<HTMLInputElement>) => {
this.setState({ this.setState({
@ -133,10 +136,10 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
); );
} }
return ( return (
<div className="mx_SettingsTab_section mx_AppearanceUserSettingsTab_Advanced"> <SettingsSubsection heading={<></>}>
{toggle} {toggle}
{advanced} {advanced}
</div> </SettingsSubsection>
); );
} }
@ -144,25 +147,24 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
const brand = SdkConfig.get().brand; const brand = SdkConfig.get().brand;
return ( return (
<div className="mx_SettingsTab mx_AppearanceUserSettingsTab"> <SettingsTab data-testid="mx_AppearanceUserSettingsTab">
<div className="mx_SettingsTab_heading" data-testid="appearance"> <SettingsSection heading={_t("Customise your appearance")}>
{_t("Customise your appearance")} <SettingsSubsectionText>
</div> {_t("Appearance Settings only affect this %(brand)s session.", { brand })}
<div className="mx_SettingsTab_subsectionText"> </SettingsSubsectionText>
{_t("Appearance Settings only affect this %(brand)s session.", { brand })} <ThemeChoicePanel />
</div> <LayoutSwitcher
<ThemeChoicePanel /> userId={this.state.userId}
<LayoutSwitcher displayName={this.state.displayName}
userId={this.state.userId} avatarUrl={this.state.avatarUrl}
displayName={this.state.displayName} messagePreviewText={this.MESSAGE_PREVIEW_TEXT}
avatarUrl={this.state.avatarUrl} onLayoutChanged={this.onLayoutChanged}
messagePreviewText={this.MESSAGE_PREVIEW_TEXT} />
onLayoutChanged={this.onLayoutChanged} <FontScalingPanel />
/> {this.renderAdvancedSection()}
<FontScalingPanel /> <ImageSizePanel />
{this.renderAdvancedSection()} </SettingsSection>
<ImageSizePanel /> </SettingsTab>
</div>
); );
} }
} }

View file

@ -3,104 +3,113 @@
exports[`FontScalingPanel renders the font scaling UI 1`] = ` exports[`FontScalingPanel renders the font scaling UI 1`] = `
<DocumentFragment> <DocumentFragment>
<div <div
class="mx_SettingsTab_section mx_FontScalingPanel" class="mx_SettingsSubsection"
data-testid="mx_FontScalingPanel"
> >
<span
class="mx_SettingsTab_subheading"
>
Font size
</span>
<div <div
class="mx_FontScalingPanel_preview mx_EventTilePreview_loader" class="mx_SettingsSubsectionHeading"
> >
<div <h3
class="mx_Spinner" class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
>
<div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<div
class="mx_FontScalingPanel_fontSlider"
>
<div
class="mx_FontScalingPanel_fontSlider_smallText"
>
Aa
</div>
<div
class="mx_Slider"
>
<input
aria-label="Font size"
autocomplete="off"
max="18"
min="13"
step="1"
type="range"
value="15"
/>
<output
class="mx_Slider_selection"
style="left: calc(2px + 40% + 1.2em - 0.96em);"
>
<span
class="mx_Slider_selection_label"
>
15
</span>
</output>
</div>
<div
class="mx_FontScalingPanel_fontSlider_largeText"
>
Aa
</div>
</div>
<span
class="mx_Checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<input
id="checkbox_abdefghi"
type="checkbox"
/>
<label
for="checkbox_abdefghi"
>
<div
class="mx_Checkbox_background"
>
<div
class="mx_Checkbox_checkmark"
/>
</div>
<div>
Use custom size
</div>
</label>
</span>
<div
class="mx_Field mx_Field_input mx_FontScalingPanel_customFontSizeField"
>
<input
autocomplete="off"
disabled=""
id="font_size_field"
label="Font size"
placeholder="15"
type="number"
value="15"
/>
<label
for="font_size_field"
> >
Font size Font size
</label> </h3>
</div>
<div
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
>
<div
class="mx_FontScalingPanel_preview mx_EventTilePreview_loader"
>
<div
class="mx_Spinner"
>
<div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<div
class="mx_FontScalingPanel_fontSlider"
>
<div
class="mx_FontScalingPanel_fontSlider_smallText"
>
Aa
</div>
<div
class="mx_Slider"
>
<input
aria-label="Font size"
autocomplete="off"
max="18"
min="13"
step="1"
type="range"
value="15"
/>
<output
class="mx_Slider_selection"
style="left: calc(2px + 40% + 1.2em - 0.96em);"
>
<span
class="mx_Slider_selection_label"
>
15
</span>
</output>
</div>
<div
class="mx_FontScalingPanel_fontSlider_largeText"
>
Aa
</div>
</div>
<span
class="mx_Checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<input
id="checkbox_abdefghi"
type="checkbox"
/>
<label
for="checkbox_abdefghi"
>
<div
class="mx_Checkbox_background"
>
<div
class="mx_Checkbox_checkmark"
/>
</div>
<div>
Use custom size
</div>
</label>
</span>
<div
class="mx_Field mx_Field_input mx_AppearanceUserSettingsTab_checkboxControlledField"
>
<input
autocomplete="off"
disabled=""
id="font_size_field"
label="Font size"
placeholder="15"
type="number"
value="15"
/>
<label
for="font_size_field"
>
Font size
</label>
</div>
</div> </div>
</div> </div>
</DocumentFragment> </DocumentFragment>

View file

@ -3,60 +3,70 @@
exports[`ThemeChoicePanel renders the theme choice UI 1`] = ` exports[`ThemeChoicePanel renders the theme choice UI 1`] = `
<DocumentFragment> <DocumentFragment>
<div <div
class="mx_SettingsTab_section mx_ThemeChoicePanel" class="mx_SettingsSubsection"
data-testid="mx_ThemeChoicePanel"
> >
<span
class="mx_SettingsTab_subheading"
>
Theme
</span>
<div <div
class="mx_ThemeSelectors" class="mx_SettingsSubsectionHeading"
> >
<label <h3
class="mx_StyledRadioButton mx_ThemeSelector_light mx_StyledRadioButton_disabled mx_StyledRadioButton_outlined" class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
> >
<input Theme
disabled="" </h3>
id="theme-light" </div>
name="theme" <div
type="radio" class="mx_SettingsSubsection_content"
value="light" >
/> <div
<div> class="mx_ThemeChoicePanel_themeSelectors"
<div /> data-testid="theme-choice-panel-selectors"
</div>
<div
class="mx_StyledRadioButton_content"
>
Light
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
<label
class="mx_StyledRadioButton mx_ThemeSelector_dark mx_StyledRadioButton_disabled mx_StyledRadioButton_outlined"
> >
<input <label
disabled="" class="mx_StyledRadioButton mx_ThemeSelector_light mx_StyledRadioButton_disabled mx_StyledRadioButton_outlined"
id="theme-dark"
name="theme"
type="radio"
value="dark"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
> >
Dark <input
</div> disabled=""
<div id="theme-light"
class="mx_StyledRadioButton_spacer" name="theme"
/> type="radio"
</label> value="light"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Light
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
<label
class="mx_StyledRadioButton mx_ThemeSelector_dark mx_StyledRadioButton_disabled mx_StyledRadioButton_outlined"
>
<input
disabled=""
id="theme-dark"
name="theme"
type="radio"
value="dark"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Dark
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</div>
</div> </div>
</div> </div>
</DocumentFragment> </DocumentFragment>

View file

@ -3,382 +3,433 @@
exports[`AppearanceUserSettingsTab should render 1`] = ` exports[`AppearanceUserSettingsTab should render 1`] = `
<DocumentFragment> <DocumentFragment>
<div <div
class="mx_SettingsTab mx_AppearanceUserSettingsTab" class="mx_SettingsTab"
data-testid="mx_AppearanceUserSettingsTab"
> >
<div <div
class="mx_SettingsTab_heading" class="mx_SettingsTab_sections"
data-testid="appearance"
> >
Customise your appearance
</div>
<div
class="mx_SettingsTab_subsectionText"
>
Appearance Settings only affect this Element session.
</div>
<div
class="mx_SettingsTab_section mx_ThemeChoicePanel"
>
<span
class="mx_SettingsTab_subheading"
>
Theme
</span>
<div <div
class="mx_ThemeSelectors" class="mx_SettingsSection"
> >
<label <h2
class="mx_StyledRadioButton mx_ThemeSelector_light mx_StyledRadioButton_disabled mx_StyledRadioButton_outlined" class="mx_Heading_h2"
>
Customise your appearance
</h2>
<div
class="mx_SettingsSection_subSections"
> >
<input
disabled=""
id="theme-light"
name="theme"
type="radio"
value="light"
/>
<div>
<div />
</div>
<div <div
class="mx_StyledRadioButton_content" class="mx_SettingsSubsection_text"
> >
Light Appearance Settings only affect this Element session.
</div> </div>
<div <div
class="mx_StyledRadioButton_spacer" class="mx_SettingsSubsection"
/> data-testid="mx_ThemeChoicePanel"
</label>
<label
class="mx_StyledRadioButton mx_ThemeSelector_dark mx_StyledRadioButton_disabled mx_StyledRadioButton_outlined"
>
<input
disabled=""
id="theme-dark"
name="theme"
type="radio"
value="dark"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Dark
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</div>
</div>
<div
class="mx_SettingsTab_section mx_LayoutSwitcher"
>
<span
class="mx_SettingsTab_subheading"
>
Message layout
</span>
<div
class="mx_LayoutSwitcher_RadioButtons"
>
<label
class="mx_LayoutSwitcher_RadioButton"
>
<div
class="mx_LayoutSwitcher_RadioButton_preview mx_IRCLayout mx_EventTilePreview_loader"
> >
<div <div
class="mx_Spinner" class="mx_SettingsSubsectionHeading"
>
<h3
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
>
Theme
</h3>
</div>
<div
class="mx_SettingsSubsection_content"
> >
<div <div
aria-label="Loading…" class="mx_ThemeChoicePanel_themeSelectors"
class="mx_Spinner_icon" data-testid="theme-choice-panel-selectors"
data-testid="spinner" >
role="progressbar" <label
style="width: 32px; height: 32px;" class="mx_StyledRadioButton mx_ThemeSelector_light mx_StyledRadioButton_disabled mx_StyledRadioButton_outlined"
/> >
<input
disabled=""
id="theme-light"
name="theme"
type="radio"
value="light"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Light
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
<label
class="mx_StyledRadioButton mx_ThemeSelector_dark mx_StyledRadioButton_disabled mx_StyledRadioButton_outlined"
>
<input
disabled=""
id="theme-dark"
name="theme"
type="radio"
value="dark"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Dark
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</div>
</div> </div>
</div> </div>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
>
<input
name="layout"
type="radio"
value="irc"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
IRC (Experimental)
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</label>
<label
class="mx_LayoutSwitcher_RadioButton mx_LayoutSwitcher_RadioButton_selected"
>
<div <div
class="mx_LayoutSwitcher_RadioButton_preview mx_EventTilePreview_loader" class="mx_SettingsSubsection"
> >
<div <div
class="mx_Spinner" class="mx_SettingsSubsectionHeading"
>
<h3
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
>
Message layout
</h3>
</div>
<div
class="mx_SettingsSubsection_content"
> >
<div <div
aria-label="Loading…" class="mx_LayoutSwitcher_RadioButtons"
class="mx_Spinner_icon" >
data-testid="spinner" <label
role="progressbar" class="mx_LayoutSwitcher_RadioButton"
style="width: 32px; height: 32px;" >
/> <div
class="mx_LayoutSwitcher_RadioButton_preview mx_IRCLayout mx_EventTilePreview_loader"
>
<div
class="mx_Spinner"
>
<div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
>
<input
name="layout"
type="radio"
value="irc"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
IRC (Experimental)
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</label>
<label
class="mx_LayoutSwitcher_RadioButton mx_LayoutSwitcher_RadioButton_selected"
>
<div
class="mx_LayoutSwitcher_RadioButton_preview mx_EventTilePreview_loader"
>
<div
class="mx_Spinner"
>
<div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled mx_StyledRadioButton_checked"
>
<input
checked=""
name="layout"
type="radio"
value="group"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Modern
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</label>
<label
class="mx_LayoutSwitcher_RadioButton"
>
<div
class="mx_LayoutSwitcher_RadioButton_preview mx_EventTilePreview_loader"
>
<div
class="mx_Spinner"
>
<div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
>
<input
name="layout"
type="radio"
value="bubble"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Message bubbles
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</label>
</div>
</div> </div>
</div> </div>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled mx_StyledRadioButton_checked"
>
<input
checked=""
name="layout"
type="radio"
value="group"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Modern
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</label>
<label
class="mx_LayoutSwitcher_RadioButton"
>
<div <div
class="mx_LayoutSwitcher_RadioButton_preview mx_EventTilePreview_loader" class="mx_SettingsSubsection"
data-testid="mx_FontScalingPanel"
> >
<div <div
class="mx_Spinner" class="mx_SettingsSubsectionHeading"
>
<h3
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
>
Font size
</h3>
</div>
<div
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
> >
<div <div
aria-label="Loading…" class="mx_FontScalingPanel_preview mx_EventTilePreview_loader"
class="mx_Spinner_icon" >
data-testid="spinner" <div
role="progressbar" class="mx_Spinner"
style="width: 32px; height: 32px;" >
/> <div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<div
class="mx_FontScalingPanel_fontSlider"
>
<div
class="mx_FontScalingPanel_fontSlider_smallText"
>
Aa
</div>
<div
class="mx_Slider"
>
<input
aria-label="Font size"
autocomplete="off"
max="18"
min="13"
step="1"
type="range"
value="15"
/>
<output
class="mx_Slider_selection"
style="left: calc(2px + 40% + 1.2em - 0.96em);"
>
<span
class="mx_Slider_selection_label"
>
15
</span>
</output>
</div>
<div
class="mx_FontScalingPanel_fontSlider_largeText"
>
Aa
</div>
</div>
<span
class="mx_Checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<input
id="checkbox_abdefghi"
type="checkbox"
/>
<label
for="checkbox_abdefghi"
>
<div
class="mx_Checkbox_background"
>
<div
class="mx_Checkbox_checkmark"
/>
</div>
<div>
Use custom size
</div>
</label>
</span>
<div
class="mx_Field mx_Field_input mx_AppearanceUserSettingsTab_checkboxControlledField"
>
<input
autocomplete="off"
disabled=""
id="font_size_field"
label="Font size"
placeholder="15"
type="number"
value="15"
/>
<label
for="font_size_field"
>
Font size
</label>
</div>
</div> </div>
</div> </div>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
>
<input
name="layout"
type="radio"
value="bubble"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Message bubbles
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</label>
</div>
</div>
<div
class="mx_SettingsTab_section mx_FontScalingPanel"
>
<span
class="mx_SettingsTab_subheading"
>
Font size
</span>
<div
class="mx_FontScalingPanel_preview mx_EventTilePreview_loader"
>
<div
class="mx_Spinner"
>
<div <div
aria-label="Loading…" class="mx_SettingsSubsection"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<div
class="mx_FontScalingPanel_fontSlider"
>
<div
class="mx_FontScalingPanel_fontSlider_smallText"
>
Aa
</div>
<div
class="mx_Slider"
>
<input
aria-label="Font size"
autocomplete="off"
max="18"
min="13"
step="1"
type="range"
value="15"
/>
<output
class="mx_Slider_selection"
style="left: calc(2px + 40% + 1.2em - 0.96em);"
>
<span
class="mx_Slider_selection_label"
>
15
</span>
</output>
</div>
<div
class="mx_FontScalingPanel_fontSlider_largeText"
>
Aa
</div>
</div>
<span
class="mx_Checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<input
id="checkbox_abdefghi"
type="checkbox"
/>
<label
for="checkbox_abdefghi"
>
<div
class="mx_Checkbox_background"
> >
<div <div
class="mx_Checkbox_checkmark" class="mx_SettingsSubsection_content"
/> >
<div
aria-expanded="false"
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link"
role="button"
tabindex="0"
>
Show advanced
</div>
</div>
</div> </div>
<div> <div
Use custom size class="mx_SettingsSubsection"
>
<div
class="mx_SettingsSubsectionHeading"
>
<h3
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
>
Image size in the timeline
</h3>
</div>
<div
class="mx_SettingsSubsection_content"
>
<div
class="mx_ImageSizePanel_radios"
>
<label>
<div
class="mx_ImageSizePanel_size mx_ImageSizePanel_sizeDefault"
/>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled mx_StyledRadioButton_checked"
>
<input
checked=""
name="image_size"
type="radio"
value="normal"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Default
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</label>
<label>
<div
class="mx_ImageSizePanel_size mx_ImageSizePanel_sizeLarge"
/>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
>
<input
name="image_size"
type="radio"
value="large"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Large
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</label>
</div>
</div>
</div> </div>
</label> </div>
</span>
<div
class="mx_Field mx_Field_input mx_FontScalingPanel_customFontSizeField"
>
<input
autocomplete="off"
disabled=""
id="font_size_field"
label="Font size"
placeholder="15"
type="number"
value="15"
/>
<label
for="font_size_field"
>
Font size
</label>
</div>
</div>
<div
class="mx_SettingsTab_section mx_AppearanceUserSettingsTab_Advanced"
>
<div
aria-expanded="false"
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link"
role="button"
tabindex="0"
>
Show advanced
</div>
</div>
<div
class="mx_SettingsTab_section mx_ImageSizePanel"
>
<span
class="mx_SettingsTab_subheading"
>
Image size in the timeline
</span>
<div
class="mx_ImageSizePanel_radios"
>
<label>
<div
class="mx_ImageSizePanel_size mx_ImageSizePanel_sizeDefault"
/>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled mx_StyledRadioButton_checked"
>
<input
checked=""
name="image_size"
type="radio"
value="normal"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Default
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</label>
<label>
<div
class="mx_ImageSizePanel_size mx_ImageSizePanel_sizeLarge"
/>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
>
<input
name="image_size"
type="radio"
value="large"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Large
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
</label>
</div> </div>
</div> </div>
</div> </div>