Delete Bundle component, use Suspense and React.lazy

This commit is contained in:
Alex Gleason
2023-10-07 17:14:45 -05:00
parent 1b213452b7
commit b02c39da2d
35 changed files with 275 additions and 578 deletions

View File

@@ -1,28 +0,0 @@
const BUNDLE_FETCH_REQUEST = 'BUNDLE_FETCH_REQUEST';
const BUNDLE_FETCH_SUCCESS = 'BUNDLE_FETCH_SUCCESS';
const BUNDLE_FETCH_FAIL = 'BUNDLE_FETCH_FAIL';
const fetchBundleRequest = (skipLoading?: boolean) => ({
type: BUNDLE_FETCH_REQUEST,
skipLoading,
});
const fetchBundleSuccess = (skipLoading?: boolean) => ({
type: BUNDLE_FETCH_SUCCESS,
skipLoading,
});
const fetchBundleFail = (error: any, skipLoading?: boolean) => ({
type: BUNDLE_FETCH_FAIL,
error,
skipLoading,
});
export {
BUNDLE_FETCH_REQUEST,
BUNDLE_FETCH_SUCCESS,
BUNDLE_FETCH_FAIL,
fetchBundleRequest,
fetchBundleSuccess,
fetchBundleFail,
};

View File

@@ -1,7 +1,6 @@
import React from 'react';
import React, { Suspense } from 'react';
import { openModal } from 'soapbox/actions/modals';
import Bundle from 'soapbox/features/ui/components/bundle';
import { MediaGallery } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch } from 'soapbox/hooks';
@@ -18,23 +17,21 @@ const AttachmentThumbs = (props: IAttachmentThumbs) => {
const { media, onClick, sensitive } = props;
const dispatch = useAppDispatch();
const renderLoading = () => <div className='media-gallery--compact' />;
const fallback = <div className='media-gallery--compact' />;
const onOpenMedia = (media: ImmutableList<Attachment>, index: number) => dispatch(openModal('MEDIA', { media, index }));
return (
<div className='attachment-thumbs'>
<Bundle fetchComponent={MediaGallery} loading={renderLoading}>
{(Component: any) => (
<Component
media={media}
onOpenMedia={onOpenMedia}
height={50}
compact
sensitive={sensitive}
visible
/>
)}
</Bundle>
<Suspense fallback={fallback}>
<MediaGallery
media={media}
onOpenMedia={onOpenMedia}
height={50}
compact
sensitive={sensitive}
visible
/>
</Suspense>
{onClick && (
<div className='attachment-thumbs__clickable-region' onClick={onClick} />

View File

@@ -2,7 +2,6 @@ import React, { useMemo } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import IconButton from 'soapbox/components/icon-button';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { DatePicker } from 'soapbox/features/ui/util/async-components';
import { useInstance, useFeatures } from 'soapbox/hooks';
@@ -114,19 +113,17 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
return (
<div className='relative mt-1 rounded-md shadow-sm'>
<BundleContainer fetchComponent={DatePicker}>
{Component => (<Component
selected={selected}
wrapperClassName='react-datepicker-wrapper'
onChange={handleChange}
placeholderText={intl.formatMessage(messages.birthdayPlaceholder)}
minDate={new Date('1900-01-01')}
maxDate={maxDate}
required={required}
renderCustomHeader={renderCustomHeader}
isClearable={!required}
/>)}
</BundleContainer>
<DatePicker
selected={selected}
wrapperClassName='react-datepicker-wrapper'
onChange={handleChange}
placeholderText={intl.formatMessage(messages.birthdayPlaceholder)}
minDate={new Date('1900-01-01')}
maxDate={maxDate}
required={required}
renderCustomHeader={renderCustomHeader}
isClearable={!required}
/>
</div>
);
};

View File

@@ -12,7 +12,6 @@ import {
import { useAccount, usePatronUser } from 'soapbox/api/hooks';
import Badge from 'soapbox/components/badge';
import ActionButton from 'soapbox/features/ui/components/action-button';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { UserPanel } from 'soapbox/features/ui/util/async-components';
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
import { isLocal } from 'soapbox/utils/accounts';
@@ -112,15 +111,11 @@ export const ProfileHoverCard: React.FC<IProfileHoverCard> = ({ visible = true }
<Card variant='rounded' className='relative isolate overflow-hidden'>
<CardBody>
<Stack space={2}>
<BundleContainer fetchComponent={UserPanel}>
{Component => (
<Component
accountId={account.id}
action={<ActionButton account={account} small />}
badges={badges}
/>
)}
</BundleContainer>
<UserPanel
accountId={account.id}
action={<ActionButton account={account} small />}
badges={badges}
/>
{isLocal(account) ? (
<HStack alignItems='center' space={0.5}>

View File

@@ -1,16 +1,14 @@
import React from 'react';
import React, { Suspense } from 'react';
import { openModal } from 'soapbox/actions/modals';
import AttachmentThumbs from 'soapbox/components/attachment-thumbs';
import { GroupLinkPreview } from 'soapbox/features/groups/components/group-link-preview';
import PlaceholderCard from 'soapbox/features/placeholder/components/placeholder-card';
import Card from 'soapbox/features/status/components/card';
import Bundle from 'soapbox/features/ui/components/bundle';
import { MediaGallery, Video, Audio } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch } from 'soapbox/hooks';
import type { List as ImmutableList } from 'immutable';
import type VideoType from 'soapbox/features/video';
import type { Status, Attachment } from 'soapbox/types/entities';
interface IStatusMedia {
@@ -70,54 +68,48 @@ const StatusMedia: React.FC<IStatusMedia> = ({
const video = firstAttachment;
media = (
<Bundle fetchComponent={Video} loading={renderLoadingVideoPlayer}>
{(Component: typeof VideoType) => (
<Component
preview={video.preview_url}
blurhash={video.blurhash}
src={video.url}
alt={video.description}
aspectRatio={Number(video.meta.getIn(['original', 'aspect']))}
height={285}
visible={showMedia}
inline
/>
)}
</Bundle>
<Suspense fallback={renderLoadingVideoPlayer()}>
<Video
preview={video.preview_url}
blurhash={video.blurhash}
src={video.url}
alt={video.description}
aspectRatio={Number(video.meta.getIn(['original', 'aspect']))}
height={285}
visible={showMedia}
inline
/>
</Suspense>
);
} else if (size === 1 && firstAttachment.type === 'audio') {
const attachment = firstAttachment;
media = (
<Bundle fetchComponent={Audio} loading={renderLoadingAudioPlayer}>
{(Component: any) => (
<Component
src={attachment.url}
alt={attachment.description}
poster={attachment.preview_url !== attachment.url ? attachment.preview_url : status.getIn(['account', 'avatar_static'])}
backgroundColor={attachment.meta.getIn(['colors', 'background'])}
foregroundColor={attachment.meta.getIn(['colors', 'foreground'])}
accentColor={attachment.meta.getIn(['colors', 'accent'])}
duration={attachment.meta.getIn(['original', 'duration'], 0)}
height={263}
/>
)}
</Bundle>
<Suspense fallback={renderLoadingAudioPlayer()}>
<Audio
src={attachment.url}
alt={attachment.description}
poster={attachment.preview_url !== attachment.url ? attachment.preview_url : status.getIn(['account', 'avatar_static']) as string | undefined}
backgroundColor={attachment.meta.getIn(['colors', 'background']) as string | undefined}
foregroundColor={attachment.meta.getIn(['colors', 'foreground']) as string | undefined}
accentColor={attachment.meta.getIn(['colors', 'accent']) as string | undefined}
duration={attachment.meta.getIn(['original', 'duration'], 0) as number | undefined}
height={263}
/>
</Suspense>
);
} else {
media = (
<Bundle fetchComponent={MediaGallery} loading={renderLoadingMediaGallery}>
{(Component: any) => (
<Component
media={status.media_attachments}
sensitive={status.sensitive}
height={285}
onOpenMedia={openMedia}
visible={showMedia}
onToggleVisibility={onToggleVisibility}
/>
)}
</Bundle>
<Suspense fallback={renderLoadingMediaGallery()}>
<MediaGallery
media={status.media_attachments}
sensitive={status.sensitive}
height={285}
onOpenMedia={openMedia}
visible={showMedia}
onToggleVisibility={onToggleVisibility}
/>
</Suspense>
);
}
} else if (status.spoiler_text.length === 0 && !status.quote && status.card?.group) {

View File

@@ -1,6 +1,6 @@
import { QueryClientProvider } from '@tanstack/react-query';
import clsx from 'clsx';
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, Suspense } from 'react';
import { Toaster } from 'react-hot-toast';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
@@ -18,7 +18,6 @@ import Helmet from 'soapbox/components/helmet';
import LoadingScreen from 'soapbox/components/loading-screen';
import { StatProvider } from 'soapbox/contexts/stat-context';
import EmbeddedStatus from 'soapbox/features/embedded-status';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import {
ModalContainer,
OnboardingWizard,
@@ -87,9 +86,9 @@ const SoapboxMount = () => {
/** Render the onboarding flow. */
const renderOnboarding = () => (
<BundleContainer fetchComponent={OnboardingWizard} loading={LoadingScreen}>
{(Component) => <Component />}
</BundleContainer>
<Suspense fallback={<LoadingScreen />}>
<OnboardingWizard />
</Suspense>
);
/** Render the auth layout or UI. */
@@ -127,10 +126,7 @@ const SoapboxMount = () => {
<Route>
{renderBody()}
<BundleContainer fetchComponent={ModalContainer}>
{Component => <Component />}
</BundleContainer>
<ModalContainer />
<GdprBanner />
<div id='toaster'>

View File

@@ -10,7 +10,6 @@ import { initReport, ReportableEntities } from 'soapbox/actions/reports';
import DropdownMenu from 'soapbox/components/dropdown-menu';
import { HStack, Icon, Stack, Text } from 'soapbox/components/ui';
import emojify from 'soapbox/features/emoji';
import Bundle from 'soapbox/features/ui/components/bundle';
import { MediaGallery } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
import { ChatKeys, IChat, useChatActions } from 'soapbox/queries/chats';
@@ -22,7 +21,6 @@ import ChatMessageReaction from './chat-message-reaction';
import ChatMessageReactionWrapper from './chat-message-reaction-wrapper/chat-message-reaction-wrapper';
import type { Menu as IMenu } from 'soapbox/components/dropdown-menu';
import type { IMediaGallery } from 'soapbox/components/media-gallery';
import type { ChatMessage as ChatMessageEntity } from 'soapbox/types/entities';
const messages = defineMessages({
@@ -111,19 +109,15 @@ const ChatMessage = (props: IChatMessage) => {
if (!chatMessage.media_attachments.size) return null;
return (
<Bundle fetchComponent={MediaGallery}>
{(Component: React.FC<IMediaGallery>) => (
<Component
className={clsx({
'rounded-br-sm': isMyMessage && content,
'rounded-bl-sm': !isMyMessage && content,
})}
media={chatMessage.media_attachments}
onOpenMedia={onOpenMedia}
visible
/>
)}
</Bundle>
<MediaGallery
className={clsx({
'rounded-br-sm': isMyMessage && content,
'rounded-bl-sm': !isMyMessage && content,
})}
media={chatMessage.media_attachments}
onOpenMedia={onOpenMedia}
visible
/>
);
};

View File

@@ -17,14 +17,12 @@ import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest
import AutosuggestTextarea from 'soapbox/components/autosuggest-textarea';
import { Button, HStack, Stack } from 'soapbox/components/ui';
import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container';
import Bundle from 'soapbox/features/ui/components/bundle';
import { ComposeEditor } from 'soapbox/features/ui/util/async-components';
import { ComposeEditor, ScheduleForm } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, usePrevious } from 'soapbox/hooks';
import { isMobile } from 'soapbox/is-mobile';
import QuotedStatusContainer from '../containers/quoted-status-container';
import ReplyIndicatorContainer from '../containers/reply-indicator-container';
import ScheduleFormContainer from '../containers/schedule-form-container';
import UploadButtonContainer from '../containers/upload-button-container';
import WarningContainer from '../containers/warning-container';
import { $createEmojiNode } from '../editor/nodes/emoji-node';
@@ -260,7 +258,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
ref={spoilerTextRef}
/>
<ScheduleFormContainer composeId={id} />
<ScheduleForm composeId={id} />
</Stack>
);
@@ -313,23 +311,19 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
{!shouldCondense && !event && !group && <ReplyMentions composeId={id} />}
<div>
<Bundle fetchComponent={ComposeEditor}>
{(Component: any) => (
<Component
ref={editorRef}
className='mt-2'
composeId={id}
condensed={condensed}
eventDiscussion={!!event}
autoFocus={shouldAutoFocus}
hasPoll={hasPoll}
handleSubmit={handleSubmit}
onChange={setText}
onFocus={handleComposeFocus}
onPaste={onPaste}
/>
)}
</Bundle>
<ComposeEditor
ref={editorRef}
className='mt-2'
composeId={id}
condensed={condensed}
eventDiscussion={!!event}
autoFocus={shouldAutoFocus}
hasPoll={hasPoll}
handleSubmit={handleSubmit}
onChange={setText}
onFocus={handleComposeFocus}
onPaste={onPaste}
/>
{composeModifiers}
</div>

View File

@@ -5,7 +5,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { setSchedule, removeSchedule } from 'soapbox/actions/compose';
import IconButton from 'soapbox/components/icon-button';
import { HStack, Stack, Text } from 'soapbox/components/ui';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { DatePicker } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch, useCompose } from 'soapbox/hooks';
@@ -55,22 +54,20 @@ const ScheduleForm: React.FC<IScheduleForm> = ({ composeId }) => {
<FormattedMessage id='datepicker.hint' defaultMessage='Scheduled to post at…' />
</Text>
<HStack space={2} alignItems='center'>
<BundleContainer fetchComponent={DatePicker}>
{Component => (<Component
selected={scheduledAt}
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
onChange={onSchedule}
placeholderText={intl.formatMessage(messages.schedule)}
filterDate={isCurrentOrFutureDate}
filterTime={isFiveMinutesFromNow}
className={clsx({
'has-error': !isFiveMinutesFromNow(scheduledAt),
})}
/>)}
</BundleContainer>
<DatePicker
selected={scheduledAt}
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
onChange={onSchedule}
placeholderText={intl.formatMessage(messages.schedule)}
filterDate={isCurrentOrFutureDate}
filterTime={isFiveMinutesFromNow}
className={clsx({
'has-error': !isFiveMinutesFromNow(scheduledAt),
})}
/>
<IconButton
iconClassName='h-4 w-4'
className='bg-transparent text-gray-400 hover:text-gray-600'

View File

@@ -1,14 +0,0 @@
import React from 'react';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { ScheduleForm } from 'soapbox/features/ui/util/async-components';
import type { IScheduleForm } from '../components/schedule-form';
const ScheduleFormContainer: React.FC<IScheduleForm> = (props) => (
<BundleContainer fetchComponent={ScheduleForm}>
{Component => <Component {...props} />}
</BundleContainer>
);
export default ScheduleFormContainer;

View File

@@ -6,7 +6,6 @@ import StatusContent from 'soapbox/components/status-content';
import { Toggle } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import Bundle from '../../ui/components/bundle';
import { MediaGallery, Video, Audio } from '../../ui/util/async-components';
interface IStatusCheckBox {
@@ -35,22 +34,16 @@ const StatusCheckBox: React.FC<IStatusCheckBox> = ({ id, disabled }) => {
if (video) {
media = (
<Bundle fetchComponent={Video}>
{(Component: any) => (
<Component
preview={video.preview_url}
blurhash={video.blurhash}
src={video.url}
alt={video.description}
aspectRatio={video.meta.getIn(['original', 'aspect'])}
width={239}
height={110}
inline
sensitive={status.sensitive}
onOpenVideo={noop}
/>
)}
</Bundle>
<Video
preview={video.preview_url}
blurhash={video.blurhash}
src={video.url}
alt={video.description}
aspectRatio={video.meta.getIn(['original', 'aspect']) as number | undefined}
width={239}
height={110}
inline
/>
);
}
} else if (status.media_attachments.get(0)?.type === 'audio') {
@@ -58,24 +51,20 @@ const StatusCheckBox: React.FC<IStatusCheckBox> = ({ id, disabled }) => {
if (audio) {
media = (
<Bundle fetchComponent={Audio}>
{(Component: any) => (
<Component
src={audio.url}
alt={audio.description}
inline
sensitive={status.sensitive}
onOpenAudio={noop}
/>
)}
</Bundle>
<Audio
src={audio.url}
alt={audio.description}
/>
);
}
} else {
media = (
<Bundle fetchComponent={MediaGallery}>
{(Component: any) => <Component media={status.media_attachments} sensitive={status.sensitive} height={110} onOpenMedia={noop} />}
</Bundle>
<MediaGallery
media={status.media_attachments}
sensitive={status.sensitive}
height={110}
onOpenMedia={noop}
/>
);
}
}

View File

@@ -1,23 +0,0 @@
import React, { Suspense } from 'react';
export interface IBundle<T extends React.ComponentType<any>> {
fetchComponent: React.LazyExoticComponent<T>;
loading?: React.ComponentType;
error?: React.ComponentType<{ onRetry: (props?: IBundle<T>) => void }>;
children: (component: React.LazyExoticComponent<T>) => React.ReactNode;
renderDelay?: number;
onFetch?: () => void;
onFetchSuccess?: () => void;
onFetchFail?: (error: any) => void;
}
/** Fetches and renders an async component. */
function Bundle<T extends React.ComponentType<any>>({ fetchComponent, loading: Loading, children }: IBundle<T>) {
return (
<Suspense fallback={Loading ? <Loading /> : null}>
{children(fetchComponent)}
</Suspense>
);
}
export default Bundle;

View File

@@ -2,8 +2,6 @@ import React from 'react';
import { Spinner } from 'soapbox/components/ui';
// Keep the markup in sync with <BundleModalError />
// (make sure they have the same dimensions)
const ModalLoading = () => (
<div className='modal-root__modal error-modal'>
<div className='error-modal__body'>

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { Suspense } from 'react';
import Base from 'soapbox/components/modal-root';
import {
@@ -38,8 +38,6 @@ import {
VideoModal,
} from 'soapbox/features/ui/util/async-components';
import BundleContainer from '../containers/bundle-container';
import ModalLoading from './modal-loading';
/* eslint sort-keys: "error" */
@@ -102,7 +100,7 @@ export default class ModalRoot extends React.PureComponent<IModalRoot> {
}
}
renderLoading = (modalId: string) => () => {
renderLoading = (modalId: string) => {
return !['MEDIA', 'VIDEO', 'BOOST', 'CONFIRM', 'ACTIONS'].includes(modalId) ? <ModalLoading /> : null;
};
@@ -113,14 +111,14 @@ export default class ModalRoot extends React.PureComponent<IModalRoot> {
render() {
const { type, props } = this.props;
const visible = !!type;
const Component = type ? MODAL_COMPONENTS[type] : null;
return (
<Base onClose={this.onClickClose} type={type}>
{visible && (
<BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading(type)} renderDelay={200}>
{(SpecificComponent) => <SpecificComponent {...props} onClose={this.onClickClose} />}
</BundleContainer>
{(Component && !!type) && (
<Suspense fallback={this.renderLoading(type)}>
<Component {...props} onClose={this.onClickClose} />
</Suspense>
)}
</Base>
);

View File

@@ -24,12 +24,13 @@ import { checkEventComposeContent } from 'soapbox/components/modal-root';
import { Button, Form, FormGroup, HStack, Icon, IconButton, Input, Modal, Spinner, Stack, Tabs, Text, Toggle } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import { isCurrentOrFutureDate } from 'soapbox/features/compose/components/schedule-form';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { ComposeEditor, DatePicker } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import UploadButton from './upload-button';
import type { LexicalEditor } from 'lexical';
const messages = defineMessages({
eventNamePlaceholder: { id: 'compose_event.fields.name_placeholder', defaultMessage: 'Name' },
eventDescriptionPlaceholder: { id: 'compose_event.fields.description_placeholder', defaultMessage: 'Description' },
@@ -94,7 +95,7 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const editorStateRef = useRef<string>(null);
const editorRef = useRef<LexicalEditor>(null);
const [tab, setTab] = useState<'edit' | 'pending'>('edit');
@@ -167,7 +168,7 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
};
const handleSubmit = () => {
dispatch(changeEditEventDescription(editorStateRef.current!));
dispatch(changeEditEventDescription(editorRef.current!));
dispatch(submitEvent());
};
@@ -235,18 +236,14 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
<FormGroup
labelText={<FormattedMessage id='compose_event.fields.description_label' defaultMessage='Event description' />}
>
<BundleContainer fetchComponent={ComposeEditor}>
{(Component: any) => (
<Component
ref={editorStateRef}
className='block w-full rounded-md border border-gray-400 bg-white px-3 py-2 text-base text-gray-900 ring-1 placeholder:text-gray-600 focus-within:border-primary-500 focus-within:ring-primary-500 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500 sm:text-sm'
placeholderClassName='pt-2'
composeId='compose-event-modal'
placeholder={intl.formatMessage(messages.eventDescriptionPlaceholder)}
handleSubmit={handleSubmit}
/>
)}
</BundleContainer>
<ComposeEditor
ref={editorRef}
className='block w-full rounded-md border border-gray-400 bg-white px-3 py-2 text-base text-gray-900 ring-1 placeholder:text-gray-600 focus-within:border-primary-500 focus-within:ring-primary-500 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500 sm:text-sm'
placeholderClassName='pt-2'
composeId='compose-event-modal'
placeholder={intl.formatMessage(messages.eventDescriptionPlaceholder)}
handleSubmit={handleSubmit}
/>
</FormGroup>
<FormGroup
labelText={<FormattedMessage id='compose_event.fields.location_label' defaultMessage='Event location' />}
@@ -260,18 +257,16 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
<FormGroup
labelText={<FormattedMessage id='compose_event.fields.start_time_label' defaultMessage='Event start date' />}
>
<BundleContainer fetchComponent={DatePicker}>
{Component => (<Component
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.eventStartTimePlaceholder)}
filterDate={isCurrentOrFutureDate}
selected={startTime}
onChange={onChangeStartTime}
/>)}
</BundleContainer>
<DatePicker
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.eventStartTimePlaceholder)}
filterDate={isCurrentOrFutureDate}
selected={startTime}
onChange={onChangeStartTime}
/>
</FormGroup>
<HStack alignItems='center' space={2}>
<Toggle
@@ -286,18 +281,16 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
<FormGroup
labelText={<FormattedMessage id='compose_event.fields.end_time_label' defaultMessage='Event end date' />}
>
<BundleContainer fetchComponent={DatePicker}>
{Component => (<Component
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.eventEndTimePlaceholder)}
filterDate={isCurrentOrFutureDate}
selected={endTime}
onChange={onChangeEndTime}
/>)}
</BundleContainer>
<DatePicker
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.eventEndTimePlaceholder)}
filterDate={isCurrentOrFutureDate}
selected={endTime}
onChange={onChangeEndTime}
/>
</FormGroup>
)}
{!id && (

View File

@@ -4,7 +4,6 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { changeAnnouncementAllDay, changeAnnouncementContent, changeAnnouncementEndTime, changeAnnouncementStartTime, handleCreateAnnouncement } from 'soapbox/actions/admin';
import { closeModal } from 'soapbox/actions/modals';
import { Form, FormGroup, HStack, Modal, Stack, Text, Textarea, Toggle } from 'soapbox/components/ui';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { DatePicker } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
@@ -67,34 +66,30 @@ const EditAnnouncementModal: React.FC<IEditAnnouncementModal> = ({ onClose }) =>
<FormGroup
labelText={<FormattedMessage id='admin.edit_announcement.fields.start_time_label' defaultMessage='Start date' />}
>
<BundleContainer fetchComponent={DatePicker}>
{Component => (<Component
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.announcementStartTimePlaceholder)}
selected={startTime}
onChange={onChangeStartTime}
isClearable
/>)}
</BundleContainer>
<DatePicker
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.announcementStartTimePlaceholder)}
selected={startTime}
onChange={onChangeStartTime}
isClearable
/>
</FormGroup>
<FormGroup
labelText={<FormattedMessage id='admin.edit_announcement.fields.end_time_label' defaultMessage='End date' />}
>
<BundleContainer fetchComponent={DatePicker}>
{Component => (<Component
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.announcementEndTimePlaceholder)}
selected={endTime}
onChange={onChangeEndTime}
isClearable
/>)}
</BundleContainer>
<DatePicker
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.announcementEndTimePlaceholder)}
selected={endTime}
onChange={onChangeEndTime}
isClearable
/>
</FormGroup>
<HStack alignItems='center' space={2}>
<Toggle

View File

@@ -5,7 +5,6 @@ import { FormattedMessage } from 'react-intl';
import { fetchPinnedAccounts } from 'soapbox/actions/accounts';
import { Widget } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { WhoToFollowPanel } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
@@ -26,9 +25,7 @@ const PinnedAccountsPanel: React.FC<IPinnedAccountsPanel> = ({ account, limit })
if (pinned.isEmpty()) {
return (
<BundleContainer fetchComponent={WhoToFollowPanel}>
{Component => <Component limit={limit} />}
</BundleContainer>
<WhoToFollowPanel limit={limit} />
);
}

View File

@@ -4,7 +4,6 @@ import { defineMessages, useIntl, FormatDateOptions } from 'react-intl';
import Markup from 'soapbox/components/markup';
import { HStack, Icon } from 'soapbox/components/ui';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { CryptoAddress } from 'soapbox/features/ui/util/async-components';
import type { Account } from 'soapbox/schemas';
@@ -35,14 +34,10 @@ const ProfileField: React.FC<IProfileField> = ({ field }) => {
if (isTicker(field.name)) {
return (
<BundleContainer fetchComponent={CryptoAddress}>
{Component => (
<Component
ticker={getTicker(field.name).toLowerCase()}
address={field.value_plain}
/>
)}
</BundleContainer>
<CryptoAddress
ticker={getTicker(field.name).toLowerCase()}
address={field.value_plain}
/>
);
}

View File

@@ -1,3 +0,0 @@
import Bundle from '../components/bundle';
export default Bundle;

View File

@@ -41,7 +41,6 @@ import { isStandalone } from 'soapbox/utils/state';
import BackgroundShapes from './components/background-shapes';
import FloatingActionButton from './components/floating-action-button';
import Navbar from './components/navbar';
import BundleContainer from './containers/bundle-container';
import {
Status,
CommunityTimeline,
@@ -501,29 +500,18 @@ const UI: React.FC<IUI> = ({ children }) => {
)}
{me && (
<BundleContainer fetchComponent={SidebarMenu}>
{Component => <Component />}
</BundleContainer>
<SidebarMenu />
)}
{me && features.chats && (
<BundleContainer fetchComponent={ChatWidget}>
{Component => (
<div className='hidden xl:block'>
<Component />
</div>
)}
</BundleContainer>
<div className='hidden xl:block'>
<ChatWidget />
</div>
)}
<ThumbNavigation />
<BundleContainer fetchComponent={ProfileHoverCard}>
{Component => <Component />}
</BundleContainer>
<BundleContainer fetchComponent={StatusHoverCard}>
{Component => <Component />}
</BundleContainer>
<ProfileHoverCard />
<StatusHoverCard />
</div>
</div>
</GlobalHotkeys>

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { Suspense } from 'react';
import { Redirect, Route, useHistory, RouteProps, RouteComponentProps, match as MatchType } from 'react-router-dom';
import { Layout } from 'soapbox/components/ui';
@@ -7,7 +7,6 @@ import { useOwnAccount, useSettings } from 'soapbox/hooks';
import ColumnForbidden from '../components/column-forbidden';
import ColumnLoading from '../components/column-loading';
import ColumnsArea from '../components/columns-area';
import BundleContainer from '../containers/bundle-container';
type PageProps = {
params?: MatchType['params'];
@@ -28,7 +27,7 @@ interface IWrappedRoute extends RouteProps {
}
const WrappedRoute: React.FC<IWrappedRoute> = ({
component,
component: Component,
page: Page,
content,
componentParams = {},
@@ -47,32 +46,24 @@ const WrappedRoute: React.FC<IWrappedRoute> = ({
const renderComponent = ({ match }: RouteComponentProps) => {
if (Page) {
return (
<BundleContainer fetchComponent={component} loading={renderLoading}>
{Component =>
(
<Page params={match.params} layout={layout} {...componentParams}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</Page>
)
}
</BundleContainer>
<Suspense fallback={renderLoading()}>
<Page params={match.params} layout={layout} {...componentParams}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</Page>
</Suspense>
);
}
return (
<BundleContainer fetchComponent={component} loading={renderLoading}>
{Component =>
(
<ColumnsArea layout={layout}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</ColumnsArea>
)
}
</BundleContainer>
<Suspense fallback={renderLoading()}>
<ColumnsArea layout={layout}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</ColumnsArea>
</Suspense>
);
};

View File

@@ -1,7 +1,6 @@
import React from 'react';
import { Layout } from 'soapbox/components/ui';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import {
LatestAccountsPanel,
} from 'soapbox/features/ui/util/async-components';
@@ -20,10 +19,7 @@ const AdminPage: React.FC<IAdminPage> = ({ children }) => {
</Layout.Main>
<Layout.Aside>
<BundleContainer fetchComponent={LatestAccountsPanel}>
{Component => <Component limit={5} />}
</BundleContainer>
<LatestAccountsPanel limit={5} />
<LinkFooter />
</Layout.Aside>
</>

View File

@@ -1,7 +1,6 @@
import React from 'react';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import {
WhoToFollowPanel,
TrendsPanel,
@@ -26,27 +25,19 @@ const DefaultPage: React.FC<IDefaultPage> = ({ children }) => {
{children}
{!me && (
<BundleContainer fetchComponent={CtaBanner}>
{Component => <Component key='cta-banner' />}
</BundleContainer>
<CtaBanner />
)}
</Layout.Main>
<Layout.Aside>
{!me && (
<BundleContainer fetchComponent={SignUpPanel}>
{Component => <Component key='sign-up-panel' />}
</BundleContainer>
<SignUpPanel />
)}
{features.trends && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={5} key='trends-panel' />}
</BundleContainer>
<TrendsPanel limit={5} />
)}
{me && features.suggestions && (
<BundleContainer fetchComponent={WhoToFollowPanel}>
{Component => <Component limit={3} key='wtf-panel' />}
</BundleContainer>
<WhoToFollowPanel limit={3} />
)}
<LinkFooter key='link-footer' />
</Layout.Aside>

View File

@@ -4,7 +4,6 @@ import { useHistory } from 'react-router-dom';
import { Column, Layout, Tabs } from 'soapbox/components/ui';
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder-status';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import {
EventHeader,
CtaBanner,
@@ -65,9 +64,7 @@ const EventPage: React.FC<IEventPage> = ({ params, children }) => {
<Layout.Main>
<Column label={event?.name} withHeader={false}>
<div className='space-y-4'>
<BundleContainer fetchComponent={EventHeader}>
{Component => <Component status={status} />}
</BundleContainer>
<EventHeader status={status} />
{status && showTabs && (
<Tabs key={`event-tabs-${status.id}`} items={tabs} activeItem={activeItem} />
@@ -78,27 +75,19 @@ const EventPage: React.FC<IEventPage> = ({ params, children }) => {
</Column>
{!me && (
<BundleContainer fetchComponent={CtaBanner}>
{Component => <Component key='cta-banner' />}
</BundleContainer>
<CtaBanner />
)}
</Layout.Main>
<Layout.Aside>
{!me && (
<BundleContainer fetchComponent={SignUpPanel}>
{Component => <Component key='sign-up-panel' />}
</BundleContainer>
<SignUpPanel />
)}
{features.trends && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={5} key='trends-panel' />}
</BundleContainer>
<TrendsPanel limit={5} />
)}
{features.suggestions && (
<BundleContainer fetchComponent={WhoToFollowPanel}>
{Component => <Component limit={3} key='wtf-panel' />}
</BundleContainer>
<WhoToFollowPanel limit={3} />
)}
<LinkFooter key='link-footer' />
</Layout.Aside>

View File

@@ -2,7 +2,6 @@ import React from 'react';
import { Layout } from 'soapbox/components/ui';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import {
WhoToFollowPanel,
TrendsPanel,
@@ -25,18 +24,12 @@ const EventsPage: React.FC<IEventsPage> = ({ children }) => {
</Layout.Main>
<Layout.Aside>
<BundleContainer fetchComponent={NewEventPanel}>
{Component => <Component key='new-event-panel' />}
</BundleContainer>
<NewEventPanel />
{features.trends && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={5} key='trends-panel' />}
</BundleContainer>
<TrendsPanel limit={5} />
)}
{features.suggestions && (
<BundleContainer fetchComponent={WhoToFollowPanel}>
{Component => <Component limit={3} key='wtf-panel' />}
</BundleContainer>
<WhoToFollowPanel limit={3} />
)}
<LinkFooter key='link-footer' />
</Layout.Aside>

View File

@@ -6,7 +6,6 @@ import { useGroup, useGroupMembershipRequests } from 'soapbox/api/hooks';
import { Column, Icon, Layout, Stack, Text, Tabs } from 'soapbox/components/ui';
import GroupHeader from 'soapbox/features/group/components/group-header';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import {
CtaBanner,
GroupMediaPanel,
@@ -166,25 +165,17 @@ const GroupPage: React.FC<IGroupPage> = ({ params, children }) => {
</Column>
{!me && (
<BundleContainer fetchComponent={CtaBanner}>
{Component => <Component key='cta-banner' />}
</BundleContainer>
<CtaBanner />
)}
</Layout.Main>
<Layout.Aside>
{!me && (
<BundleContainer fetchComponent={SignUpPanel}>
{Component => <Component key='sign-up-panel' />}
</BundleContainer>
<SignUpPanel />
)}
<BundleContainer fetchComponent={GroupMediaPanel}>
{Component => <Component group={group} />}
</BundleContainer>
<BundleContainer fetchComponent={SuggestedGroupsPanel}>
{Component => <Component />}
</BundleContainer>
<LinkFooter key='link-footer' />
<GroupMediaPanel group={group} />
<SuggestedGroupsPanel />
<LinkFooter />
</Layout.Aside>
</>
);

View File

@@ -3,7 +3,6 @@ import { Route, Routes } from 'react-router-dom-v5-compat';
import { Column, Layout } from 'soapbox/components/ui';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { MyGroupsPanel, NewGroupPanel, SuggestedGroupsPanel } from 'soapbox/features/ui/util/async-components';
interface IGroupsPage {
@@ -22,26 +21,10 @@ const GroupsPage: React.FC<IGroupsPage> = ({ children }) => (
</Layout.Main>
<Layout.Aside>
<BundleContainer fetchComponent={NewGroupPanel}>
{Component => <Component />}
</BundleContainer>
<NewGroupPanel />
<Routes>
<Route
path='/groups'
element={(
<BundleContainer fetchComponent={SuggestedGroupsPanel}>
{Component => <Component />}
</BundleContainer>
)}
/>
<Route
path='/groups/discover'
element={(
<BundleContainer fetchComponent={MyGroupsPanel}>
{Component => <Component />}
</BundleContainer>
)}
/>
<Route path='/groups' element={<SuggestedGroupsPanel />} />
<Route path='/groups/discover' element={<MyGroupsPanel />} />
</Routes>
<LinkFooter />

View File

@@ -2,7 +2,6 @@ import React from 'react';
import { Layout } from 'soapbox/components/ui';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { NewGroupPanel, SuggestedGroupsPanel } from 'soapbox/features/ui/util/async-components';
interface IGroupsPage {
@@ -17,15 +16,9 @@ const GroupsPendingPage: React.FC<IGroupsPage> = ({ children }) => (
</Layout.Main>
<Layout.Aside>
<BundleContainer fetchComponent={NewGroupPanel}>
{Component => <Component key='new-group-panel' />}
</BundleContainer>
<BundleContainer fetchComponent={SuggestedGroupsPanel}>
{Component => <Component key='suggested-groups-panel' />}
</BundleContainer>
<LinkFooter key='link-footer' />
<NewGroupPanel />
<SuggestedGroupsPanel />
<LinkFooter />
</Layout.Aside>
</>
);

View File

@@ -20,7 +20,6 @@ import { useAppSelector, useOwnAccount, useFeatures, useSoapboxConfig, useDragge
import { Avatar, Card, CardBody, HStack, Layout } from '../components/ui';
import ComposeForm from '../features/compose/components/compose-form';
import BundleContainer from '../features/ui/containers/bundle-container';
interface IHomePage {
children: React.ReactNode;
@@ -83,52 +82,34 @@ const HomePage: React.FC<IHomePage> = ({ children }) => {
{children}
{!me && (
<BundleContainer fetchComponent={CtaBanner}>
{Component => <Component key='cta-banner' />}
</BundleContainer>
<CtaBanner />
)}
</Layout.Main>
<Layout.Aside>
{!me && (
<BundleContainer fetchComponent={SignUpPanel}>
{Component => <Component />}
</BundleContainer>
<SignUpPanel />
)}
{me && features.announcements && (
<BundleContainer fetchComponent={AnnouncementsPanel}>
{Component => <Component key='announcements-panel' />}
</BundleContainer>
<AnnouncementsPanel />
)}
{features.trends && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={5} />}
</BundleContainer>
<TrendsPanel limit={5} />
)}
{(hasPatron && me) && (
<BundleContainer fetchComponent={FundingPanel}>
{Component => <Component />}
</BundleContainer>
<FundingPanel />
)}
{(hasCrypto && cryptoLimit > 0 && me) && (
<BundleContainer fetchComponent={CryptoDonatePanel}>
{Component => <Component limit={cryptoLimit} />}
</BundleContainer>
<CryptoDonatePanel limit={cryptoLimit} />
)}
<BundleContainer fetchComponent={PromoPanel}>
{Component => <Component />}
</BundleContainer>
<PromoPanel />
{features.birthdays && (
<BundleContainer fetchComponent={BirthdayPanel}>
{Component => <Component limit={10} />}
</BundleContainer>
<BirthdayPanel limit={10} />
)}
{me && features.suggestions && (
<BundleContainer fetchComponent={WhoToFollowPanel}>
{Component => <Component limit={3} />}
</BundleContainer>
<WhoToFollowPanel limit={3} />
)}
<LinkFooter key='link-footer' />
<LinkFooter />
</Layout.Aside>
</>
);

View File

@@ -9,7 +9,6 @@ import {
import { useAppSelector, useFeatures } from 'soapbox/hooks';
import { Layout } from '../components/ui';
import BundleContainer from '../features/ui/containers/bundle-container';
interface ILandingPage {
children: React.ReactNode;
@@ -25,22 +24,16 @@ const LandingPage: React.FC<ILandingPage> = ({ children }) => {
{children}
{!me && (
<BundleContainer fetchComponent={CtaBanner}>
{Component => <Component />}
</BundleContainer>
<CtaBanner />
)}
</Layout.Main>
<Layout.Aside>
{!me && (
<BundleContainer fetchComponent={SignUpPanel}>
{Component => <Component />}
</BundleContainer>
<SignUpPanel />
)}
{features.trends && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={5} />}
</BundleContainer>
<TrendsPanel limit={5} />
)}
<LinkFooter />
</Layout.Aside>

View File

@@ -2,7 +2,6 @@ import React from 'react';
import { Layout } from 'soapbox/components/ui';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { MyGroupsPanel, NewGroupPanel } from 'soapbox/features/ui/util/async-components';
interface IGroupsPage {
@@ -17,13 +16,8 @@ const ManageGroupsPage: React.FC<IGroupsPage> = ({ children }) => (
</Layout.Main>
<Layout.Aside>
<BundleContainer fetchComponent={NewGroupPanel}>
{Component => <Component />}
</BundleContainer>
<BundleContainer fetchComponent={MyGroupsPanel}>
{Component => <Component />}
</BundleContainer>
<NewGroupPanel />
<MyGroupsPanel />
<LinkFooter />
</Layout.Aside>
</>

View File

@@ -6,7 +6,6 @@ import { useAccountLookup } from 'soapbox/api/hooks';
import { Column, Layout, Tabs } from 'soapbox/components/ui';
import Header from 'soapbox/features/account/components/header';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import {
WhoToFollowPanel,
ProfileInfoPanel,
@@ -92,10 +91,7 @@ const ProfilePage: React.FC<IProfilePage> = ({ params, children }) => {
<Column size='lg' label={account ? `@${getAcct(account, displayFqn)}` : ''} withHeader={false}>
<div className='space-y-4'>
<Header account={account} />
<BundleContainer fetchComponent={ProfileInfoPanel}>
{Component => <Component username={username} account={account} />}
</BundleContainer>
<ProfileInfoPanel username={username} account={account} />
{account && showTabs && (
<Tabs key={`profile-tabs-${account.id}`} items={tabItems} activeItem={activeItem} />
@@ -106,40 +102,26 @@ const ProfilePage: React.FC<IProfilePage> = ({ params, children }) => {
</Column>
{!me && (
<BundleContainer fetchComponent={CtaBanner}>
{Component => <Component key='cta-banner' />}
</BundleContainer>
<CtaBanner />
)}
</Layout.Main>
<Layout.Aside>
{!me && (
<BundleContainer fetchComponent={SignUpPanel}>
{Component => <Component key='sign-up-panel' />}
</BundleContainer>
<SignUpPanel />
)}
{features.notes && account && account?.id !== me && (
<BundleContainer fetchComponent={AccountNotePanel}>
{Component => <Component account={account} />}
</BundleContainer>
<AccountNotePanel account={account} />
)}
<BundleContainer fetchComponent={ProfileMediaPanel}>
{Component => <Component account={account} />}
</BundleContainer>
<ProfileMediaPanel account={account} />
{(account && account.fields.length > 0) && (
<BundleContainer fetchComponent={ProfileFieldsPanel}>
{Component => <Component account={account} />}
</BundleContainer>
<ProfileFieldsPanel account={account} />
)}
{(features.accountEndorsements && account && isLocal(account)) ? (
<BundleContainer fetchComponent={PinnedAccountsPanel}>
{Component => <Component account={account} limit={5} key='pinned-accounts-panel' />}
</BundleContainer>
<PinnedAccountsPanel account={account} limit={5} />
) : me && features.suggestions && (
<BundleContainer fetchComponent={WhoToFollowPanel}>
{Component => <Component limit={3} key='wtf-panel' />}
</BundleContainer>
<WhoToFollowPanel limit={3} />
)}
<LinkFooter key='link-footer' />
</Layout.Aside>

View File

@@ -1,7 +1,6 @@
import React from 'react';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import {
PromoPanel,
InstanceInfoPanel,
@@ -33,18 +32,12 @@ const RemoteInstancePage: React.FC<IRemoteInstancePage> = ({ children, params })
</Layout.Main>
<Layout.Aside>
<BundleContainer fetchComponent={PromoPanel}>
{Component => <Component key='promo-panel' />}
</BundleContainer>
<BundleContainer fetchComponent={InstanceInfoPanel}>
{Component => <Component host={host} />}
</BundleContainer>
<PromoPanel />
<InstanceInfoPanel host={host} />
{(disclosed || account?.admin) && (
<BundleContainer fetchComponent={InstanceModerationPanel}>
{Component => <Component host={host} />}
</BundleContainer>
<InstanceModerationPanel host={host} />
)}
<LinkFooter key='link-footer' />
<LinkFooter />
</Layout.Aside>
</>
);

View File

@@ -1,7 +1,6 @@
import React from 'react';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import {
WhoToFollowPanel,
TrendsPanel,
@@ -27,38 +26,28 @@ const SearchPage: React.FC<ISearchPage> = ({ children }) => {
{children}
{!me && (
<BundleContainer fetchComponent={CtaBanner}>
{Component => <Component key='cta-banner' />}
</BundleContainer>
<CtaBanner />
)}
</Layout.Main>
<Layout.Aside>
{!me && (
<BundleContainer fetchComponent={SignUpPanel}>
{Component => <Component key='sign-up-panel' />}
</BundleContainer>
<SignUpPanel />
)}
{features.trends && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={5} key='trends-panel' />}
</BundleContainer>
<TrendsPanel limit={5} />
)}
{me && features.suggestions && (
<BundleContainer fetchComponent={WhoToFollowPanel}>
{Component => <Component limit={3} key='wtf-panel' />}
</BundleContainer>
<WhoToFollowPanel limit={3} />
)}
{features.groups && (
<BundleContainer fetchComponent={SuggestedGroupsPanel}>
{Component => <Component key='suggested-groups-panel' />}
</BundleContainer>
<SuggestedGroupsPanel />
)}
<LinkFooter key='link-footer' />
<LinkFooter />
</Layout.Aside>
</>
);

View File

@@ -10,7 +10,6 @@ import {
import { useAppSelector, useFeatures } from 'soapbox/hooks';
import { Layout } from '../components/ui';
import BundleContainer from '../features/ui/containers/bundle-container';
interface IStatusPage {
children: React.ReactNode;
@@ -26,29 +25,21 @@ const StatusPage: React.FC<IStatusPage> = ({ children }) => {
{children}
{!me && (
<BundleContainer fetchComponent={CtaBanner}>
{Component => <Component key='cta-banner' />}
</BundleContainer>
<CtaBanner />
)}
</Layout.Main>
<Layout.Aside>
{!me && (
<BundleContainer fetchComponent={SignUpPanel}>
{Component => <Component key='sign-up-panel' />}
</BundleContainer>
<SignUpPanel />
)}
{features.trends && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={5} key='trends-panel' />}
</BundleContainer>
<TrendsPanel limit={5} />
)}
{me && features.suggestions && (
<BundleContainer fetchComponent={WhoToFollowPanel}>
{Component => <Component limit={3} key='wtf-panel' />}
</BundleContainer>
<WhoToFollowPanel limit={3} />
)}
<LinkFooter key='link-footer' />
<LinkFooter />
</Layout.Aside>
</>
);