nicolium: avoid useless jsx fragments
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -98,9 +98,8 @@ interface IProfilePopper {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const ProfilePopper: React.FC<IProfilePopper> = ({ condition, wrapper, children }) => (
|
||||
<>{condition ? wrapper(children) : children}</>
|
||||
);
|
||||
const ProfilePopper: React.FC<IProfilePopper> = ({ condition, wrapper, children }) =>
|
||||
condition ? wrapper(children) : children;
|
||||
|
||||
interface IAccount {
|
||||
account: AccountSchema;
|
||||
|
||||
@ -16,7 +16,7 @@ const Emoji: React.FC<IEmoji> = ({ emoji, emojiMap, hovered }) => {
|
||||
const { autoPlayGif, reduceMotion, systemEmojiFont } = useSettings();
|
||||
|
||||
if (unicodeMapping[emoji]) {
|
||||
if (systemEmojiFont) return <>{emoji}</>;
|
||||
if (systemEmojiFont) return emoji;
|
||||
|
||||
const { unified, shortcode } = unicodeMapping[emoji];
|
||||
const title = shortcode ? `:${shortcode}:` : '';
|
||||
|
||||
@ -21,7 +21,7 @@ const AutosuggestEmoji: React.FC<IAutosuggestEmoji> = ({ emoji }) => {
|
||||
<img className='emojione mr-2 block size-4' src={emoji.imageUrl} alt={emoji.colons} />
|
||||
);
|
||||
} else {
|
||||
if (systemEmojiFont) emojiElement = <>{emoji.native}</>;
|
||||
if (systemEmojiFont) emojiElement = emoji.native;
|
||||
|
||||
const mapping =
|
||||
unicodeMapping[emoji.native] || unicodeMapping[emoji.native.replace(/\uFE0F$/, '')];
|
||||
|
||||
@ -272,7 +272,7 @@ const ScrollableList = React.forwardRef<VirtuosoHandle, IScrollableList>(
|
||||
itemClassName,
|
||||
}}
|
||||
components={{
|
||||
Header: prepend ? () => <>{prepend}</> : undefined,
|
||||
Header: prepend ? () => prepend : undefined,
|
||||
ScrollSeekPlaceholder: Placeholder as React.ComponentType<any>,
|
||||
EmptyPlaceholder: renderEmpty,
|
||||
List,
|
||||
|
||||
@ -328,7 +328,7 @@ const StatusContent: React.FC<IStatusContent> = React.memo(
|
||||
if (onClick) {
|
||||
return <div className='⁂-status-content__container'>{output}</div>;
|
||||
} else {
|
||||
return <>{output}</>;
|
||||
return output;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@ -164,22 +164,20 @@ const StatusList: React.FC<IStatusList> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ScrollableList
|
||||
id='status-list'
|
||||
key='scrollable-list'
|
||||
isLoading={isLoading}
|
||||
showLoading={isLoading && statusIds.length === 0}
|
||||
onLoadMore={handleLoadOlder}
|
||||
placeholderComponent={() => <PlaceholderStatus variant='slim' />}
|
||||
placeholderCount={20}
|
||||
ref={node}
|
||||
listClassName={clsx('⁂-status-list', className)}
|
||||
{...other}
|
||||
>
|
||||
{scrollableContent}
|
||||
</ScrollableList>
|
||||
</>
|
||||
<ScrollableList
|
||||
id='status-list'
|
||||
key='scrollable-list'
|
||||
isLoading={isLoading}
|
||||
showLoading={isLoading && statusIds.length === 0}
|
||||
onLoadMore={handleLoadOlder}
|
||||
placeholderComponent={() => <PlaceholderStatus variant='slim' />}
|
||||
placeholderCount={20}
|
||||
ref={node}
|
||||
listClassName={clsx('⁂-status-list', className)}
|
||||
{...other}
|
||||
>
|
||||
{scrollableContent}
|
||||
</ScrollableList>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ interface IEmoji extends Pick<
|
||||
}
|
||||
|
||||
/** A single emoji image. */
|
||||
const Emoji: React.FC<IEmoji> = (props): React.JSX.Element | null => {
|
||||
const Emoji: React.FC<IEmoji> = (props) => {
|
||||
const { disableUserProvidedMedia, systemEmojiFont } = useSettings();
|
||||
const { emoji, alt, src, staticSrc, noGroup, ...rest } = props;
|
||||
|
||||
@ -30,8 +30,7 @@ const Emoji: React.FC<IEmoji> = (props): React.JSX.Element | null => {
|
||||
if (!filename && !src) return null;
|
||||
|
||||
if (src) {
|
||||
if (disableUserProvidedMedia)
|
||||
return <>{alt ?? <span className={rest.className}>{emoji}</span>}</>;
|
||||
if (disableUserProvidedMedia) return alt ?? <span className={rest.className}>{emoji}</span>;
|
||||
return (
|
||||
<StillImage
|
||||
alt={alt ?? emoji}
|
||||
|
||||
@ -50,12 +50,11 @@ const Counter: React.FC<ICounter> = ({
|
||||
let content;
|
||||
|
||||
if (!data) {
|
||||
content = (
|
||||
<>
|
||||
{/* <span className='sparkline__value__total'><Skeleton width={43} /></span>
|
||||
<span className='sparkline__value__change'><Skeleton width={43} /></span> */}
|
||||
</>
|
||||
);
|
||||
content = null;
|
||||
{
|
||||
/* <span className='sparkline__value__total'><Skeleton width={43} /></span>
|
||||
<span className='sparkline__value__change'><Skeleton width={43} /></span> */
|
||||
}
|
||||
} else {
|
||||
const measure = data[0];
|
||||
const percentChange =
|
||||
|
||||
@ -279,154 +279,148 @@ const RegistrationForm: React.FC<IRegistrationForm> = ({ inviteToken }) => {
|
||||
return (
|
||||
<Form onSubmit={onSubmit} data-testid='registrations-open'>
|
||||
<fieldset disabled={isLoading} className='space-y-3'>
|
||||
<>
|
||||
<FormGroup
|
||||
hintText={
|
||||
<FormattedMessage
|
||||
id='registration.fields.username_hint'
|
||||
defaultMessage='Only letters, numbers, and underscores are allowed.'
|
||||
/>
|
||||
}
|
||||
errors={
|
||||
usernameUnavailable ? [intl.formatMessage(messages.usernameUnavailable)] : undefined
|
||||
}
|
||||
>
|
||||
<Input
|
||||
type='text'
|
||||
name='username'
|
||||
placeholder={intl.formatMessage(messages.username)}
|
||||
autoComplete='off'
|
||||
autoCorrect='off'
|
||||
autoCapitalize='off'
|
||||
pattern='^[a-zA-Z\d_-]+'
|
||||
icon={require('@phosphor-icons/core/regular/at.svg')}
|
||||
onChange={onUsernameChange}
|
||||
value={params.username}
|
||||
required
|
||||
<FormGroup
|
||||
hintText={
|
||||
<FormattedMessage
|
||||
id='registration.fields.username_hint'
|
||||
defaultMessage='Only letters, numbers, and underscores are allowed.'
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{domains && (
|
||||
<FormGroup>
|
||||
<Select onChange={onDomainChange} value={params.domain}>
|
||||
{domains.map(({ id, domain }) => (
|
||||
<option key={id} value={id}>
|
||||
{domain}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</FormGroup>
|
||||
)}
|
||||
|
||||
}
|
||||
errors={
|
||||
usernameUnavailable ? [intl.formatMessage(messages.usernameUnavailable)] : undefined
|
||||
}
|
||||
>
|
||||
<Input
|
||||
type='email'
|
||||
name='email'
|
||||
placeholder={intl.formatMessage(messages.email)}
|
||||
type='text'
|
||||
name='username'
|
||||
placeholder={intl.formatMessage(messages.username)}
|
||||
autoComplete='off'
|
||||
autoCorrect='off'
|
||||
autoCapitalize='off'
|
||||
onChange={onInputChange}
|
||||
value={params.email}
|
||||
pattern='^[a-zA-Z\d_-]+'
|
||||
icon={require('@phosphor-icons/core/regular/at.svg')}
|
||||
onChange={onUsernameChange}
|
||||
value={params.username}
|
||||
required
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{domains && (
|
||||
<FormGroup>
|
||||
<Select onChange={onDomainChange} value={params.domain}>
|
||||
{domains.map(({ id, domain }) => (
|
||||
<option key={id} value={id}>
|
||||
{domain}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</FormGroup>
|
||||
)}
|
||||
|
||||
<Input
|
||||
type='email'
|
||||
name='email'
|
||||
placeholder={intl.formatMessage(messages.email)}
|
||||
autoComplete='off'
|
||||
autoCorrect='off'
|
||||
autoCapitalize='off'
|
||||
onChange={onInputChange}
|
||||
value={params.email}
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
type='password'
|
||||
name='password'
|
||||
placeholder={intl.formatMessage(messages.password)}
|
||||
autoComplete='off'
|
||||
autoCorrect='off'
|
||||
autoCapitalize='off'
|
||||
onChange={onPasswordChange}
|
||||
value={params.password}
|
||||
required
|
||||
/>
|
||||
|
||||
<FormGroup
|
||||
errors={passwordMismatch ? [intl.formatMessage(messages.passwordMismatch)] : undefined}
|
||||
>
|
||||
<Input
|
||||
type='password'
|
||||
name='password'
|
||||
placeholder={intl.formatMessage(messages.password)}
|
||||
name='password_confirmation'
|
||||
placeholder={intl.formatMessage(messages.confirm)}
|
||||
autoComplete='off'
|
||||
autoCorrect='off'
|
||||
autoCapitalize='off'
|
||||
onChange={onPasswordChange}
|
||||
value={params.password}
|
||||
onChange={onPasswordConfirmChange}
|
||||
onBlur={onPasswordConfirmBlur}
|
||||
value={passwordConfirmation}
|
||||
required
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
errors={passwordMismatch ? [intl.formatMessage(messages.passwordMismatch)] : undefined}
|
||||
>
|
||||
<Input
|
||||
type='password'
|
||||
name='password_confirmation'
|
||||
placeholder={intl.formatMessage(messages.confirm)}
|
||||
autoComplete='off'
|
||||
autoCorrect='off'
|
||||
autoCapitalize='off'
|
||||
onChange={onPasswordConfirmChange}
|
||||
onBlur={onPasswordConfirmBlur}
|
||||
value={passwordConfirmation}
|
||||
required
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{birthdayRequired && (
|
||||
<BirthdayInput
|
||||
value={params.date_of_birth ?? ''}
|
||||
onChange={onBirthdayChange}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
|
||||
{needsApproval && (
|
||||
<FormGroup
|
||||
labelText={
|
||||
<FormattedMessage
|
||||
id='registration.reason'
|
||||
defaultMessage='Why do you want to join?'
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Textarea
|
||||
name='reason'
|
||||
placeholder={intl.formatMessage(messages.reasonHint)}
|
||||
maxLength={500}
|
||||
onChange={onInputChange}
|
||||
value={params.reason ?? ''}
|
||||
autoGrow
|
||||
required
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
|
||||
<CaptchaField
|
||||
onFetch={onFetchCaptcha}
|
||||
onFetchFail={onFetchCaptchaFail}
|
||||
onChange={onInputChange}
|
||||
onClick={onCaptchaClick}
|
||||
idempotencyKey={captchaIdempotencyKey}
|
||||
name='captcha_solution'
|
||||
value={params.captcha_solution ?? ''}
|
||||
/>
|
||||
{birthdayRequired && (
|
||||
<BirthdayInput value={params.date_of_birth ?? ''} onChange={onBirthdayChange} required />
|
||||
)}
|
||||
|
||||
{needsApproval && (
|
||||
<FormGroup
|
||||
labelText={
|
||||
<FormattedMessage
|
||||
id='registration.agreement'
|
||||
defaultMessage='I agree to the {tos}.'
|
||||
values={{
|
||||
tos: (
|
||||
<Link to='/about/{-$slug}' params={{ slug: 'tos' }} target='_blank'>
|
||||
<FormattedMessage id='registration.tos' defaultMessage='Terms of Service' />
|
||||
</Link>
|
||||
),
|
||||
}}
|
||||
id='registration.reason'
|
||||
defaultMessage='Why do you want to join?'
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Checkbox
|
||||
name='agreement'
|
||||
onChange={onCheckboxChange}
|
||||
checked={params.agreement}
|
||||
<Textarea
|
||||
name='reason'
|
||||
placeholder={intl.formatMessage(messages.reasonHint)}
|
||||
maxLength={500}
|
||||
onChange={onInputChange}
|
||||
value={params.reason ?? ''}
|
||||
autoGrow
|
||||
required
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
|
||||
<FormActions>
|
||||
<Button type='submit'>
|
||||
<FormattedMessage id='registration.sign_up' defaultMessage='Sign up' />
|
||||
</Button>
|
||||
</FormActions>
|
||||
</>
|
||||
<CaptchaField
|
||||
onFetch={onFetchCaptcha}
|
||||
onFetchFail={onFetchCaptchaFail}
|
||||
onChange={onInputChange}
|
||||
onClick={onCaptchaClick}
|
||||
idempotencyKey={captchaIdempotencyKey}
|
||||
name='captcha_solution'
|
||||
value={params.captcha_solution ?? ''}
|
||||
/>
|
||||
|
||||
<FormGroup
|
||||
labelText={
|
||||
<FormattedMessage
|
||||
id='registration.agreement'
|
||||
defaultMessage='I agree to the {tos}.'
|
||||
values={{
|
||||
tos: (
|
||||
<Link to='/about/{-$slug}' params={{ slug: 'tos' }} target='_blank'>
|
||||
<FormattedMessage id='registration.tos' defaultMessage='Terms of Service' />
|
||||
</Link>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Checkbox
|
||||
name='agreement'
|
||||
onChange={onCheckboxChange}
|
||||
checked={params.agreement}
|
||||
required
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormActions>
|
||||
<Button type='submit'>
|
||||
<FormattedMessage id='registration.sign_up' defaultMessage='Sign up' />
|
||||
</Button>
|
||||
</FormActions>
|
||||
</fieldset>
|
||||
</Form>
|
||||
);
|
||||
|
||||
@ -75,20 +75,18 @@ const ChatListShoutbox: React.FC<IChatListShoutbox> = ({ onClick, onMoveUp, onMo
|
||||
</div>
|
||||
|
||||
{lastMessage && (
|
||||
<>
|
||||
<p className='⁂-chat-list-item__message'>
|
||||
{lastMessageAuthor && (
|
||||
<span className='⁂-chat-list-item__message__author'>
|
||||
<Emojify
|
||||
text={lastMessageAuthor.display_name}
|
||||
emojis={lastMessageAuthor.emojis}
|
||||
/>
|
||||
{': '}
|
||||
</span>
|
||||
)}
|
||||
<ParsedContent html={lastMessage.text} />
|
||||
</p>
|
||||
</>
|
||||
<p className='⁂-chat-list-item__message'>
|
||||
{lastMessageAuthor && (
|
||||
<span className='⁂-chat-list-item__message__author'>
|
||||
<Emojify
|
||||
text={lastMessageAuthor.display_name}
|
||||
emojis={lastMessageAuthor.emojis}
|
||||
/>
|
||||
{': '}
|
||||
</span>
|
||||
)}
|
||||
<ParsedContent html={lastMessage.text} />
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -289,92 +289,87 @@ const ImageComponent = ({
|
||||
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<>
|
||||
<div
|
||||
className='relative'
|
||||
draggable={draggable}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleClick}
|
||||
role='button'
|
||||
>
|
||||
<HStack className='absolute right-2 top-2 z-10' space={2}>
|
||||
<IconButton
|
||||
onClick={previewImage}
|
||||
src={require('@phosphor-icons/core/regular/magnifying-glass-plus.svg')}
|
||||
theme='dark'
|
||||
className='!p-1.5 hover:scale-105 hover:bg-gray-900'
|
||||
iconClassName='h-5 w-5'
|
||||
title={intl.formatMessage(messages.preview)}
|
||||
/>
|
||||
<IconButton
|
||||
onClick={deleteNode}
|
||||
src={require('@phosphor-icons/core/regular/x.svg')}
|
||||
theme='dark'
|
||||
className='!p-1.5 hover:scale-105 hover:bg-gray-900'
|
||||
iconClassName='h-5 w-5'
|
||||
title={intl.formatMessage(messages.delete)}
|
||||
/>
|
||||
</HStack>
|
||||
<div
|
||||
className='relative'
|
||||
draggable={draggable}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleClick}
|
||||
role='button'
|
||||
>
|
||||
<HStack className='absolute right-2 top-2 z-10' space={2}>
|
||||
<IconButton
|
||||
onClick={previewImage}
|
||||
src={require('@phosphor-icons/core/regular/magnifying-glass-plus.svg')}
|
||||
theme='dark'
|
||||
className='!p-1.5 hover:scale-105 hover:bg-gray-900'
|
||||
iconClassName='h-5 w-5'
|
||||
title={intl.formatMessage(messages.preview)}
|
||||
/>
|
||||
<IconButton
|
||||
onClick={deleteNode}
|
||||
src={require('@phosphor-icons/core/regular/x.svg')}
|
||||
theme='dark'
|
||||
className='!p-1.5 hover:scale-105 hover:bg-gray-900'
|
||||
iconClassName='h-5 w-5'
|
||||
title={intl.formatMessage(messages.delete)}
|
||||
/>
|
||||
</HStack>
|
||||
|
||||
<div
|
||||
<div
|
||||
className={clsx(
|
||||
'absolute inset-x-0 bottom-0 z-[2px] bg-gradient-to-b from-transparent via-gray-900/50 to-gray-900/80 p-2.5 opacity-0 transition-opacity duration-100 ease-linear',
|
||||
{
|
||||
'opacity-100': active,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<label>
|
||||
<span className='sr-only'>
|
||||
<FormattedMessage
|
||||
id='upload_form.description'
|
||||
defaultMessage='Describe for the visually impaired'
|
||||
/>
|
||||
</span>
|
||||
|
||||
<textarea
|
||||
className='m-0 w-full rounded-md border border-solid border-white/25 bg-transparent p-2.5 text-sm text-white placeholder:text-white/60'
|
||||
placeholder={intl.formatMessage(messages.description)}
|
||||
value={description}
|
||||
onFocus={handleInputFocus}
|
||||
onChange={handleInputChange}
|
||||
onBlur={handleInputBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{missingDescriptionModal && !description && (
|
||||
<span
|
||||
title={intl.formatMessage(messages.descriptionMissingTitle)}
|
||||
className={clsx(
|
||||
'absolute inset-x-0 bottom-0 z-[2px] bg-gradient-to-b from-transparent via-gray-900/50 to-gray-900/80 p-2.5 opacity-0 transition-opacity duration-100 ease-linear',
|
||||
'absolute bottom-2 left-2 z-10 inline-flex items-center gap-1 rounded bg-gray-900 px-2 py-1 text-xs font-medium uppercase text-white transition-opacity duration-100 ease-linear',
|
||||
{
|
||||
'opacity-100': active,
|
||||
'pointer-events-none opacity-0': active,
|
||||
'opacity-100': !active,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<label>
|
||||
<span className='sr-only'>
|
||||
<FormattedMessage
|
||||
id='upload_form.description'
|
||||
defaultMessage='Describe for the visually impaired'
|
||||
/>
|
||||
</span>
|
||||
<Icon className='size-4' src={require('@phosphor-icons/core/regular/warning.svg')} />
|
||||
<FormattedMessage id='upload_form.description_missing.indicator' defaultMessage='Alt' />
|
||||
</span>
|
||||
)}
|
||||
|
||||
<textarea
|
||||
className='m-0 w-full rounded-md border border-solid border-white/25 bg-transparent p-2.5 text-sm text-white placeholder:text-white/60'
|
||||
placeholder={intl.formatMessage(messages.description)}
|
||||
value={description}
|
||||
onFocus={handleInputFocus}
|
||||
onChange={handleInputChange}
|
||||
onBlur={handleInputBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{missingDescriptionModal && !description && (
|
||||
<span
|
||||
title={intl.formatMessage(messages.descriptionMissingTitle)}
|
||||
className={clsx(
|
||||
'absolute bottom-2 left-2 z-10 inline-flex items-center gap-1 rounded bg-gray-900 px-2 py-1 text-xs font-medium uppercase text-white transition-opacity duration-100 ease-linear',
|
||||
{
|
||||
'pointer-events-none opacity-0': active,
|
||||
'opacity-100': !active,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Icon className='size-4' src={require('@phosphor-icons/core/regular/warning.svg')} />
|
||||
<FormattedMessage
|
||||
id='upload_form.description_missing.indicator'
|
||||
defaultMessage='Alt'
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
|
||||
<LazyImage
|
||||
className={clsx('mx-auto cursor-default', {
|
||||
'select-none': isSelected,
|
||||
'cursor-grab active:cursor-grabbing': isSelected && $isNodeSelection(selection),
|
||||
})}
|
||||
src={src}
|
||||
altText={altText}
|
||||
imageRef={imageRef}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
<LazyImage
|
||||
className={clsx('mx-auto cursor-default', {
|
||||
'select-none': isSelected,
|
||||
'cursor-grab active:cursor-grabbing': isSelected && $isNodeSelection(selection),
|
||||
})}
|
||||
src={src}
|
||||
altText={altText}
|
||||
imageRef={imageRef}
|
||||
/>
|
||||
</div>
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
||||
@ -203,84 +203,82 @@ const BlockTypeDropdown = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowDropDown(!showDropDown);
|
||||
}}
|
||||
className='relative flex cursor-pointer rounded-lg border-0 bg-none p-1 align-middle hover:bg-gray-100 disabled:cursor-not-allowed disabled:hover:bg-none dark:hover:bg-primary-700'
|
||||
aria-label={intl.formatMessage(messages.blockType)}
|
||||
type='button'
|
||||
>
|
||||
<Icon src={icon} />
|
||||
<Icon
|
||||
src={require('@phosphor-icons/core/regular/caret-down.svg')}
|
||||
className='-bottom-2 size-4'
|
||||
/>
|
||||
{showDropDown && (
|
||||
<div className='absolute left-0 top-9 z-10 flex h-[38px] gap-0.5 rounded-lg bg-white p-1 shadow-lg transition-opacity dark:bg-gray-900'>
|
||||
<ToolbarButton
|
||||
onClick={formatParagraph}
|
||||
active={blockType === 'paragraph'}
|
||||
icon={blockTypeToIcon.paragraph}
|
||||
aria-label={intl.formatMessage(messages.paragraph)}
|
||||
/>
|
||||
{composeAllowHeadings && (
|
||||
<>
|
||||
<ToolbarButton
|
||||
onClick={() => {
|
||||
formatHeading('h1');
|
||||
}}
|
||||
active={blockType === 'h1'}
|
||||
icon={blockTypeToIcon.h1}
|
||||
aria-label={intl.formatMessage(messages.h1)}
|
||||
/>
|
||||
<ToolbarButton
|
||||
onClick={() => {
|
||||
formatHeading('h2');
|
||||
}}
|
||||
active={blockType === 'h2'}
|
||||
icon={blockTypeToIcon.h2}
|
||||
aria-label={intl.formatMessage(messages.h2)}
|
||||
/>
|
||||
<ToolbarButton
|
||||
onClick={() => {
|
||||
formatHeading('h3');
|
||||
}}
|
||||
active={blockType === 'h3'}
|
||||
icon={blockTypeToIcon.h3}
|
||||
aria-label={intl.formatMessage(messages.h3)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<ToolbarButton
|
||||
onClick={formatBulletList}
|
||||
active={blockType === 'bullet'}
|
||||
icon={blockTypeToIcon.bullet}
|
||||
aria-label={intl.formatMessage(messages.bulletList)}
|
||||
/>
|
||||
<ToolbarButton
|
||||
onClick={formatNumberedList}
|
||||
active={blockType === 'number'}
|
||||
icon={blockTypeToIcon.number}
|
||||
aria-label={intl.formatMessage(messages.numberedList)}
|
||||
/>
|
||||
<ToolbarButton
|
||||
onClick={formatQuote}
|
||||
active={blockType === 'quote'}
|
||||
icon={blockTypeToIcon.quote}
|
||||
aria-label={intl.formatMessage(messages.quote)}
|
||||
/>
|
||||
<ToolbarButton
|
||||
onClick={formatCode}
|
||||
active={blockType === 'code'}
|
||||
icon={blockTypeToIcon.code}
|
||||
aria-label={intl.formatMessage(messages.codeBlock)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
</>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowDropDown(!showDropDown);
|
||||
}}
|
||||
className='relative flex cursor-pointer rounded-lg border-0 bg-none p-1 align-middle hover:bg-gray-100 disabled:cursor-not-allowed disabled:hover:bg-none dark:hover:bg-primary-700'
|
||||
aria-label={intl.formatMessage(messages.blockType)}
|
||||
type='button'
|
||||
>
|
||||
<Icon src={icon} />
|
||||
<Icon
|
||||
src={require('@phosphor-icons/core/regular/caret-down.svg')}
|
||||
className='-bottom-2 size-4'
|
||||
/>
|
||||
{showDropDown && (
|
||||
<div className='absolute left-0 top-9 z-10 flex h-[38px] gap-0.5 rounded-lg bg-white p-1 shadow-lg transition-opacity dark:bg-gray-900'>
|
||||
<ToolbarButton
|
||||
onClick={formatParagraph}
|
||||
active={blockType === 'paragraph'}
|
||||
icon={blockTypeToIcon.paragraph}
|
||||
aria-label={intl.formatMessage(messages.paragraph)}
|
||||
/>
|
||||
{composeAllowHeadings && (
|
||||
<>
|
||||
<ToolbarButton
|
||||
onClick={() => {
|
||||
formatHeading('h1');
|
||||
}}
|
||||
active={blockType === 'h1'}
|
||||
icon={blockTypeToIcon.h1}
|
||||
aria-label={intl.formatMessage(messages.h1)}
|
||||
/>
|
||||
<ToolbarButton
|
||||
onClick={() => {
|
||||
formatHeading('h2');
|
||||
}}
|
||||
active={blockType === 'h2'}
|
||||
icon={blockTypeToIcon.h2}
|
||||
aria-label={intl.formatMessage(messages.h2)}
|
||||
/>
|
||||
<ToolbarButton
|
||||
onClick={() => {
|
||||
formatHeading('h3');
|
||||
}}
|
||||
active={blockType === 'h3'}
|
||||
icon={blockTypeToIcon.h3}
|
||||
aria-label={intl.formatMessage(messages.h3)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<ToolbarButton
|
||||
onClick={formatBulletList}
|
||||
active={blockType === 'bullet'}
|
||||
icon={blockTypeToIcon.bullet}
|
||||
aria-label={intl.formatMessage(messages.bulletList)}
|
||||
/>
|
||||
<ToolbarButton
|
||||
onClick={formatNumberedList}
|
||||
active={blockType === 'number'}
|
||||
icon={blockTypeToIcon.number}
|
||||
aria-label={intl.formatMessage(messages.numberedList)}
|
||||
/>
|
||||
<ToolbarButton
|
||||
onClick={formatQuote}
|
||||
active={blockType === 'quote'}
|
||||
icon={blockTypeToIcon.quote}
|
||||
aria-label={intl.formatMessage(messages.quote)}
|
||||
/>
|
||||
<ToolbarButton
|
||||
onClick={formatCode}
|
||||
active={blockType === 'code'}
|
||||
icon={blockTypeToIcon.code}
|
||||
aria-label={intl.formatMessage(messages.codeBlock)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -37,38 +37,36 @@ const GroupMembers: React.FC = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ScrollableList
|
||||
scrollKey={`groupMembers:${groupId}`}
|
||||
hasMore={hasNextPage}
|
||||
onLoadMore={fetchNextPage}
|
||||
isLoading={!group || isLoading}
|
||||
showLoading={!group || ((isFetchingPending ?? isLoading) && members.length === 0)}
|
||||
placeholderComponent={PlaceholderAccount}
|
||||
placeholderCount={3}
|
||||
className='⁂-status-list'
|
||||
itemClassName='py-3 last:pb-0'
|
||||
prepend={
|
||||
membershipRequests.length > 0 && (
|
||||
<div
|
||||
className={clsx('py-3', {
|
||||
'border-b border-gray-200 dark:border-gray-800': members.length,
|
||||
})}
|
||||
>
|
||||
<PendingItemsRow
|
||||
to='/groups/$groupId/manage/requests'
|
||||
params={{ groupId }}
|
||||
count={membershipRequests.length}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
>
|
||||
{members.map((member) => (
|
||||
<GroupMemberListItem group={group!} member={member} key={member.account_id} />
|
||||
))}
|
||||
</ScrollableList>
|
||||
</>
|
||||
<ScrollableList
|
||||
scrollKey={`groupMembers:${groupId}`}
|
||||
hasMore={hasNextPage}
|
||||
onLoadMore={fetchNextPage}
|
||||
isLoading={!group || isLoading}
|
||||
showLoading={!group || ((isFetchingPending ?? isLoading) && members.length === 0)}
|
||||
placeholderComponent={PlaceholderAccount}
|
||||
placeholderCount={3}
|
||||
className='⁂-status-list'
|
||||
itemClassName='py-3 last:pb-0'
|
||||
prepend={
|
||||
membershipRequests.length > 0 && (
|
||||
<div
|
||||
className={clsx('py-3', {
|
||||
'border-b border-gray-200 dark:border-gray-800': members.length,
|
||||
})}
|
||||
>
|
||||
<PendingItemsRow
|
||||
to='/groups/$groupId/manage/requests'
|
||||
params={{ groupId }}
|
||||
count={membershipRequests.length}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
>
|
||||
{members.map((member) => (
|
||||
<GroupMemberListItem group={group!} member={member} key={member.account_id} />
|
||||
))}
|
||||
</ScrollableList>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -116,22 +116,20 @@ const SettingsPage = () => {
|
||||
/>
|
||||
)}
|
||||
{features.manageMfa && (
|
||||
<>
|
||||
<ListItem
|
||||
label={
|
||||
<FormattedMessage id='settings.configure_mfa' defaultMessage='Configure MFA' />
|
||||
}
|
||||
to='/settings/mfa'
|
||||
>
|
||||
<span>
|
||||
{isMfaEnabled ? (
|
||||
<FormattedMessage id='mfa.enabled' defaultMessage='Enabled' />
|
||||
) : (
|
||||
<FormattedMessage id='mfa.disabled' defaultMessage='Disabled' />
|
||||
)}
|
||||
</span>
|
||||
</ListItem>
|
||||
</>
|
||||
<ListItem
|
||||
label={
|
||||
<FormattedMessage id='settings.configure_mfa' defaultMessage='Configure MFA' />
|
||||
}
|
||||
to='/settings/mfa'
|
||||
>
|
||||
<span>
|
||||
{isMfaEnabled ? (
|
||||
<FormattedMessage id='mfa.enabled' defaultMessage='Enabled' />
|
||||
) : (
|
||||
<FormattedMessage id='mfa.disabled' defaultMessage='Disabled' />
|
||||
)}
|
||||
</span>
|
||||
</ListItem>
|
||||
)}
|
||||
{features.sessions && (
|
||||
<ListItem
|
||||
|
||||
Reference in New Issue
Block a user