Profile editing: Tab display controls (#37994)
This commit is contained in:
@@ -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 people’s 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import type { FC } 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 { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import type { ModalType } from '@/mastodon/actions/modal';
|
import type { ModalType } from '@/mastodon/actions/modal';
|
||||||
import { openModal } from '@/mastodon/actions/modal';
|
import { openModal } from '@/mastodon/actions/modal';
|
||||||
import { Avatar } from '@/mastodon/components/avatar';
|
import { Avatar } from '@/mastodon/components/avatar';
|
||||||
|
import { Button } from '@/mastodon/components/button';
|
||||||
import { CustomEmojiProvider } from '@/mastodon/components/emoji/context';
|
import { CustomEmojiProvider } from '@/mastodon/components/emoji/context';
|
||||||
import { EmojiHTML } from '@/mastodon/components/emoji/html';
|
import { EmojiHTML } from '@/mastodon/components/emoji/html';
|
||||||
import { useElementHandledLink } from '@/mastodon/components/status/handled_link';
|
import { useElementHandledLink } from '@/mastodon/components/status/handled_link';
|
||||||
@@ -25,7 +26,7 @@ import { EditButton } from './components/edit_button';
|
|||||||
import { AccountEditSection } from './components/section';
|
import { AccountEditSection } from './components/section';
|
||||||
import classes from './styles.module.scss';
|
import classes from './styles.module.scss';
|
||||||
|
|
||||||
const messages = defineMessages({
|
export const messages = defineMessages({
|
||||||
columnTitle: {
|
columnTitle: {
|
||||||
id: 'account_edit.column_title',
|
id: 'account_edit.column_title',
|
||||||
defaultMessage: 'Edit Profile',
|
defaultMessage: 'Edit Profile',
|
||||||
@@ -104,6 +105,9 @@ export const AccountEdit: FC = () => {
|
|||||||
const handleBioEdit = useCallback(() => {
|
const handleBioEdit = useCallback(() => {
|
||||||
handleOpenModal('ACCOUNT_EDIT_BIO');
|
handleOpenModal('ACCOUNT_EDIT_BIO');
|
||||||
}, [handleOpenModal]);
|
}, [handleOpenModal]);
|
||||||
|
const handleProfileDisplayEdit = useCallback(() => {
|
||||||
|
handleOpenModal('ACCOUNT_EDIT_PROFILE_DISPLAY');
|
||||||
|
}, [handleOpenModal]);
|
||||||
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const handleFeaturedTagsEdit = useCallback(() => {
|
const handleFeaturedTagsEdit = useCallback(() => {
|
||||||
@@ -193,6 +197,17 @@ export const AccountEdit: FC = () => {
|
|||||||
title={messages.profileTabTitle}
|
title={messages.profileTabTitle}
|
||||||
description={messages.profileTabSubtitle}
|
description={messages.profileTabSubtitle}
|
||||||
showDescription
|
showDescription
|
||||||
|
buttons={
|
||||||
|
<Button
|
||||||
|
className={classes.editButton}
|
||||||
|
onClick={handleProfileDisplayEdit}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='account_edit.profile_tab.button_label'
|
||||||
|
defaultMessage='Customize'
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</CustomEmojiProvider>
|
</CustomEmojiProvider>
|
||||||
</AccountEditColumn>
|
</AccountEditColumn>
|
||||||
|
|||||||
@@ -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 component
|
||||||
|
|
||||||
.column {
|
.column {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -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_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_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_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 {
|
export default class ModalRoot extends PureComponent {
|
||||||
|
|||||||
@@ -161,6 +161,15 @@
|
|||||||
"account_edit.featured_hashtags.title": "Featured hashtags",
|
"account_edit.featured_hashtags.title": "Featured hashtags",
|
||||||
"account_edit.name_modal.add_title": "Add display name",
|
"account_edit.name_modal.add_title": "Add display name",
|
||||||
"account_edit.name_modal.edit_title": "Edit 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 people’s 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.subtitle": "Customize the tabs on your profile and what they display.",
|
||||||
"account_edit.profile_tab.title": "Profile tab settings",
|
"account_edit.profile_tab.title": "Profile tab settings",
|
||||||
"account_edit.save": "Save",
|
"account_edit.save": "Save",
|
||||||
|
|||||||
Reference in New Issue
Block a user