Profile editing: Tab display controls (#37994)

This commit is contained in:
Echo
2026-02-27 14:36:19 +01:00
committed by GitHub
parent 6b88dd4923
commit d69d7c0507
6 changed files with 253 additions and 2 deletions

View File

@@ -0,0 +1,122 @@
import type { ChangeEventHandler, FC } from 'react';
import { useCallback } from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import { Callout } from '@/mastodon/components/callout';
import { ToggleField } from '@/mastodon/components/form_fields';
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
import { patchProfile } from '@/mastodon/reducers/slices/profile_edit';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import type { DialogModalProps } from '../../ui/components/dialog_modal';
import { DialogModal } from '../../ui/components/dialog_modal';
import { messages } from '../index';
import classes from '../styles.module.scss';
export const ProfileDisplayModal: FC<DialogModalProps> = ({ onClose }) => {
const intl = useIntl();
const { profile, isPending } = useAppSelector((state) => state.profileEdit);
const serverName = useAppSelector(
(state) => state.meta.get('domain') as string,
);
const dispatch = useAppDispatch();
const handleToggleChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(event) => {
const { name, checked } = event.target;
void dispatch(patchProfile({ [name]: checked }));
},
[dispatch],
);
if (!profile) {
return <LoadingIndicator />;
}
return (
<DialogModal
onClose={onClose}
title={intl.formatMessage(messages.profileTabTitle)}
noCancelButton
>
<div className={classes.toggleInputWrapper}>
<ToggleField
checked={profile.showMedia}
onChange={handleToggleChange}
disabled={isPending}
name='show_media'
label={
<FormattedMessage
id='account_edit.profile_tab.show_media.title'
defaultMessage='Show Media tab'
/>
}
hint={
<FormattedMessage
id='account_edit.profile_tab.show_media.description'
defaultMessage='Media is an optional tab that shows your posts containing images or videos.'
/>
}
/>
<ToggleField
checked={profile.showMediaReplies}
onChange={handleToggleChange}
disabled={!profile.showMedia || isPending}
name='show_media_replies'
label={
<FormattedMessage
id='account_edit.profile_tab.show_media_replies.title'
defaultMessage='Include replies on Media tab'
/>
}
hint={
<FormattedMessage
id='account_edit.profile_tab.show_media_replies.description'
defaultMessage='When enabled, Media tab shows both your posts and replies to other peoples posts.'
/>
}
/>
<ToggleField
checked={profile.showFeatured}
onChange={handleToggleChange}
disabled={isPending}
name='show_featured'
label={
<FormattedMessage
id='account_edit.profile_tab.show_featured.title'
defaultMessage='Show Featured tab'
/>
}
hint={
<FormattedMessage
id='account_edit.profile_tab.show_featured.description'
defaultMessage='Featured is an optional tab where you can showcase other accounts.'
/>
}
/>
</div>
<Callout
title={
<FormattedMessage
id='account_edit.profile_tab.hint.title'
defaultMessage='Displays still vary'
/>
}
icon={false}
>
<FormattedMessage
id='account_edit.profile_tab.hint.description'
defaultMessage='These settings customize what users see on {server} in the official apps, but they may not apply to users on other servers and 3rd party apps.'
values={{
server: serverName,
}}
/>
</Callout>
</DialogModal>
);
};

View File

