Merge remote-tracking branch 'origin/develop' into edit-group-page
This commit is contained in:
commit
9c78a37844
4 changed files with 43 additions and 15 deletions
|
@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Reactions: Support custom emoji reactions
|
||||
- Compatbility: Support Mastodon v2 timeline filters.
|
||||
- Posts: Support dislikes on Friendica.
|
||||
- UI: added a character counter to some textareas.
|
||||
|
||||
### Changed
|
||||
- Posts: truncate Nostr pubkeys in reply mentions.
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import clsx from 'clsx';
|
||||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import Stack from '../stack/stack';
|
||||
import Text from '../text/text';
|
||||
|
||||
interface ITextarea extends Pick<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'maxLength' | 'onChange' | 'onKeyDown' | 'onPaste' | 'required' | 'disabled' | 'rows' | 'readOnly'> {
|
||||
/** Put the cursor into the input on mount. */
|
||||
|
@ -28,6 +32,8 @@ interface ITextarea extends Pick<React.TextareaHTMLAttributes<HTMLTextAreaElemen
|
|||
isResizeable?: boolean
|
||||
/** Textarea theme. */
|
||||
theme?: 'default' | 'transparent'
|
||||
/** Whether to display a character counter below the textarea. */
|
||||
withCounter?: boolean
|
||||
}
|
||||
|
||||
/** Textarea with custom styles. */
|
||||
|
@ -40,8 +46,11 @@ const Textarea = React.forwardRef(({
|
|||
maxRows = 10,
|
||||
minRows = 1,
|
||||
theme = 'default',
|
||||
maxLength,
|
||||
value,
|
||||
...props
|
||||
}: ITextarea, ref: React.ForwardedRef<HTMLTextAreaElement>) => {
|
||||
const length = value?.length || 0;
|
||||
const [rows, setRows] = useState<number>(autoGrow ? 1 : 4);
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
|
@ -70,20 +79,35 @@ const Textarea = React.forwardRef(({
|
|||
};
|
||||
|
||||
return (
|
||||
<textarea
|
||||
{...props}
|
||||
ref={ref}
|
||||
rows={rows}
|
||||
onChange={handleChange}
|
||||
className={clsx('block w-full rounded-md text-gray-900 placeholder:text-gray-600 dark:text-gray-100 dark:placeholder:text-gray-600 sm:text-sm', {
|
||||
'bg-white dark:bg-transparent shadow-sm border-gray-400 dark:border-gray-800 dark:ring-1 dark:ring-gray-800 focus:ring-primary-500 focus:border-primary-500 dark:focus:ring-primary-500 dark:focus:border-primary-500':
|
||||
theme === 'default',
|
||||
'bg-transparent border-0 focus:border-0 focus:ring-0': theme === 'transparent',
|
||||
'font-mono': isCodeEditor,
|
||||
'text-red-600 border-red-600': hasError,
|
||||
'resize-none': !isResizeable,
|
||||
})}
|
||||
/>
|
||||
<Stack space={1.5}>
|
||||
<textarea
|
||||
{...props}
|
||||
value={value}
|
||||
ref={ref}
|
||||
rows={rows}
|
||||
onChange={handleChange}
|
||||
className={clsx('block w-full rounded-md text-gray-900 placeholder:text-gray-600 dark:text-gray-100 dark:placeholder:text-gray-600 sm:text-sm', {
|
||||
'bg-white dark:bg-transparent shadow-sm border-gray-400 dark:border-gray-800 dark:ring-1 dark:ring-gray-800 focus:ring-primary-500 focus:border-primary-500 dark:focus:ring-primary-500 dark:focus:border-primary-500':
|
||||
theme === 'default',
|
||||
'bg-transparent border-0 focus:border-0 focus:ring-0': theme === 'transparent',
|
||||
'font-mono': isCodeEditor,
|
||||
'text-red-600 border-red-600': hasError,
|
||||
'resize-none': !isResizeable,
|
||||
})}
|
||||
/>
|
||||
|
||||
{maxLength && (
|
||||
<div className='text-right rtl:text-left'>
|
||||
<Text size='xs' theme={maxLength - length < 0 ? 'danger' : 'muted'}>
|
||||
<FormattedMessage
|
||||
id='textarea.counter.label'
|
||||
defaultMessage='{count} characters remaining'
|
||||
values={{ count: maxLength - length }}
|
||||
/>
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -28,6 +28,7 @@ const messages = defineMessages({
|
|||
newsletter: { id: 'registration.newsletter', defaultMessage: 'Subscribe to newsletter.' },
|
||||
needsConfirmationHeader: { id: 'confirmations.register.needs_confirmation.header', defaultMessage: 'Confirmation needed' },
|
||||
needsApprovalHeader: { id: 'confirmations.register.needs_approval.header', defaultMessage: 'Approval needed' },
|
||||
reasonHint: { id: 'registration.reason_hint', defaultMessage: 'This will help us review your application' },
|
||||
});
|
||||
|
||||
interface IRegistrationForm {
|
||||
|
@ -296,13 +297,14 @@ const RegistrationForm: React.FC<IRegistrationForm> = ({ inviteToken }) => {
|
|||
{needsApproval && (
|
||||
<FormGroup
|
||||
labelText={<FormattedMessage id='registration.reason' defaultMessage='Why do you want to join?' />}
|
||||
hintText={<FormattedMessage id='registration.reason_hint' defaultMessage='This will help us review your application' />}
|
||||
>
|
||||
<Textarea
|
||||
name='reason'
|
||||
placeholder={intl.formatMessage(messages.reasonHint)}
|
||||
maxLength={500}
|
||||
onChange={onInputChange}
|
||||
value={params.get('reason', '')}
|
||||
autoGrow
|
||||
required
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -1481,6 +1481,7 @@
|
|||
"tabs_bar.profile": "Profile",
|
||||
"tabs_bar.search": "Search",
|
||||
"tabs_bar.settings": "Settings",
|
||||
"textarea.counter.label": "{count} characters remaining",
|
||||
"theme_editor.Reset": "Reset",
|
||||
"theme_editor.export": "Export theme",
|
||||
"theme_editor.import": "Import theme",
|
||||
|
|
Loading…
Reference in a new issue