mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-12 00:46:13 -05:00
Composer redesign: Quote modal (#40437)
This commit is contained in:
@@ -15,6 +15,8 @@ import {
|
||||
createAppThunk,
|
||||
} from '@/mastodon/store/typed_functions';
|
||||
|
||||
import { isRedesignEnabled } from '../utils/environment';
|
||||
|
||||
import { showAlert } from './alerts';
|
||||
import { changeCompose, focusCompose, uploadCompose } from './compose';
|
||||
import { importFetchedStatuses } from './importer';
|
||||
@@ -170,6 +172,8 @@ export const quoteComposeByStatus = createAppThunk(
|
||||
false,
|
||||
);
|
||||
|
||||
const statusId = status.get('id') as string;
|
||||
|
||||
if (composeState.get('id')) {
|
||||
dispatch(showAlert({ message: messages.quoteErrorEdit }));
|
||||
} else if (composeState.get('privacy') === 'direct') {
|
||||
@@ -202,6 +206,17 @@ export const quoteComposeByStatus = createAppThunk(
|
||||
modalProps: { status },
|
||||
}),
|
||||
);
|
||||
} else if (
|
||||
composeState.get('in_reply_to') &&
|
||||
statusId &&
|
||||
isRedesignEnabled()
|
||||
) {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'COMPOSER_ADD_QUOTE',
|
||||
modalProps: { statusId },
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
dispatch(quoteCompose(status));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
@include mixins.elevation-1;
|
||||
|
||||
border-radius: var(--radius-xl);
|
||||
box-sizing: border-box;
|
||||
background: var(--color-bg-primary);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -50,3 +51,8 @@
|
||||
.actionsRight {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.actionsVertical {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ export const ModalTitle: React.FC<
|
||||
return title;
|
||||
};
|
||||
|
||||
export const ModalActions = <As extends React.ElementType>({
|
||||
export const ModalActions = <As extends React.ElementType = 'div'>({
|
||||
align,
|
||||
as: asComp,
|
||||
children,
|
||||
@@ -110,7 +110,7 @@ export const ModalActions = <As extends React.ElementType>({
|
||||
...props
|
||||
}: PolymorphicProps<
|
||||
{
|
||||
align?: 'left' | 'right' | 'stretch';
|
||||
align?: 'left' | 'right' | 'stretch' | 'vertical';
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
},
|
||||
@@ -126,6 +126,7 @@ export const ModalActions = <As extends React.ElementType>({
|
||||
classes.actions,
|
||||
align === 'left' && classes.actionsLeft,
|
||||
align === 'right' && classes.actionsRight,
|
||||
align === 'vertical' && classes.actionsVertical,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -78,5 +78,4 @@ const AnnualReportModal: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default AnnualReportModal;
|
||||
|
||||
@@ -69,5 +69,4 @@ const ComposerModalCancelConfirm: React.FC<{ openNew?: boolean }> = ({
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export -- Modals import from default
|
||||
export default ComposerModalCancelConfirm;
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { resetCompose } from '@/mastodon/actions/compose';
|
||||
import { quoteCompose } from '@/mastodon/actions/compose_typed';
|
||||
import { closeModal } from '@/mastodon/actions/modal';
|
||||
import { Button } from '@/mastodon/components/button/redesign';
|
||||
import {
|
||||
ModalShell,
|
||||
ModalActions,
|
||||
ModalTitle,
|
||||
} from '@/mastodon/components/modal_shell/redesign';
|
||||
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
|
||||
|
||||
const ComposerQuoteAddConfirm: React.FC<{ statusId: string }> = ({
|
||||
statusId,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const status = useAppSelector((state) => state.statuses.get(statusId));
|
||||
const handleClose = useCallback(() => {
|
||||
dispatch(
|
||||
closeModal({
|
||||
modalType: 'COMPOSER_ADD_QUOTE',
|
||||
ignoreFocus: true,
|
||||
}),
|
||||
);
|
||||
}, [dispatch]);
|
||||
const handleAdd = useCallback(() => {
|
||||
if (status) {
|
||||
dispatch(quoteCompose(status));
|
||||
}
|
||||
handleClose();
|
||||
}, [dispatch, handleClose, status]);
|
||||
const handleDelete = useCallback(() => {
|
||||
dispatch(resetCompose());
|
||||
handleAdd();
|
||||
}, [dispatch, handleAdd]);
|
||||
|
||||
return (
|
||||
<ModalShell maxWidth={400}>
|
||||
<ModalTitle>
|
||||
<FormattedMessage
|
||||
id='compose.quote_modal.title'
|
||||
defaultMessage='Draft in progress'
|
||||
/>
|
||||
</ModalTitle>
|
||||
|
||||
<FormattedMessage
|
||||
id='compose.cancel_modal.body'
|
||||
defaultMessage='You have a draft already in progress. What would you like to do?'
|
||||
/>
|
||||
|
||||
<ModalActions align='vertical'>
|
||||
<Button variant='solid' onClick={handleAdd}>
|
||||
<FormattedMessage
|
||||
id='compose.quote_modal.add'
|
||||
defaultMessage='Add quote to existing draft'
|
||||
/>
|
||||
</Button>
|
||||
<Button variant='solid' color='destructive' onClick={handleDelete}>
|
||||
<FormattedMessage
|
||||
id='compose.quote_modal.delete'
|
||||
defaultMessage='Delete draft and start a new post'
|
||||
/>
|
||||
</Button>
|
||||
<Button variant='ghost' onClick={handleClose}>
|
||||
<FormattedMessage
|
||||
id='compose.quote_modal.cancel'
|
||||
defaultMessage='Go back'
|
||||
/>
|
||||
</Button>
|
||||
</ModalActions>
|
||||
</ModalShell>
|
||||
);
|
||||
};
|
||||
|
||||
export default ComposerQuoteAddConfirm;
|
||||
@@ -189,5 +189,4 @@ const ComposeRearrangeItemDisplay: React.FC<
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export -- Modals import from default
|
||||
export default ComposerModalRearrange;
|
||||
|
||||
@@ -67,5 +67,4 @@ const ComposerModalSwitch: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default ComposerModalSwitch;
|
||||
|
||||
@@ -44,5 +44,4 @@ const HashtagSettingsModal: React.FC<{ columnId: string; tagId: string }> = ({
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default HashtagSettingsModal;
|
||||
|
||||
@@ -40,5 +40,4 @@ const NotificationSettingsModal: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default NotificationSettingsModal;
|
||||
|
||||
@@ -74,5 +74,4 @@ const AudioModal: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default AudioModal;
|
||||
|
||||
@@ -97,14 +97,14 @@ export const BlockModal = ({ accountId, acct }) => {
|
||||
|
||||
<div className='safety-action-modal__actions'>
|
||||
{domain && (
|
||||
<button onClick={handleToggleLearnMore} className='link-button'>
|
||||
<button type='button' onClick={handleToggleLearnMore} className='link-button'>
|
||||
{expanded ? <FormattedMessage id='block_modal.show_less' defaultMessage='Show less' /> : <FormattedMessage id='block_modal.show_more' defaultMessage='Show more' />}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<div className='spacer' />
|
||||
|
||||
<button onClick={handleCancel} className='link-button'>
|
||||
<button type='button' onClick={handleCancel} className='link-button'>
|
||||
<FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
|
||||
</button>
|
||||
|
||||
|
||||
@@ -218,5 +218,4 @@ export const DomainBlockModal: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default DomainBlockModal;
|
||||
|
||||
@@ -115,5 +115,4 @@ const EmbedModal: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default EmbedModal;
|
||||
|
||||
@@ -92,11 +92,11 @@ export const IgnoreNotificationsModal = ({ filterType }) => {
|
||||
|
||||
<div className='spacer' />
|
||||
|
||||
<button onClick={handleCancel} className='link-button'>
|
||||
<button type='button' onClick={handleCancel} className='link-button'>
|
||||
<FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
|
||||
</button>
|
||||
|
||||
<button onClick={handleClick} className='link-button'>
|
||||
<button type='button' onClick={handleClick} className='link-button'>
|
||||
<FormattedMessage id='ignore_notifications_modal.ignore' defaultMessage='Ignore notifications' />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -109,11 +109,12 @@ export const MODAL_COMPONENTS = {
|
||||
'COMPOSER_DRAFT_DELETE': () => import('@/mastodon/features/compose/redesign/modal_cancel'),
|
||||
'COMPOSER_REARRANGE': () => import('@/mastodon/features/compose/redesign/modal_rearrange'),
|
||||
'COMPOSER_SWITCH_TO_POST': () => import('@/mastodon/features/compose/redesign/modal_switch'),
|
||||
'COMPOSER_ADD_QUOTE': () => import('@/mastodon/features/compose/redesign/modal_quote'),
|
||||
'NOTIFICATION_SETTINGS': () => import('@/mastodon/features/notifications_v2/components/notification_settings_modal'),
|
||||
'HASHTAG_SETTINGS': () => import('@/mastodon/features/hashtag_timeline/components/column_settings_modal'),
|
||||
};
|
||||
|
||||
/** @arg {keyof import('@/mastodon/features/account_edit/modals')} type */
|
||||
/** @param {keyof import('@/mastodon/features/account_edit/modals')} type */
|
||||
function accountEditModal(type) {
|
||||
return () => import('@/mastodon/features/account_edit/modals').then(module => ({ default: module[type] }));
|
||||
}
|
||||
|
||||
@@ -131,13 +131,13 @@ export const MuteModal = ({ accountId, acct }) => {
|
||||
</div>
|
||||
|
||||
<div className='safety-action-modal__actions'>
|
||||
<button onClick={handleToggleSettings} className='link-button'>
|
||||
<button type='button' onClick={handleToggleSettings} className='link-button'>
|
||||
{expanded ? <FormattedMessage id='mute_modal.hide_options' defaultMessage='Hide options' /> : <FormattedMessage id='mute_modal.show_options' defaultMessage='Show options' />}
|
||||
</button>
|
||||
|
||||
<div className='spacer' />
|
||||
|
||||
<button onClick={handleCancel} className='link-button'>
|
||||
<button type='button' onClick={handleCancel} className='link-button'>
|
||||
<FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
|
||||
</button>
|
||||
|
||||
|
||||
@@ -545,6 +545,10 @@
|
||||
"compose.quote.audio": "Audio file {duration}",
|
||||
"compose.quote.poll": "Poll {sep} {isOpen, select, open {Accepting responses} other {Closed}}",
|
||||
"compose.quote.spoiler": "Content:",
|
||||
"compose.quote_modal.add": "Add quote to existing draft",
|
||||
"compose.quote_modal.cancel": "Go back",
|
||||
"compose.quote_modal.delete": "Delete draft and start a new post",
|
||||
"compose.quote_modal.title": "Draft in progress",
|
||||
"compose.rearrange_modal.cancel": "Cancel",
|
||||
"compose.rearrange_modal.drag_cancel": "Dragging was cancelled. Attachment index {item, number} was dropped.",
|
||||
"compose.rearrange_modal.drag_end": "Attachment index {item, number} was moved to index {over, number}.",
|
||||
|
||||
@@ -342,6 +342,12 @@ export default tseslint.config([
|
||||
'@typescript-eslint/non-nullable-type-assertion-style': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*modal*.{j,t}sx'],
|
||||
rules: {
|
||||
'import/no-default-export': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/__tests__/*.js', '**/__tests__/*.jsx'],
|
||||
|
||||
|
||||
Reference in New Issue
Block a user