@@ -1,13 +1,14 @@
import { useCallback, useEffect } from 'react';
import type { FC } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom';
import type { ModalType } from '@/mastodon/actions/modal';
import { openModal } from '@/mastodon/actions/modal';
import { Avatar } from '@/mastodon/components/avatar';
import { Button } from '@/mastodon/components/button';
import { CustomEmojiProvider } from '@/mastodon/components/emoji/context';
import { EmojiHTML } from '@/mastodon/components/emoji/html';
import { useElementHandledLink } from '@/mastodon/components/status/handled_link';
@@ -25,7 +26,7 @@ import { EditButton } from './components/edit_button';
import { AccountEditSection } from './components/section';
import classes from './styles.module.scss';
const messages = defineMessages({
export const messages = defineMessages({
columnTitle: {
id: 'account_edit.column_title',
defaultMessage: 'Edit Profile',
@@ -104,6 +105,9 @@ export const AccountEdit: FC = () => {
const handleBioEdit = useCallback(() => {
handleOpenModal('ACCOUNT_EDIT_BIO');
}, [handleOpenModal]);
const handleProfileDisplayEdit = useCallback(() => {
handleOpenModal('ACCOUNT_EDIT_PROFILE_DISPLAY');
}, [handleOpenModal]);
const history = useHistory();
const handleFeaturedTagsEdit = useCallback(() => {
@@ -193,6 +197,17 @@ export const AccountEdit: FC = () => {
title={messages.profileTabTitle}
description={messages.profileTabSubtitle}
showDescription
buttons={
<Button
className={classes.editButton}
onClick={handleProfileDisplayEdit}
>
<FormattedMessage
id='account_edit.profile_tab.button_label'
defaultMessage='Customize'
/>
</Button>
}
/>
</CustomEmojiProvider>
</AccountEditColumn>

View File

@@ -90,6 +90,16 @@ textarea.inputText {
}
}
.toggleInputWrapper {
> div {
padding: 12px 0;
&:not(:first-child) {
border-top: 1px solid var(--color-border-primary);
}
}
}
// Column component
.column {

View File

@@ -0,0 +1,94 @@
import type { FC, ReactNode } from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import classNames from 'classnames';
import { Button } from '@/mastodon/components/button';
import { IconButton } from '@/mastodon/components/icon_button';
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
export type { BaseConfirmationModalProps as DialogModalProps } from './confirmation_modals/confirmation_modal';
interface DialogModalProps {
className?: string;
title: ReactNode;
onClose: () => void;
description?: ReactNode;
formClassName?: string;
children?: ReactNode;
noCancelButton?: boolean;
onSave?: () => void;
saveLabel?: ReactNode;
}
export const DialogModal: FC<DialogModalProps> = ({
className,
title,
onClose,
description,
formClassName,
children,
noCancelButton = false,
onSave,
saveLabel,
}) => {
const intl = useIntl();
const showButtons = !noCancelButton || onSave;
return (
<div className={classNames('modal-root__modal dialog-modal', className)}>
<div className='dialog-modal__header'>
<IconButton
className='dialog-modal__header__close'
title={intl.formatMessage({
id: 'lightbox.close',
defaultMessage: 'Close',
})}
icon='close'
iconComponent={CloseIcon}
onClick={onClose}
/>
<h1 className='dialog-modal__header__title'>{title}</h1>
</div>
<div className='dialog-modal__content'>
{description && (
<div className='dialog-modal__content__description'>
{description}
</div>
)}
<div
className={classNames('dialog-modal__content__form', formClassName)}
>
{children}
</div>
</div>
{showButtons && (
<div className='dialog-modal__content__actions'>
{!noCancelButton && (
<Button onClick={onClose} secondary>
<FormattedMessage
id='confirmation_modal.cancel'
defaultMessage='Cancel'
/>
</Button>
)}
{onSave && (
<Button onClick={onClose}>
{saveLabel ?? (
<FormattedMessage
id='confirmation_modal.cancel'
defaultMessage='Cancel'
/>
)}
</Button>
)}
</div>
)}
</div>
);
};

View File

@@ -97,6 +97,7 @@ export const MODAL_COMPONENTS = {
'ACCOUNT_FIELD_OVERFLOW': () => import('@/mastodon/features/account_timeline/modals/field_modal').then(module => ({ default: module.AccountFieldModal })),
'ACCOUNT_EDIT_NAME': () => import('@/mastodon/features/account_edit/components/name_modal').then(module => ({ default: module.NameModal })),
'ACCOUNT_EDIT_BIO': () => import('@/mastodon/features/account_edit/components/bio_modal').then(module => ({ default: module.BioModal })),
'ACCOUNT_EDIT_PROFILE_DISPLAY': () => import('@/mastodon/features/account_edit/components/profile_display_modal').then(module => ({ default: module.ProfileDisplayModal })),
};
export default class ModalRoot extends PureComponent {

View File

@@ -161,6 +161,15 @@
"account_edit.featured_hashtags.title": "Featured hashtags",
"account_edit.name_modal.add_title": "Add display name",
"account_edit.name_modal.edit_title": "Edit display name",
"account_edit.profile_tab.button_label": "Customize",
"account_edit.profile_tab.hint.description": "These settings customize what users see on {server} in the official apps, but they may not apply to users on other servers and 3rd party apps.",
"account_edit.profile_tab.hint.title": "Displays still vary",
"account_edit.profile_tab.show_featured.description": "Featured is an optional tab where you can showcase other accounts.",
"account_edit.profile_tab.show_featured.title": "Show Featured tab",
"account_edit.profile_tab.show_media.description": "Media is an optional tab that shows your posts containing images or videos.",
"account_edit.profile_tab.show_media.title": "Show Media tab",
"account_edit.profile_tab.show_media_replies.description": "When enabled, Media tab shows both your posts and replies to other peoples posts.",
"account_edit.profile_tab.show_media_replies.title": "Include replies on Media tab",
"account_edit.profile_tab.subtitle": "Customize the tabs on your profile and what they display.",
"account_edit.profile_tab.title": "Profile tab settings",
"account_edit.save": "Save",