[MM-61592]: Updated the Theme list section in the settings modal (#29596)

* [MA-13]: Updated the Theme list section in the settings modal

* [MA-13]: Fixed failing e2e test cases

* [MA-13]: Fixed accordion and removed aria-label from button

* [MA-13]: Fixed grouping of radio buttons

* [MA-13]: Updated the Theme list structure

* [MA-13]: Minor styling changes

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
ayush-chauhan233
2025-02-28 02:59:25 +05:30
коммит произвёл GitHub
родитель e1336b24bf
Коммит 0acadb7b93
6 изменённых файлов: 226 добавлений и 129 удалений

Просмотреть файл

@@ -35,10 +35,10 @@ describe('Settings > Display > Theme > Custom Theme Colors', () => {
cy.get('#customThemes').check().should('be.checked'); cy.get('#customThemes').check().should('be.checked');
// # Open Center Channel Styles section // # Open Center Channel Styles section
cy.get('#centerChannelStyles').click({force: true}).wait(TIMEOUTS.ONE_HUNDRED_MILLIS); cy.get('#centerChannelStylesAccordion').click({force: true}).wait(TIMEOUTS.ONE_HUNDRED_MILLIS);
// # Select custom code theme // # Select custom code theme
cy.get('#codeThemeSelect').should('be.visible').scrollIntoView().select(theme.name); cy.get('#codeThemeSelect').scrollIntoView().should('be.visible').select(theme.name);
// * Verify that the setting changes in the background? // * Verify that the setting changes in the background?
verifyLastPostStyle(theme); verifyLastPostStyle(theme);

Просмотреть файл

@@ -2,33 +2,45 @@
exports[`components/user_settings/display/CustomThemeChooser should match, init 1`] = ` exports[`components/user_settings/display/CustomThemeChooser should match, init 1`] = `
<div <div
aria-labelledby="customThemes"
className="appearance-section pt-2" className="appearance-section pt-2"
id="customThemesSection"
> >
<div <div
className="theme-elements row" className="theme-elements row"
> >
<div <h4
className="theme-elements__header" className="theme-elements__header"
id="sidebarStyles"
onClick={[Function]}
> >
<MemoizedFormattedMessage <button
defaultMessage="Sidebar Styles" aria-controls="sidebarStylesSection"
id="user.settings.custom_theme.sidebarTitle" aria-expanded={false}
/> className="theme-elements__header"
<div id="sidebarStylesAccordion"
className="header__icon" onClick={[Function]}
> >
<i <MemoizedFormattedMessage
className="fa fa-plus" defaultMessage="Sidebar Styles"
id="user.settings.custom_theme.sidebarTitle"
/> />
<i <div
className="fa fa-minus" className="header__icon"
/> >
</div> <i
</div> aria-hidden={true}
className="fa fa-plus"
/>
<i
aria-hidden={true}
className="fa fa-minus"
/>
</div>
</button>
</h4>
<div <div
aria-labelledby="sidebarStylesAccordion"
className="theme-elements__body" className="theme-elements__body"
id="sidebarStylesSection"
> >
<div <div
className="col-sm-6 form-group element" className="col-sm-6 form-group element"
@@ -259,29 +271,38 @@ exports[`components/user_settings/display/CustomThemeChooser should match, init
<div <div
className="theme-elements row" className="theme-elements row"
> >
<div <h4
className="theme-elements__header" className="theme-elements__header"
id="centerChannelStyles"
onClick={[Function]}
> >
<MemoizedFormattedMessage <button
defaultMessage="Center Channel Styles" aria-controls="centerChannelStylesSection"
id="user.settings.custom_theme.centerChannelTitle" aria-expanded={false}
/> className="theme-elements__header"
<div id="centerChannelStylesAccordion"
className="header__icon" onClick={[Function]}
> >
<i <MemoizedFormattedMessage
className="fa fa-plus" defaultMessage="Center Channel Styles"
id="user.settings.custom_theme.centerChannelTitle"
/> />
<i <div
className="fa fa-minus" className="header__icon"
/> >
</div> <i
</div> aria-hidden={true}
className="fa fa-plus"
/>
<i
aria-hidden={true}
className="fa fa-minus"
/>
</div>
</button>
</h4>
<div <div
aria-labelledby="centerChannelStylesAccordion"
className="theme-elements__body" className="theme-elements__body"
id="centerChannelStyles" id="centerChannelStylesSection"
> >
<div <div
className="col-sm-6 form-group element" className="col-sm-6 form-group element"
@@ -456,28 +477,38 @@ exports[`components/user_settings/display/CustomThemeChooser should match, init
<div <div
className="theme-elements row" className="theme-elements row"
> >
<div <h4
className="theme-elements__header" className="theme-elements__header"
id="linkAndButtonsStyles"
onClick={[Function]}
> >
<MemoizedFormattedMessage <button
defaultMessage="Link and Button Styles" aria-controls="linkAndButtonsStylesSection"
id="user.settings.custom_theme.linkButtonTitle" aria-expanded={false}
/> className="theme-elements__header"
<div id="linkAndButtonsStylesAccordion"
className="header__icon" onClick={[Function]}
> >
<i <MemoizedFormattedMessage
className="fa fa-plus" defaultMessage="Link and Button Styles"
id="user.settings.custom_theme.linkButtonTitle"
/> />
<i <div
className="fa fa-minus" className="header__icon"
/> >
</div> <i
</div> aria-hidden={true}
className="fa fa-plus"
/>
<i
aria-hidden={true}
className="fa fa-minus"
/>
</div>
</button>
</h4>
<div <div
aria-labelledby="linkAndButtonsStylesAccordion"
className="theme-elements__body" className="theme-elements__body"
id="linkAndButtonsStylesSection"
> >
<div <div
className="col-sm-6 form-group element" className="col-sm-6 form-group element"

Просмотреть файл

@@ -128,9 +128,9 @@ type State = {
export class CustomThemeChooser extends React.PureComponent<Props, State> { export class CustomThemeChooser extends React.PureComponent<Props, State> {
textareaRef: RefObject<HTMLTextAreaElement>; textareaRef: RefObject<HTMLTextAreaElement>;
sidebarStylesHeaderRef: RefObject<HTMLDivElement>; sidebarStylesHeaderRef: RefObject<HTMLButtonElement>;
centerChannelStylesHeaderRef: RefObject<HTMLDivElement>; centerChannelStylesHeaderRef: RefObject<HTMLButtonElement>;
linkAndButtonStylesHeaderRef: RefObject<HTMLDivElement>; linkAndButtonStylesHeaderRef: RefObject<HTMLButtonElement>;
sidebarStylesRef: RefObject<HTMLDivElement>; sidebarStylesRef: RefObject<HTMLDivElement>;
centerChannelStylesRef: RefObject<HTMLDivElement>; centerChannelStylesRef: RefObject<HTMLDivElement>;
linkAndButtonStylesRef: RefObject<HTMLDivElement>; linkAndButtonStylesRef: RefObject<HTMLDivElement>;
@@ -160,7 +160,7 @@ export class CustomThemeChooser extends React.PureComponent<Props, State> {
[settingId]: color, [settingId]: color,
}; };
// For backwards compatability // For backwards compatibility
if (settingId === 'mentionBg') { if (settingId === 'mentionBg') {
newTheme.mentionBj = color; newTheme.mentionBj = color;
} }
@@ -220,24 +220,33 @@ export class CustomThemeChooser extends React.PureComponent<Props, State> {
this.textareaRef.current?.setSelectionRange(0, this.state.copyTheme.length); this.textareaRef.current?.setSelectionRange(0, this.state.copyTheme.length);
}; };
toggleSidebarStyles = (e: MouseEvent<HTMLDivElement>) => { toggleSidebarStyles = (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault(); e.preventDefault();
this.sidebarStylesHeaderRef.current?.classList.toggle('open'); this.sidebarStylesHeaderRef.current?.classList.toggle('open');
const isAccordionOpen = this.sidebarStylesHeaderRef.current?.classList.contains('open');
this.sidebarStylesHeaderRef.current?.setAttribute('aria-expanded', `${isAccordionOpen}`);
this.toggleSection(this.sidebarStylesRef.current); this.toggleSection(this.sidebarStylesRef.current);
}; };
toggleCenterChannelStyles = (e: MouseEvent<HTMLDivElement>) => { toggleCenterChannelStyles = (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault(); e.preventDefault();
this.centerChannelStylesHeaderRef.current?.classList.toggle('open'); this.centerChannelStylesHeaderRef.current?.classList.toggle('open');
const isAccordionOpen = this.centerChannelStylesHeaderRef.current?.classList.contains('open');
this.centerChannelStylesHeaderRef.current?.setAttribute('aria-expanded', `${isAccordionOpen}`);
this.toggleSection(this.centerChannelStylesRef.current); this.toggleSection(this.centerChannelStylesRef.current);
}; };
toggleLinkAndButtonStyles = (e: MouseEvent<HTMLDivElement>) => { toggleLinkAndButtonStyles = (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault(); e.preventDefault();
this.linkAndButtonStylesHeaderRef.current?.classList.toggle('open'); this.linkAndButtonStylesHeaderRef.current?.classList.toggle('open');
const isAccordionOpen = this.linkAndButtonStylesHeaderRef.current?.classList.contains('open');
this.linkAndButtonStylesHeaderRef.current?.setAttribute('aria-expanded', `${isAccordionOpen}`);
this.toggleSection(this.linkAndButtonStylesRef.current); this.toggleSection(this.linkAndButtonStylesRef.current);
}; };
@@ -448,91 +457,118 @@ export class CustomThemeChooser extends React.PureComponent<Props, State> {
); );
return ( return (
<div className='appearance-section pt-2'> <div
id='customThemesSection'
className='appearance-section pt-2'
aria-labelledby='customThemes'
>
<div className='theme-elements row'> <div className='theme-elements row'>
<div <h4 className='theme-elements__header'>
ref={this.sidebarStylesHeaderRef} <button
id='sidebarStyles' ref={this.sidebarStylesHeaderRef}
className='theme-elements__header' id='sidebarStylesAccordion'
onClick={this.toggleSidebarStyles} onClick={this.toggleSidebarStyles}
> aria-expanded={false}
<FormattedMessage aria-controls='sidebarStylesSection'
id='user.settings.custom_theme.sidebarTitle' className='theme-elements__header'
defaultMessage='Sidebar Styles' >
/> <FormattedMessage
<div className='header__icon'> id='user.settings.custom_theme.sidebarTitle'
<i defaultMessage='Sidebar Styles'
className='fa fa-plus'
title={intl.formatMessage({id: 'generic_icons.expand', defaultMessage: 'Expand Icon'})}
/> />
<i <div className='header__icon'>
className='fa fa-minus' <i
title={intl.formatMessage({id: 'generic_icons.collapse', defaultMessage: 'Collapse Icon'})} className='fa fa-plus'
/> aria-hidden={true}
</div> title={intl.formatMessage({id: 'generic_icons.expand', defaultMessage: 'Expand Icon'})}
</div> />
<i
className='fa fa-minus'
aria-hidden={true}
title={intl.formatMessage({id: 'generic_icons.collapse', defaultMessage: 'Collapse Icon'})}
/>
</div>
</button>
</h4>
<div <div
ref={this.sidebarStylesRef} ref={this.sidebarStylesRef}
id='sidebarStylesSection'
aria-labelledby='sidebarStylesAccordion'
className='theme-elements__body' className='theme-elements__body'
> >
{sidebarElements} {sidebarElements}
</div> </div>
</div> </div>
<div className='theme-elements row'> <div className='theme-elements row'>
<div <h4 className='theme-elements__header'>
ref={this.centerChannelStylesHeaderRef} <button
id='centerChannelStyles' ref={this.centerChannelStylesHeaderRef}
className='theme-elements__header' id='centerChannelStylesAccordion'
onClick={this.toggleCenterChannelStyles} onClick={this.toggleCenterChannelStyles}
> aria-expanded={false}
<FormattedMessage aria-controls='centerChannelStylesSection'
id='user.settings.custom_theme.centerChannelTitle' className='theme-elements__header'
defaultMessage='Center Channel Styles' >
/> <FormattedMessage
<div className='header__icon'> id='user.settings.custom_theme.centerChannelTitle'
<i defaultMessage='Center Channel Styles'
className='fa fa-plus'
title={intl.formatMessage({id: 'generic_icons.expand', defaultMessage: 'Expand Icon'})}
/> />
<i <div className='header__icon'>
className='fa fa-minus' <i
title={intl.formatMessage({id: 'generic_icons.collapse', defaultMessage: 'Collapse Icon'})} className='fa fa-plus'
/> aria-hidden={true}
</div> title={intl.formatMessage({id: 'generic_icons.expand', defaultMessage: 'Expand Icon'})}
</div> />
<i
className='fa fa-minus'
aria-hidden={true}
title={intl.formatMessage({id: 'generic_icons.collapse', defaultMessage: 'Collapse Icon'})}
/>
</div>
</button>
</h4>
<div <div
ref={this.centerChannelStylesRef} ref={this.centerChannelStylesRef}
id='centerChannelStyles' id='centerChannelStylesSection'
className='theme-elements__body' className='theme-elements__body'
aria-labelledby='centerChannelStylesAccordion'
> >
{centerChannelElements} {centerChannelElements}
</div> </div>
</div> </div>
<div className='theme-elements row'> <div className='theme-elements row'>
<div <h4 className='theme-elements__header'>
ref={this.linkAndButtonStylesHeaderRef} <button
id='linkAndButtonsStyles' ref={this.linkAndButtonStylesHeaderRef}
className='theme-elements__header' id='linkAndButtonsStylesAccordion'
onClick={this.toggleLinkAndButtonStyles} onClick={this.toggleLinkAndButtonStyles}
> aria-expanded={false}
<FormattedMessage aria-controls='linkAndButtonsStylesSection'
id='user.settings.custom_theme.linkButtonTitle' className='theme-elements__header'
defaultMessage='Link and Button Styles' >
/> <FormattedMessage
<div className='header__icon'> id='user.settings.custom_theme.linkButtonTitle'
<i defaultMessage='Link and Button Styles'
className='fa fa-plus'
title={intl.formatMessage({id: 'generic_icons.expand', defaultMessage: 'Expand Icon'})}
/> />
<i <div className='header__icon'>
className='fa fa-minus' <i
title={intl.formatMessage({id: 'generic_icons.collapse', defaultMessage: 'Collapse Icon'})} className='fa fa-plus'
/> aria-hidden={true}
</div> title={intl.formatMessage({id: 'generic_icons.expand', defaultMessage: 'Expand Icon'})}
</div> />
<i
className='fa fa-minus'
aria-hidden={true}
title={intl.formatMessage({id: 'generic_icons.collapse', defaultMessage: 'Collapse Icon'})}
/>
</div>
</button>
</h4>
<div <div
id='linkAndButtonsStylesSection'
ref={this.linkAndButtonStylesRef} ref={this.linkAndButtonStylesRef}
className='theme-elements__body' className='theme-elements__body'
aria-labelledby='linkAndButtonsStylesAccordion'
> >
{linkAndButtonElements} {linkAndButtonElements}
</div> </div>

Просмотреть файл

@@ -39,9 +39,9 @@ const PremadeThemeChooser = ({theme, updateTheme, allowedThemes = []}: Props) =>
className='col-xs-6 col-sm-3 premade-themes' className='col-xs-6 col-sm-3 premade-themes'
key={'premade-theme-key' + k} key={'premade-theme-key' + k}
> >
<div <button
id={`premadeTheme${premadeTheme.type?.replace(' ', '')}`} id={`premadeTheme${premadeTheme.type?.replace(' ', '')}`}
className={activeClass} className={`premadeThemeButton ${activeClass}`}
onClick={() => updateTheme(premadeTheme)} onClick={() => updateTheme(premadeTheme)}
> >
<label> <label>
@@ -61,14 +61,18 @@ const PremadeThemeChooser = ({theme, updateTheme, allowedThemes = []}: Props) =>
/> />
<div className='theme-label'>{toTitleCase(premadeTheme.type || '')}</div> <div className='theme-label'>{toTitleCase(premadeTheme.type || '')}</div>
</label> </label>
</div> </button>
</div>, </div>,
); );
} }
} }
return ( return (
<div className='row appearance-section'> <div
id='premadeThemesSection'
className='row appearance-section'
aria-labelledby='standardThemes'
>
<div className='clearfix'> <div className='clearfix'>
{premadeThemes} {premadeThemes}
</div> </div>

Просмотреть файл

@@ -195,6 +195,7 @@ export default class ThemeSetting extends React.PureComponent<Props, State> {
name='theme' name='theme'
checked={!displayCustom} checked={!displayCustom}
onChange={this.updateType.bind(this, 'premade')} onChange={this.updateType.bind(this, 'premade')}
aria-controls='premadeThemesSection'
/> />
<FormattedMessage <FormattedMessage
id='user.settings.display.theme.themeColors' id='user.settings.display.theme.themeColors'
@@ -206,8 +207,6 @@ export default class ThemeSetting extends React.PureComponent<Props, State> {
); );
} }
inputs.push(premade);
if (this.props.allowCustomThemes) { if (this.props.allowCustomThemes) {
inputs.push( inputs.push(
<div <div
@@ -221,6 +220,7 @@ export default class ThemeSetting extends React.PureComponent<Props, State> {
name='theme' name='theme'
checked={displayCustom} checked={displayCustom}
onChange={this.updateType.bind(this, 'custom')} onChange={this.updateType.bind(this, 'custom')}
aria-controls='customThemesSection'
/> />
<FormattedMessage <FormattedMessage
id='user.settings.display.theme.customTheme' id='user.settings.display.theme.customTheme'
@@ -230,7 +230,7 @@ export default class ThemeSetting extends React.PureComponent<Props, State> {
</div>, </div>,
); );
inputs.push(custom); inputs.push(premade, custom);
inputs.push( inputs.push(
<div key='otherThemes'> <div key='otherThemes'>
@@ -271,7 +271,19 @@ export default class ThemeSetting extends React.PureComponent<Props, State> {
themeUI = ( themeUI = (
<SettingItemMax <SettingItemMax
inputs={inputs} inputs={
<fieldset>
<legend className='hidden-label'>
<FormattedMessage
id='user.settings.display.theme.title'
defaultMessage='Theme'
/>
</legend>
<div>
{inputs}
</div>
</fieldset>
}
submitExtra={allTeamsCheckbox} submitExtra={allTeamsCheckbox}
submit={this.submitTheme} submit={this.submitTheme}
disableEnterSubmit={true} disableEnterSubmit={true}

Просмотреть файл

@@ -371,6 +371,11 @@
white-space: nowrap; white-space: nowrap;
} }
.premadeThemeButton{
border: none;
background: none;
}
label { label {
width: 100%; width: 100%;
} }
@@ -407,13 +412,22 @@
} }
.theme-elements__header { .theme-elements__header {
padding: 1px 0 10px;
border-bottom: 1px solid; border-bottom: 1px solid;
margin: 10px 20px 0 0; margin: 10px 20px 0 0;
cursor: pointer; cursor: pointer;
font-size: functions.em(13.5px); font-size: functions.em(13.5px);
font-weight: 600; font-weight: 600;
button {
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
padding: 10px 1px;
border: none;
background: none;
}
.fa-minus { .fa-minus {
display: none; display: none;
} }