Merge remote-tracking branch 'origin/develop' into react-any-emoji

This commit is contained in:
Alex Gleason
2023-02-12 20:30:33 -06:00
64 changed files with 586 additions and 1915 deletions

View File

@@ -4,9 +4,8 @@ import { defineMessages, useIntl } from 'react-intl';
import { expandUserIndex, fetchUserIndex, setUserIndexQuery } from 'soapbox/actions/admin';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Column } from 'soapbox/components/ui';
import { Column, Input } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import { SimpleForm, TextInput } from 'soapbox/features/forms';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
const messages = defineMessages({
@@ -22,7 +21,7 @@ const UserIndex: React.FC = () => {
const { isLoading, items, total, query, next } = useAppSelector((state) => state.admin_user_index);
const handleLoadMore = () => {
dispatch(expandUserIndex());
if (!isLoading) dispatch(expandUserIndex());
};
const updateQuery = useCallback(debounce(() => {
@@ -31,25 +30,25 @@ const UserIndex: React.FC = () => {
const handleQueryChange: React.ChangeEventHandler<HTMLInputElement> = e => {
dispatch(setUserIndexQuery(e.target.value));
updateQuery();
};
useEffect(() => {
updateQuery();
}, [query]);
}, []);
const hasMore = items.count() < total && next !== null;
const hasMore = items.count() < total && !!next;
const showLoading = isLoading && items.isEmpty();
return (
<Column label={intl.formatMessage(messages.heading)}>
<SimpleForm style={{ paddingBottom: 0 }}>
<TextInput
value={query}
onChange={handleQueryChange}
placeholder={intl.formatMessage(messages.searchPlaceholder)}
/>
</SimpleForm>
<Input
value={query}
onChange={handleQueryChange}
placeholder={intl.formatMessage(messages.searchPlaceholder)}
/>
<ScrollableList
scrollKey='user-index'
hasMore={hasMore}

View File

@@ -581,4 +581,4 @@ const Audio: React.FC<IAudio> = (props) => {
);
};
export default Audio;
export default Audio;

View File

@@ -42,6 +42,7 @@ interface IChatComposer extends Pick<React.TextareaHTMLAttributes<HTMLTextAreaEl
errorMessage: string | undefined
onSelectFile: (files: FileList, intl: IntlShape) => void
resetFileKey: number | null
resetContentKey: number | null
attachments?: Attachment[]
onDeleteAttachment?: () => void
isUploading?: boolean
@@ -58,6 +59,7 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
disabled = false,
onSelectFile,
resetFileKey,
resetContentKey,
onPaste,
attachments = [],
onDeleteAttachment,
@@ -179,6 +181,7 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
<Stack grow>
<Combobox onSelect={onSelectComboboxOption}>
<ComboboxInput
key={resetContentKey}
as={ChatTextarea}
autoFocus
ref={ref}
@@ -250,4 +253,4 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
);
});
export default ChatComposer;
export default ChatComposer;

View File

@@ -54,6 +54,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
const [attachment, setAttachment] = useState<any>(undefined);
const [isUploading, setIsUploading] = useState(false);
const [uploadProgress, setUploadProgress] = useState(0);
const [resetContentKey, setResetContentKey] = useState<number>(fileKeyGen());
const [resetFileKey, setResetFileKey] = useState<number>(fileKeyGen());
const [errorMessage, setErrorMessage] = useState<string>();
@@ -83,6 +84,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
setIsUploading(false);
setUploadProgress(0);
setResetFileKey(fileKeyGen());
setResetContentKey(fileKeyGen());
};
const sendMessage = () => {
@@ -171,6 +173,7 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
errorMessage={errorMessage}
onSelectFile={handleFiles}
resetFileKey={resetFileKey}
resetContentKey={resetContentKey}
onPaste={handlePaste}
attachments={attachment ? [attachment] : []}
onDeleteAttachment={handleRemoveFile}

View File

@@ -242,7 +242,10 @@ const PrivacyDropdown: React.FC<IPrivacyDropdown> = ({
<div className={clsx('privacy-dropdown', placement, { active: open })} onKeyDown={handleKeyDown} ref={node}>
<div className={clsx('privacy-dropdown__value', { active: valueOption && options.indexOf(valueOption) === 0 })}>
<IconButton
className='text-gray-600 hover:text-gray-700 dark:hover:text-gray-500'
className={clsx({
'text-gray-600 hover:text-gray-700 dark:hover:text-gray-500': !open,
'text-primary-500 hover:text-primary-600 dark:text-primary-500 dark:hover:text-primary-400': open,
})}
src={valueOption?.icon}
title={intl.formatMessage(messages.change_privacy)}
onClick={handleToggle}

View File

@@ -1,3 +1,4 @@
import clsx from 'clsx';
import React from 'react';
import AttachmentThumbs from 'soapbox/components/attachment-thumbs';
@@ -8,12 +9,13 @@ import { isRtl } from 'soapbox/rtl';
import type { Status } from 'soapbox/types/entities';
interface IReplyIndicator {
className?: string,
status?: Status,
onCancel?: () => void,
hideActions: boolean,
}
const ReplyIndicator: React.FC<IReplyIndicator> = ({ status, hideActions, onCancel }) => {
const ReplyIndicator: React.FC<IReplyIndicator> = ({ className, status, hideActions, onCancel }) => {
const handleClick = () => {
onCancel!();
};
@@ -33,7 +35,7 @@ const ReplyIndicator: React.FC<IReplyIndicator> = ({ status, hideActions, onCanc
}
return (
<Stack space={2} className='rounded-lg bg-gray-100 p-4 dark:bg-gray-800'>
<Stack space={2} className={clsx('rounded-lg bg-gray-100 p-4 dark:bg-gray-800', className)}>
<AccountContainer
{...actions}
id={status.getIn(['account', 'id']) as string}

View File

@@ -21,4 +21,4 @@ const Indicator: React.FC<IIndicator> = ({ state = 'inactive', size = 'sm' }) =>
);
};
export default Indicator;
export default Indicator;

View File

@@ -152,14 +152,14 @@ const ProfileField: StreamfieldComponent<AccountCredentialsField> = ({ value, on
<HStack space={2} grow>
<Input
type='text'
outerClassName='w-2/5 flex-grow'
outerClassName='w-2/5 grow'
value={value.name}
onChange={handleChange('name')}
placeholder={intl.formatMessage(messages.metaFieldLabel)}
/>
<Input
type='text'
outerClassName='w-3/5 flex-grow'
outerClassName='w-3/5 grow'
value={value.value}
onChange={handleChange('value')}
placeholder={intl.formatMessage(messages.metaFieldContent)}

View File

@@ -2,13 +2,9 @@ import React, { useEffect, useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { fetchFilters, createFilter, deleteFilter } from 'soapbox/actions/filters';
import Icon from 'soapbox/components/icon';
import List, { ListItem } from 'soapbox/components/list';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Button, CardHeader, CardTitle, Column, Form, FormActions, FormGroup, Input, Text } from 'soapbox/components/ui';
import {
FieldsGroup,
Checkbox,
} from 'soapbox/features/forms';
import { Button, CardHeader, CardTitle, Column, Form, FormActions, FormGroup, HStack, IconButton, Input, Stack, Text, Toggle } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import toast from 'soapbox/toast';
@@ -33,6 +29,13 @@ const messages = defineMessages({
delete: { id: 'column.filters.delete', defaultMessage: 'Delete' },
});
const contexts = {
home: messages.home_timeline,
public: messages.public_timeline,
notifications: messages.notifications,
thread: messages.conversations,
};
// const expirations = {
// null: 'Never',
// // 3600: '30 minutes',
@@ -85,8 +88,8 @@ const Filters = () => {
});
};
const handleFilterDelete: React.MouseEventHandler<HTMLDivElement> = e => {
dispatch(deleteFilter(e.currentTarget.dataset.value!)).then(() => {
const handleFilterDelete = (id: string) => () => {
dispatch(deleteFilter(id)).then(() => {
return dispatch(fetchFilters());
}).catch(() => {
toast.error(intl.formatMessage(messages.delete_error));
@@ -121,58 +124,68 @@ const Filters = () => {
/>
</FormGroup> */}
<FieldsGroup>
<Text tag='label'>
<Stack>
<Text size='sm' weight='medium'>
<FormattedMessage id='filters.context_header' defaultMessage='Filter contexts' />
</Text>
<Text theme='muted' size='xs'>
<Text size='xs' theme='muted'>
<FormattedMessage id='filters.context_hint' defaultMessage='One or multiple contexts where the filter should apply' />
</Text>
<div className='two-col'>
<Checkbox
label={intl.formatMessage(messages.home_timeline)}
</Stack>
<List>
<ListItem label={intl.formatMessage(messages.home_timeline)}>
<Toggle
name='home_timeline'
checked={homeTimeline}
onChange={({ target }) => setHomeTimeline(target.checked)}
/>
<Checkbox
label={intl.formatMessage(messages.public_timeline)}
</ListItem>
<ListItem label={intl.formatMessage(messages.public_timeline)}>
<Toggle
name='public_timeline'
checked={publicTimeline}
onChange={({ target }) => setPublicTimeline(target.checked)}
/>
<Checkbox
label={intl.formatMessage(messages.notifications)}
</ListItem>
<ListItem label={intl.formatMessage(messages.notifications)}>
<Toggle
name='notifications'
checked={notifications}
onChange={({ target }) => setNotifications(target.checked)}
/>
<Checkbox
label={intl.formatMessage(messages.conversations)}
</ListItem>
<ListItem label={intl.formatMessage(messages.conversations)}>
<Toggle
name='conversations'
checked={conversations}
onChange={({ target }) => setConversations(target.checked)}
/>
</div>
</ListItem>
</List>
</FieldsGroup>
<FieldsGroup>
<Checkbox
<List>
<ListItem
label={intl.formatMessage(messages.drop_header)}
hint={intl.formatMessage(messages.drop_hint)}
name='irreversible'
checked={irreversible}
onChange={({ target }) => setIrreversible(target.checked)}
/>
<Checkbox
>
<Toggle
name='irreversible'
checked={irreversible}
onChange={({ target }) => setIrreversible(target.checked)}
/>
</ListItem>
<ListItem
label={intl.formatMessage(messages.whole_word_header)}
hint={intl.formatMessage(messages.whole_word_hint)}
name='whole_word'
checked={wholeWord}
onChange={({ target }) => setWholeWord(target.checked)}
/>
</FieldsGroup>
>
<Toggle
name='whole_word'
checked={wholeWord}
onChange={({ target }) => setWholeWord(target.checked)}
/>
</ListItem>
</List>
<FormActions>
<Button type='submit' theme='primary'>{intl.formatMessage(messages.add_new)}</Button>
@@ -186,40 +199,41 @@ const Filters = () => {
<ScrollableList
scrollKey='filters'
emptyMessage={emptyMessage}
itemClassName='pb-4 last:pb-0'
>
{filters.map((filter, i) => (
<div key={i} className='filter__container'>
<div className='filter__details'>
<div className='filter__phrase'>
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_phrase_label' defaultMessage='Keyword or phrase:' /></span>
<span className='filter__list-value'>{filter.phrase}</span>
</div>
<div className='filter__contexts'>
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_context_label' defaultMessage='Filter contexts:' /></span>
<span className='filter__list-value'>
{filter.context.map((context, i) => (
<span key={i} className='context'>{context}</span>
))}
</span>
</div>
<div className='filter__details'>
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_details_label' defaultMessage='Filter settings:' /></span>
<span className='filter__list-value'>
<HStack space={1} justifyContent='between'>
<Stack space={1}>
<Text weight='medium'>
<FormattedMessage id='filters.filters_list_phrase_label' defaultMessage='Keyword or phrase:' />
{' '}
<Text theme='muted' tag='span'>{filter.phrase}</Text>
</Text>
<Text weight='medium'>
<FormattedMessage id='filters.filters_list_context_label' defaultMessage='Filter contexts:' />
{' '}
<Text theme='muted' tag='span'>{filter.context.map(context => contexts[context] ? intl.formatMessage(contexts[context]) : context).join(', ')}</Text>
</Text>
<HStack space={4}>
<Text weight='medium'>
{filter.irreversible ?
<span><FormattedMessage id='filters.filters_list_drop' defaultMessage='Drop' /></span> :
<span><FormattedMessage id='filters.filters_list_hide' defaultMessage='Hide' /></span>
}
{filter.whole_word &&
<span><FormattedMessage id='filters.filters_list_whole-word' defaultMessage='Whole word' /></span>
}
</span>
</div>
</div>
<div className='filter__delete' role='button' tabIndex={0} onClick={handleFilterDelete} data-value={filter.id} aria-label={intl.formatMessage(messages.delete)}>
<Icon className='filter__delete-icon' src={require('@tabler/icons/x.svg')} />
<span className='filter__delete-label'><FormattedMessage id='filters.filters_list_delete' defaultMessage='Delete' /></span>
</div>
</div>
<FormattedMessage id='filters.filters_list_drop' defaultMessage='Drop' /> :
<FormattedMessage id='filters.filters_list_hide' defaultMessage='Hide' />}
</Text>
{filter.whole_word && (
<Text weight='medium'>
<FormattedMessage id='filters.filters_list_whole-word' defaultMessage='Whole word' />
</Text>
)}
</HStack>
</Stack>
<IconButton
iconClassName='h-5 w-5 text-gray-700 dark:text-gray-600 hover:text-gray-800 dark:hover:text-gray-500'
src={require('@tabler/icons/trash.svg')}
onClick={handleFilterDelete(filter.id)}
title={intl.formatMessage(messages.delete)}
/>
</HStack>
))}
</ScrollableList>
</Column>

View File

@@ -103,71 +103,6 @@ export const SimpleInput: React.FC<ISimpleInput> = (props) => {
);
};
interface ISimpleTextarea {
label?: React.ReactNode,
hint?: React.ReactNode,
value?: string,
onChange?: React.ChangeEventHandler<HTMLTextAreaElement>,
rows?: number,
name?: string,
maxLength?: number,
required?: boolean,
}
export const SimpleTextarea: React.FC<ISimpleTextarea> = (props) => {
const { hint, label, ...rest } = props;
const Input = label ? LabelTextarea : 'textarea';
return (
<InputContainer {...props}>
<Input {...rest} />
</InputContainer>
);
};
interface ISimpleForm {
className?: string,
onSubmit?: React.FormEventHandler,
acceptCharset?: string,
style?: React.CSSProperties,
children: React.ReactNode,
}
export const SimpleForm: React.FC<ISimpleForm> = (props) => {
const {
className,
children,
onSubmit = () => {},
acceptCharset = 'UTF-8',
...rest
} = props;
const handleSubmit: React.FormEventHandler = e => {
onSubmit(e);
e.preventDefault();
};
return (
<form
className={clsx('simple_form', className)}
method='post'
onSubmit={handleSubmit}
acceptCharset={acceptCharset}
{...rest}
>
{children}
</form>
);
};
interface IFieldsGroup {
children: React.ReactNode,
}
export const FieldsGroup: React.FC<IFieldsGroup> = ({ children }) => (
<div className='fields-group'>{children}</div>
);
interface ICheckbox {
label?: React.ReactNode,
hint?: React.ReactNode,

View File

@@ -36,7 +36,7 @@ const ListForm = () => {
<Form onSubmit={handleSubmit}>
<HStack space={2}>
<Input
outerClassName='flex-grow'
outerClassName='grow'
type='text'
value={value}
onChange={handleChange}

View File

@@ -1,18 +0,0 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import Icon from 'soapbox/components/icon';
interface IClearColumnButton {
onClick: React.MouseEventHandler<HTMLButtonElement>;
}
const ClearColumnButton: React.FC<IClearColumnButton> = ({ onClick }) => (
<button className='text-btn column-header__setting-btn' tabIndex={0} onClick={onClick}>
<Icon src={require('@tabler/icons/eraser.svg')} />
{' '}
<FormattedMessage id='notifications.clear' defaultMessage='Clear notifications' />
</button>
);
export default ClearColumnButton;

View File

@@ -329,6 +329,7 @@ const Notification: React.FC<INotificaton> = (props) => {
onMoveDown={handleMoveDown}
onMoveUp={handleMoveUp}
avatarSize={avatarSize}
contextType='notifications'
/>
) : null;
default:

View File

@@ -78,7 +78,7 @@ const PlaceholderMediaGallery: React.FC<IPlaceholderMediaGallery> = ({ media, de
const float = dimensions.float as any || 'left';
const position = dimensions.pos as any || 'relative';
return <div key={i} className='media-gallery__item' style={{ position, float, left, top, right, bottom, height, width }} />;
return <div key={i} className='media-gallery__item animate-pulse bg-primary-200' style={{ position, float, left, top, right, bottom, height, width }} />;
};
const sizeData = getSizeData(media.size);

View File

@@ -1,58 +0,0 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { getSettings, changeSettingImmediate } from 'soapbox/actions/settings';
import List, { ListItem } from 'soapbox/components/list';
import { Card, CardBody, CardHeader, CardTitle } from 'soapbox/components/ui';
import { SimpleForm, SelectDropdown } from 'soapbox/features/forms';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
const messages = defineMessages({
mediaDisplay: { id: 'preferences.fields.media_display_label', defaultMessage: 'Media display' },
display_media_default: { id: 'preferences.fields.display_media.default', defaultMessage: 'Hide media marked as sensitive' },
display_media_hide_all: { id: 'preferences.fields.display_media.hide_all', defaultMessage: 'Always hide media' },
display_media_show_all: { id: 'preferences.fields.display_media.show_all', defaultMessage: 'Always show media' },
});
const MediaDisplay = () => {
const dispatch = useAppDispatch();
const intl = useIntl();
const settings = useAppSelector((state) => getSettings(state));
const displayMediaOptions = {
default: intl.formatMessage(messages.display_media_default),
hide_all: intl.formatMessage(messages.display_media_hide_all),
show_all: intl.formatMessage(messages.display_media_show_all),
};
const onSelectChange: (path: string[]) => React.ChangeEventHandler<HTMLSelectElement> = path => {
return e => {
dispatch(changeSettingImmediate(path, e.target.value));
};
};
return (
<Card variant='rounded'>
<CardHeader>
<CardTitle title={intl.formatMessage(messages.mediaDisplay)} />
</CardHeader>
<CardBody>
<SimpleForm className='space-y-3 p-0'>
<List>
<ListItem label={intl.formatMessage(messages.mediaDisplay)}>
<SelectDropdown
items={displayMediaOptions}
defaultValue={settings.get('displayMedia') as string}
onChange={onSelectChange(['displayMedia'])}
/>
</ListItem>
</List>
</SimpleForm>
</CardBody>
</Card>
);
};
export default MediaDisplay;

View File

@@ -25,21 +25,21 @@ const CryptoAddressInput: StreamfieldComponent<CryptoAddress> = ({ value, onChan
<HStack space={2} grow>
<Input
type='text'
outerClassName='w-1/6 flex-grow'
outerClassName='w-1/6 grow'
value={value.ticker}
onChange={handleChange('ticker')}
placeholder={intl.formatMessage(messages.ticker)}
/>
<Input
type='text'
outerClassName='w-3/6 flex-grow'
outerClassName='w-3/6 grow'
value={value.address}
onChange={handleChange('address')}
placeholder={intl.formatMessage(messages.address)}
/>
<Input
type='text'
outerClassName='w-2/6 flex-grow'
outerClassName='w-2/6 grow'
value={value.note}
onChange={handleChange('note')}
placeholder={intl.formatMessage(messages.note)}

View File

@@ -24,14 +24,14 @@ const PromoPanelInput: StreamfieldComponent<FooterItem> = ({ value, onChange })
<HStack space={2} grow>
<Input
type='text'
outerClassName='w-full flex-grow'
outerClassName='w-full grow'
placeholder={intl.formatMessage(messages.label)}
value={value.title}
onChange={handleChange('title')}
/>
<Input
type='text'
outerClassName='w-full flex-grow'
outerClassName='w-full grow'
placeholder={intl.formatMessage(messages.url)}
value={value.url}
onChange={handleChange('url')}

View File

@@ -36,14 +36,14 @@ const PromoPanelInput: StreamfieldComponent<PromoPanelItem> = ({ value, onChange
<Input
type='text'
outerClassName='w-full flex-grow'
outerClassName='w-full grow'
placeholder={intl.formatMessage(messages.label)}
value={value.text}
onChange={handleChange('text')}
/>
<Input
type='text'
outerClassName='w-full flex-grow'
outerClassName='w-full grow'
placeholder={intl.formatMessage(messages.url)}
value={value.url}
onChange={handleChange('url')}

View File

@@ -1,4 +1,4 @@
import classnames from 'clsx';
import clsx from 'clsx';
import { List as ImmutableList } from 'immutable';
import React, { useState, useEffect } from 'react';
@@ -112,7 +112,7 @@ const Card: React.FC<ICard> = ({
const interactive = card.type !== 'link';
horizontal = typeof horizontal === 'boolean' ? horizontal : interactive || embedded;
const className = classnames('status-card', { horizontal, compact, interactive }, `status-card--${card.type}`);
const className = clsx('status-card', { horizontal, compact, interactive }, `status-card--${card.type}`);
const ratio = getRatio(card);
const height = (compact && !embedded) ? (width / (16 / 9)) : (width / ratio);
@@ -223,7 +223,7 @@ const Card: React.FC<ICard> = ({
);
} else if (card.image) {
embed = (
<div className={classnames(
<div className={clsx(
'status-card__image',
'w-full flex-none rounded-l md:h-auto md:w-auto md:flex-auto',
{

View File

@@ -8,6 +8,7 @@ import { useAppSelector } from 'soapbox/hooks';
interface IThreadStatus {
id: string,
contextType?: string,
focusedStatusId: string,
onMoveUp: (id: string) => void,
onMoveDown: (id: string) => void,

View File

@@ -361,6 +361,7 @@ const Thread: React.FC<IThread> = (props) => {
focusedStatusId={status!.id}
onMoveUp={handleMoveUp}
onMoveDown={handleMoveDown}
contextType='thread'
/>
);
};

View File

@@ -39,4 +39,4 @@ const FloatingActionButton: React.FC<IFloatingActionButton> = () => {
);
};
export default FloatingActionButton;
export default FloatingActionButton;

View File

@@ -162,4 +162,4 @@ class ImageLoader extends React.PureComponent<IImageLoader> {
}
export default ImageLoader;
export default ImageLoader;

View File

@@ -4,9 +4,8 @@ import { FormattedMessage } from 'react-intl';
import { spring } from 'react-motion';
import Icon from 'soapbox/components/icon';
import StatusContent from 'soapbox/components/status-content';
import { HStack, Stack } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import { HStack } from 'soapbox/components/ui';
import ReplyIndicator from 'soapbox/features/compose/components/reply-indicator';
import Motion from '../../util/optional-motion';
@@ -56,16 +55,7 @@ const ActionsModal: React.FC<IActionsModal> = ({ status, actions, onClick, onClo
{({ top }) => (
<div className='modal-root__modal actions-modal' style={{ top: `${top}%` }}>
{status && (
<Stack space={2} className='border-b border-solid border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-800'>
<AccountContainer
key={status.account as string}
id={status.account as string}
showProfileHoverCard={false}
withLinkToProfile={false}
timestamp={status.created_at}
/>
<StatusContent status={status} />
</Stack>
<ReplyIndicator className='actions-modal__status rounded-b-none' status={status} hideActions />
)}
<ul className={clsx({ 'with-status': !!status })}>

View File

@@ -3,7 +3,7 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import { useHistory } from 'react-router-dom';
import { remoteInteraction } from 'soapbox/actions/interactions';
import { Button, Modal, Stack, Text } from 'soapbox/components/ui';
import { Button, Form, Input, Modal, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector, useAppDispatch, useFeatures, useInstance, useRegistrationStatus } from 'soapbox/hooks';
import toast from 'soapbox/toast';
@@ -104,9 +104,8 @@ const UnauthorizedModal: React.FC<IUnauthorizedModal> = ({ action, onClose, acco
secondaryText={isOpen ? <FormattedMessage id='account.register' defaultMessage='Sign up' /> : undefined}
>
<div className='remote-interaction-modal__content'>
<form className='simple_form remote-interaction-modal__fields' onSubmit={onSubmit}>
<input
type='text'
<Form className='remote-interaction-modal__fields' onSubmit={onSubmit}>
<Input
placeholder={intl.formatMessage(messages.accountPlaceholder)}
name='remote_follow[acct]'
value={account}
@@ -116,7 +115,7 @@ const UnauthorizedModal: React.FC<IUnauthorizedModal> = ({ action, onClose, acco
required
/>
<Button type='submit' theme='primary'>{button}</Button>
</form>
</Form>
<div className='remote-interaction-modal__divider'>
<Text align='center'>
<FormattedMessage id='remote_interaction.divider' defaultMessage='or' />

View File

@@ -56,7 +56,7 @@ const UploadArea: React.FC<IUploadArea> = ({ active, onClose }) => {
<Stack space={3} justifyContent='center' alignItems='center'>
<Icon
src={require('@tabler/icons/cloud-upload.svg')}
className='h-12 w-12 text-white text-opacity-90'
className='h-12 w-12 text-white/90'
/>
<Text size='xl' theme='white'>

View File

@@ -72,7 +72,6 @@ import {
Lists,
Bookmarks,
Settings,
MediaDisplay,
EditProfile,
EditEmail,
EditPassword,
@@ -301,7 +300,6 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
<WrappedRoute path='/settings/email' page={DefaultPage} component={EditEmail} content={children} />
<WrappedRoute path='/settings/password' page={DefaultPage} component={EditPassword} content={children} />
<WrappedRoute path='/settings/account' page={DefaultPage} component={DeleteAccount} content={children} />
<WrappedRoute path='/settings/media_display' page={DefaultPage} component={MediaDisplay} content={children} />
<WrappedRoute path='/settings/mfa' page={DefaultPage} component={MfaForm} exact />
<WrappedRoute path='/settings/tokens' page={DefaultPage} component={AuthTokenList} content={children} />
<WrappedRoute path='/settings' page={DefaultPage} component={Settings} content={children} />

View File

@@ -238,10 +238,6 @@ export function Settings() {
return import(/* webpackChunkName: "features/settings" */'../../settings');
}
export function MediaDisplay() {
return import(/* webpackChunkName: "features/settings" */'../../settings/media-display');
}
export function EditProfile() {
return import(/* webpackChunkName: "features/edit_profile" */'../../edit-profile');
}