Merge branch 'react-lazy' into 'main'
Delete Bundle component, switch to React.lazy See merge request soapbox-pub/soapbox!2779
This commit is contained in:
commit
74817c40b7
|
@ -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,
|
||||
};
|
|
@ -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} />
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
import { useGroupLookup } from 'soapbox/api/hooks';
|
||||
import ColumnLoading from 'soapbox/features/ui/components/column-loading';
|
||||
|
||||
import { Layout } from '../ui';
|
||||
|
||||
interface IGroupLookup {
|
||||
params: {
|
||||
groupSlug: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface IMaybeGroupLookup {
|
||||
params?: {
|
||||
groupSlug?: string;
|
||||
groupId?: string;
|
||||
};
|
||||
}
|
||||
|
||||
function GroupLookupHoc(Component: React.ComponentType<{ params: { groupId: string } }>) {
|
||||
const GroupLookup: React.FC<IGroupLookup> = (props) => {
|
||||
const { entity: group } = useGroupLookup(props.params.groupSlug);
|
||||
|
||||
if (!group) return (
|
||||
<>
|
||||
<Layout.Main>
|
||||
<ColumnLoading />
|
||||
</Layout.Main>
|
||||
|
||||
<Layout.Aside />
|
||||
</>
|
||||
);
|
||||
|
||||
const newProps = {
|
||||
...props,
|
||||
params: {
|
||||
...props.params,
|
||||
id: group.id,
|
||||
groupId: group.id,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<Component {...newProps} />
|
||||
);
|
||||
};
|
||||
|
||||
const MaybeGroupLookup: React.FC<IMaybeGroupLookup> = (props) => {
|
||||
const { params } = props;
|
||||
|
||||
if (params?.groupId) {
|
||||
return <Component {...props} params={{ ...params, groupId: params.groupId }} />;
|
||||
} else {
|
||||
return <GroupLookup {...props} params={{ ...params, groupSlug: params?.groupSlug || '' }} />;
|
||||
}
|
||||
};
|
||||
|
||||
return MaybeGroupLookup;
|
||||
}
|
||||
|
||||
export default GroupLookupHoc;
|
|
@ -1,11 +0,0 @@
|
|||
type HOC<P, R> = (Component: React.ComponentType<P>) => React.ComponentType<R>
|
||||
type AsyncComponent<P> = () => Promise<{ default: React.ComponentType<P> }>
|
||||
|
||||
const withHoc = <P, R>(asyncComponent: AsyncComponent<P>, hoc: HOC<P, R>) => {
|
||||
return async () => {
|
||||
const { default: component } = await asyncComponent();
|
||||
return { default: hoc(component) };
|
||||
};
|
||||
};
|
||||
|
||||
export default withHoc;
|
|
@ -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';
|
||||
|
@ -56,7 +55,7 @@ const handleMouseLeave = (dispatch: AppDispatch): React.MouseEventHandler => {
|
|||
};
|
||||
|
||||
interface IProfileHoverCard {
|
||||
visible: boolean;
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
/** Popup profile preview that appears when hovering avatars and display names. */
|
||||
|
@ -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}>
|
||||
|
|
|
@ -15,7 +15,7 @@ import { showStatusHoverCard } from './hover-status-wrapper';
|
|||
import { Card, CardBody } from './ui';
|
||||
|
||||
interface IStatusHoverCard {
|
||||
visible: boolean;
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
/** Popup status preview that appears when hovering reply to */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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'>
|
||||
|
|
|
@ -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
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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;
|
|
@ -9,12 +9,10 @@ import { useAppDispatch, useAppSelector, useTheme } from 'soapbox/hooks';
|
|||
import { RootState } from 'soapbox/store';
|
||||
|
||||
import { buildCustomEmojis } from '../../emoji';
|
||||
import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components';
|
||||
import { EmojiPicker } from '../../ui/util/async-components';
|
||||
|
||||
import type { Emoji, CustomEmoji, NativeEmoji } from 'soapbox/features/emoji';
|
||||
|
||||
let EmojiPicker: any; // load asynchronously
|
||||
|
||||
export const messages = defineMessages({
|
||||
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
|
||||
emoji_pick: { id: 'emoji_button.pick', defaultMessage: 'Pick an emoji…' },
|
||||
|
@ -136,8 +134,6 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
|
|||
const customEmojis = useAppSelector((state) => getCustomEmojis(state));
|
||||
const frequentlyUsedEmojis = useAppSelector((state) => getFrequentlyUsedEmojis(state));
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handlePick = (emoji: any) => {
|
||||
setVisible(false);
|
||||
|
||||
|
@ -210,18 +206,6 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
|
|||
} else {
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
if (!EmojiPicker) {
|
||||
setLoading(true);
|
||||
|
||||
EmojiPickerAsync().then(EmojiMart => {
|
||||
EmojiPicker = EmojiMart.Picker;
|
||||
|
||||
setLoading(false);
|
||||
}).catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
useEffect(() => () => {
|
||||
|
@ -231,23 +215,21 @@ const EmojiPickerDropdown: React.FC<IEmojiPickerDropdown> = ({
|
|||
return (
|
||||
visible ? (
|
||||
<RenderAfter update={update}>
|
||||
{!loading && (
|
||||
<EmojiPicker
|
||||
custom={withCustom ? [{ emojis: buildCustomEmojis(customEmojis) }] : undefined}
|
||||
title={title}
|
||||
onEmojiSelect={handlePick}
|
||||
recent={frequentlyUsedEmojis}
|
||||
perLine={8}
|
||||
skin={handleSkinTone}
|
||||
emojiSize={22}
|
||||
emojiButtonSize={34}
|
||||
set='twitter'
|
||||
theme={theme}
|
||||
i18n={getI18n()}
|
||||
skinTonePosition='search'
|
||||
previewPosition='none'
|
||||
/>
|
||||
)}
|
||||
<EmojiPicker
|
||||
custom={withCustom ? [{ emojis: buildCustomEmojis(customEmojis) }] : undefined}
|
||||
title={title}
|
||||
onEmojiSelect={handlePick}
|
||||
recent={frequentlyUsedEmojis}
|
||||
perLine={8}
|
||||
skin={handleSkinTone}
|
||||
emojiSize={22}
|
||||
emojiButtonSize={34}
|
||||
set='twitter'
|
||||
theme={theme}
|
||||
i18n={getI18n()}
|
||||
skinTonePosition='search'
|
||||
previewPosition='none'
|
||||
/>
|
||||
</RenderAfter>
|
||||
) : null
|
||||
);
|
||||
|
|
|
@ -13,7 +13,7 @@ const getImageURL = (set: string, name: string) => {
|
|||
return joinPublicPath(`/packs/emoji/${name}.svg`);
|
||||
};
|
||||
|
||||
const Picker = (props: any) => {
|
||||
const Picker: React.FC<any> = (props) => {
|
||||
const ref = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -25,6 +25,4 @@ const Picker = (props: any) => {
|
|||
return <div ref={ref} />;
|
||||
};
|
||||
|
||||
export {
|
||||
Picker,
|
||||
};
|
||||
export default Picker;
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { Column, Stack, Text, IconButton } from 'soapbox/components/ui';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' },
|
||||
body: { id: 'bundle_column_error.body', defaultMessage: 'Something went wrong while loading this page.' },
|
||||
retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' },
|
||||
});
|
||||
|
||||
interface IBundleColumnError {
|
||||
onRetry: () => void;
|
||||
}
|
||||
|
||||
const BundleColumnError: React.FC<IBundleColumnError> = ({ onRetry }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const handleRetry = () => {
|
||||
onRetry();
|
||||
};
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.title)}>
|
||||
<Stack space={4} alignItems='center' justifyContent='center' className='min-h-[160px] rounded-lg p-10'>
|
||||
<IconButton
|
||||
iconClassName='h-10 w-10'
|
||||
title={intl.formatMessage(messages.retry)}
|
||||
src={require('@tabler/icons/refresh.svg')}
|
||||
onClick={handleRetry}
|
||||
/>
|
||||
|
||||
<Text align='center' theme='muted'>{intl.formatMessage(messages.body)}</Text>
|
||||
</Stack>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
export default BundleColumnError;
|
|
@ -1,35 +0,0 @@
|
|||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { Modal } from 'soapbox/components/ui';
|
||||
|
||||
const messages = defineMessages({
|
||||
error: { id: 'bundle_modal_error.message', defaultMessage: 'Something went wrong while loading this modal.' },
|
||||
retry: { id: 'bundle_modal_error.retry', defaultMessage: 'Try again' },
|
||||
close: { id: 'bundle_modal_error.close', defaultMessage: 'Close' },
|
||||
});
|
||||
|
||||
interface IBundleModalError {
|
||||
onRetry: () => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const BundleModalError: React.FC<IBundleModalError> = ({ onRetry, onClose }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const handleRetry = () => {
|
||||
onRetry();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={intl.formatMessage(messages.error)}
|
||||
confirmationAction={onClose}
|
||||
confirmationText={intl.formatMessage(messages.close)}
|
||||
secondaryAction={handleRetry}
|
||||
secondaryText={intl.formatMessage(messages.retry)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default BundleModalError;
|
|
@ -1,114 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
const emptyComponent = () => null;
|
||||
const noop = () => { };
|
||||
|
||||
export interface BundleProps {
|
||||
fetchComponent: () => Promise<any>;
|
||||
loading: React.ComponentType;
|
||||
error: React.ComponentType<{ onRetry: (props?: BundleProps) => void }>;
|
||||
children: (mod: any) => React.ReactNode;
|
||||
renderDelay?: number;
|
||||
onFetch: () => void;
|
||||
onFetchSuccess: () => void;
|
||||
onFetchFail: (error: any) => void;
|
||||
}
|
||||
|
||||
interface BundleState {
|
||||
mod: any;
|
||||
forceRender: boolean;
|
||||
}
|
||||
|
||||
/** Fetches and renders an async component. */
|
||||
class Bundle extends React.PureComponent<BundleProps, BundleState> {
|
||||
|
||||
timeout: NodeJS.Timeout | undefined;
|
||||
timestamp: Date | undefined;
|
||||
|
||||
static defaultProps = {
|
||||
loading: emptyComponent,
|
||||
error: emptyComponent,
|
||||
renderDelay: 0,
|
||||
onFetch: noop,
|
||||
onFetchSuccess: noop,
|
||||
onFetchFail: noop,
|
||||
};
|
||||
|
||||
static cache = new Map;
|
||||
|
||||
state = {
|
||||
mod: undefined,
|
||||
forceRender: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.load(this.props);
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps: BundleProps) {
|
||||
if (nextProps.fetchComponent !== this.props.fetchComponent) {
|
||||
this.load(nextProps);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
}
|
||||
|
||||
load = (props?: BundleProps) => {
|
||||
const { fetchComponent, onFetch, onFetchSuccess, onFetchFail, renderDelay } = props || this.props;
|
||||
const cachedMod = Bundle.cache.get(fetchComponent);
|
||||
|
||||
if (fetchComponent === undefined) {
|
||||
this.setState({ mod: null });
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
onFetch();
|
||||
|
||||
if (cachedMod) {
|
||||
this.setState({ mod: cachedMod.default });
|
||||
onFetchSuccess();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.setState({ mod: undefined });
|
||||
|
||||
if (renderDelay !== 0) {
|
||||
this.timestamp = new Date();
|
||||
this.timeout = setTimeout(() => this.setState({ forceRender: true }), renderDelay);
|
||||
}
|
||||
|
||||
return fetchComponent()
|
||||
.then((mod) => {
|
||||
Bundle.cache.set(fetchComponent, mod);
|
||||
this.setState({ mod: mod.default });
|
||||
onFetchSuccess();
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({ mod: null });
|
||||
onFetchFail(error);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loading: Loading, error: Error, children, renderDelay } = this.props;
|
||||
const { mod, forceRender } = this.state;
|
||||
const elapsed = this.timestamp ? ((new Date()).getTime() - this.timestamp.getTime()) : renderDelay!;
|
||||
|
||||
if (mod === undefined) {
|
||||
return (elapsed >= renderDelay! || forceRender) ? <Loading /> : null;
|
||||
}
|
||||
|
||||
if (mod === null) {
|
||||
return <Error onRetry={this.load} />;
|
||||
}
|
||||
|
||||
return children(mod);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Bundle;
|
|
@ -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'>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React, { Suspense } from 'react';
|
||||
|
||||
import Base from 'soapbox/components/modal-root';
|
||||
import {
|
||||
|
@ -38,14 +38,10 @@ import {
|
|||
VideoModal,
|
||||
} from 'soapbox/features/ui/util/async-components';
|
||||
|
||||
import BundleContainer from '../containers/bundle-container';
|
||||
|
||||
import { BundleProps } from './bundle';
|
||||
import BundleModalError from './bundle-modal-error';
|
||||
import ModalLoading from './modal-loading';
|
||||
|
||||
/* eslint sort-keys: "error" */
|
||||
const MODAL_COMPONENTS = {
|
||||
const MODAL_COMPONENTS: Record<string, React.LazyExoticComponent<any>> = {
|
||||
'ACCOUNT_MODERATION': AccountModerationModal,
|
||||
'ACTIONS': ActionsModal,
|
||||
'BIRTHDAYS': BirthdaysModal,
|
||||
|
@ -104,14 +100,10 @@ export default class ModalRoot extends React.PureComponent<IModalRoot> {
|
|||
}
|
||||
}
|
||||
|
||||
renderLoading = (modalId: string) => () => {
|
||||
renderLoading = (modalId: string) => {
|
||||
return !['MEDIA', 'VIDEO', 'BOOST', 'CONFIRM', 'ACTIONS'].includes(modalId) ? <ModalLoading /> : null;
|
||||
};
|
||||
|
||||
renderError: React.ComponentType<{ onRetry: (props?: BundleProps) => void }> = (props) => {
|
||||
return <BundleModalError {...props} onClose={this.onClickClose} />;
|
||||
};
|
||||
|
||||
onClickClose = (_?: ModalType) => {
|
||||
const { onClose, type } = this.props;
|
||||
onClose(type);
|
||||
|
@ -119,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)} error={this.renderError} renderDelay={200}>
|
||||
{(SpecificComponent) => <SpecificComponent {...props} onClose={this.onClickClose} />}
|
||||
</BundleContainer>
|
||||
{(Component && !!type) && (
|
||||
<Suspense fallback={this.renderLoading(type)}>
|
||||
<Component {...props} onClose={this.onClickClose} />
|
||||
</Suspense>
|
||||
)}
|
||||
</Base>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import {
|
||||
|
@ -24,7 +24,6 @@ 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';
|
||||
|
||||
|
@ -94,9 +93,8 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
|
|||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const editorStateRef = useRef<string>(null);
|
||||
|
||||
const [tab, setTab] = useState<'edit' | 'pending'>('edit');
|
||||
const [text, setText] = useState('');
|
||||
|
||||
const banner = useAppSelector((state) => state.compose_event.banner);
|
||||
const isUploading = useAppSelector((state) => state.compose_event.is_uploading);
|
||||
|
@ -167,7 +165,7 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
|
|||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
dispatch(changeEditEventDescription(editorStateRef.current!));
|
||||
dispatch(changeEditEventDescription(text));
|
||||
dispatch(submitEvent());
|
||||
};
|
||||
|
||||
|
@ -235,18 +233,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
|
||||
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}
|
||||
onChange={setText}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
labelText={<FormattedMessage id='compose_event.fields.location_label' defaultMessage='Event location' />}
|
||||
|
@ -260,18 +254,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 +278,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 && (
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,8 +7,8 @@ import { submitAccountNote } from 'soapbox/actions/account-notes';
|
|||
import { HStack, Text, Widget } from 'soapbox/components/ui';
|
||||
import { useAppDispatch } from 'soapbox/hooks';
|
||||
|
||||
import type { Account as AccountEntity } from 'soapbox/schemas';
|
||||
import type { AppDispatch } from 'soapbox/store';
|
||||
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
||||
|
||||
const onSave = debounce(
|
||||
(dispatch: AppDispatch, id: string, value: string, callback: () => void) =>
|
||||
|
|
|
@ -5,11 +5,10 @@ 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';
|
||||
|
||||
import type { Account } from 'soapbox/types/entities';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
|
||||
interface IPinnedAccountsPanel {
|
||||
account: Account;
|
||||
|
@ -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} />
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import VerificationBadge from 'soapbox/components/verification-badge';
|
|||
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
import type { Account } from 'soapbox/types/entities';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Widget, Stack } from 'soapbox/components/ui';
|
|||
|
||||
import ProfileField from './profile-field';
|
||||
|
||||
import type { Account } from 'soapbox/types/entities';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
|
||||
interface IProfileFieldsPanel {
|
||||
account: Account;
|
||||
|
|
|
@ -15,7 +15,7 @@ import ProfileFamiliarFollowers from './profile-familiar-followers';
|
|||
import ProfileField from './profile-field';
|
||||
import ProfileStats from './profile-stats';
|
||||
|
||||
import type { Account } from 'soapbox/types/entities';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
|
||||
/** Basically ensure the URL isn't `javascript:alert('hi')` or something like that */
|
||||
const isSafeUrl = (text: string): boolean => {
|
||||
|
|
|
@ -10,7 +10,8 @@ import { getAccountGallery } from 'soapbox/selectors';
|
|||
|
||||
import MediaItem from '../../account-gallery/components/media-item';
|
||||
|
||||
import type { Account, Attachment } from 'soapbox/types/entities';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
import type { Attachment } from 'soapbox/types/entities';
|
||||
|
||||
interface IProfileMediaPanel {
|
||||
account?: Account;
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import { connect } from 'react-redux';
|
||||
|
||||
import { fetchBundleRequest, fetchBundleSuccess, fetchBundleFail } from 'soapbox/actions/bundles';
|
||||
|
||||
import Bundle from '../components/bundle';
|
||||
|
||||
import type { AppDispatch } from 'soapbox/store';
|
||||
|
||||
const mapDispatchToProps = (dispatch: AppDispatch) => ({
|
||||
onFetch() {
|
||||
dispatch(fetchBundleRequest());
|
||||
},
|
||||
onFetchSuccess() {
|
||||
dispatch(fetchBundleSuccess());
|
||||
},
|
||||
onFetchFail(error: any) {
|
||||
dispatch(fetchBundleFail(error));
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(null, mapDispatchToProps)(Bundle);
|
|
@ -1,5 +1,5 @@
|
|||
import clsx from 'clsx';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import React, { lazy, useEffect, useRef } from 'react';
|
||||
import { Switch, useHistory, useLocation, Redirect } from 'react-router-dom';
|
||||
|
||||
import { fetchFollowRequests } from 'soapbox/actions/accounts';
|
||||
|
@ -15,8 +15,6 @@ import { fetchSuggestionsForTimeline } from 'soapbox/actions/suggestions';
|
|||
import { expandHomeTimeline } from 'soapbox/actions/timelines';
|
||||
import { useUserStream } from 'soapbox/api/hooks';
|
||||
import { useSignerStream } from 'soapbox/api/hooks/nostr/useSignerStream';
|
||||
import GroupLookupHoc from 'soapbox/components/hoc/group-lookup-hoc';
|
||||
import withHoc from 'soapbox/components/hoc/with-hoc';
|
||||
import SidebarNavigation from 'soapbox/components/sidebar-navigation';
|
||||
import ThumbNavigation from 'soapbox/components/thumb-navigation';
|
||||
import { Layout } from 'soapbox/components/ui';
|
||||
|
@ -43,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,
|
||||
|
@ -147,16 +144,6 @@ import { WrappedRoute } from './util/react-router-helpers';
|
|||
// Without this it ends up in ~8 very commonly used bundles.
|
||||
import 'soapbox/components/status';
|
||||
|
||||
const GroupTagsSlug = withHoc(GroupTags as any, GroupLookupHoc);
|
||||
const GroupTagTimelineSlug = withHoc(GroupTagTimeline as any, GroupLookupHoc);
|
||||
const GroupTimelineSlug = withHoc(GroupTimeline as any, GroupLookupHoc);
|
||||
const GroupMembersSlug = withHoc(GroupMembers as any, GroupLookupHoc);
|
||||
const GroupGallerySlug = withHoc(GroupGallery as any, GroupLookupHoc);
|
||||
const ManageGroupSlug = withHoc(ManageGroup as any, GroupLookupHoc);
|
||||
const EditGroupSlug = withHoc(EditGroup as any, GroupLookupHoc);
|
||||
const GroupBlockedMembersSlug = withHoc(GroupBlockedMembers as any, GroupLookupHoc);
|
||||
const GroupMembershipRequestsSlug = withHoc(GroupMembershipRequests as any, GroupLookupHoc);
|
||||
|
||||
interface ISwitchingColumnsArea {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
@ -310,18 +297,6 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
|||
{features.groups && <WrappedRoute path='/groups/:groupId/manage/requests' exact page={ManageGroupsPage} component={GroupMembershipRequests} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/posts/:statusId' exact page={StatusPage} component={Status} content={children} />}
|
||||
|
||||
{features.groupsTags && <WrappedRoute path='/group/:groupSlug/tags' exact page={GroupPage} component={GroupTagsSlug} content={children} />}
|
||||
{features.groupsTags && <WrappedRoute path='/group/:groupSlug/tag/:tagId' exact page={GroupsPendingPage} component={GroupTagTimelineSlug} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug' publicRoute exact page={GroupPage} component={GroupTimelineSlug} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug/members' exact page={GroupPage} component={GroupMembersSlug} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug/media' publicRoute={!authenticatedProfile} component={GroupGallerySlug} page={GroupPage} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug/manage' exact page={ManageGroupsPage} component={ManageGroupSlug} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug/manage/edit' exact page={ManageGroupsPage} component={EditGroupSlug} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug/manage/blocks' exact page={ManageGroupsPage} component={GroupBlockedMembersSlug} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug/manage/requests' exact page={ManageGroupsPage} component={GroupMembershipRequestsSlug} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug/posts/:statusId' exact page={StatusPage} component={Status} content={children} />}
|
||||
{features.groups && <Redirect from='/group/:groupSlug/statuses/:statusId' to='/group/:groupSlug/posts/:statusId' />}
|
||||
|
||||
<WrappedRoute path='/statuses/new' page={DefaultPage} component={NewStatus} content={children} exact />
|
||||
<WrappedRoute path='/statuses/:statusId' exact page={StatusPage} component={Status} content={children} />
|
||||
{features.scheduledStatuses && <WrappedRoute path='/scheduled_statuses' page={DefaultPage} component={ScheduledStatuses} content={children} />}
|
||||
|
@ -354,7 +329,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
|||
<WrappedRoute path='/developers/timeline' developerOnly page={DefaultPage} component={TestTimeline} content={children} />
|
||||
<WrappedRoute path='/developers/sw' developerOnly page={DefaultPage} component={ServiceWorkerInfo} content={children} />
|
||||
<WrappedRoute path='/developers' page={DefaultPage} component={Developers} content={children} />
|
||||
<WrappedRoute path='/error/network' developerOnly page={EmptyPage} component={() => new Promise((_resolve, reject) => reject())} content={children} />
|
||||
<WrappedRoute path='/error/network' developerOnly page={EmptyPage} component={lazy(() => Promise.reject())} content={children} />
|
||||
<WrappedRoute path='/error' developerOnly page={EmptyPage} component={IntentionalError} content={children} />
|
||||
|
||||
{hasCrypto && <WrappedRoute path='/donate/crypto' publicRoute page={DefaultPage} component={CryptoDonate} content={children} />}
|
||||
|
@ -525,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>
|
||||
|
|
|
@ -1,647 +1,164 @@
|
|||
export function AboutPage() {
|
||||
return import('../../about');
|
||||
}
|
||||
|
||||
export function EmojiPicker() {
|
||||
return import('../../emoji/components/emoji-picker');
|
||||
}
|
||||
|
||||
export function Notifications() {
|
||||
return import('../../notifications');
|
||||
}
|
||||
|
||||
export function LandingTimeline() {
|
||||
return import('../../landing-timeline');
|
||||
}
|
||||
|
||||
export function HomeTimeline() {
|
||||
return import('../../home-timeline');
|
||||
}
|
||||
|
||||
export function PublicTimeline() {
|
||||
return import('../../public-timeline');
|
||||
}
|
||||
|
||||
export function RemoteTimeline() {
|
||||
return import('../../remote-timeline');
|
||||
}
|
||||
|
||||
export function CommunityTimeline() {
|
||||
return import('../../community-timeline');
|
||||
}
|
||||
|
||||
export function HashtagTimeline() {
|
||||
return import('../../hashtag-timeline');
|
||||
}
|
||||
|
||||
export function DirectTimeline() {
|
||||
return import('../../direct-timeline');
|
||||
}
|
||||
|
||||
export function Conversations() {
|
||||
return import('../../conversations');
|
||||
}
|
||||
|
||||
export function ListTimeline() {
|
||||
return import('../../list-timeline');
|
||||
}
|
||||
|
||||
export function Lists() {
|
||||
return import('../../lists');
|
||||
}
|
||||
|
||||
export function Bookmarks() {
|
||||
return import('../../bookmarks');
|
||||
}
|
||||
|
||||
export function Status() {
|
||||
return import('../../status');
|
||||
}
|
||||
|
||||
export function PinnedStatuses() {
|
||||
return import('../../pinned-statuses');
|
||||
}
|
||||
|
||||
export function AccountTimeline() {
|
||||
return import('../../account-timeline');
|
||||
}
|
||||
|
||||
export function AccountGallery() {
|
||||
return import('../../account-gallery');
|
||||
}
|
||||
|
||||
export function Followers() {
|
||||
return import('../../followers');
|
||||
}
|
||||
|
||||
export function Following() {
|
||||
return import('../../following');
|
||||
}
|
||||
|
||||
export function FollowRequests() {
|
||||
return import('../../follow-requests');
|
||||
}
|
||||
|
||||
export function GenericNotFound() {
|
||||
return import('../../generic-not-found');
|
||||
}
|
||||
|
||||
export function FavouritedStatuses() {
|
||||
return import('../../favourited-statuses');
|
||||
}
|
||||
|
||||
export function Blocks() {
|
||||
return import('../../blocks');
|
||||
}
|
||||
|
||||
export function DomainBlocks() {
|
||||
return import('../../domain-blocks');
|
||||
}
|
||||
|
||||
export function Mutes() {
|
||||
return import('../../mutes');
|
||||
}
|
||||
|
||||
export function MuteModal() {
|
||||
return import('../components/modals/mute-modal');
|
||||
}
|
||||
|
||||
export function Filters() {
|
||||
return import('../../filters');
|
||||
}
|
||||
|
||||
export function EditFilter() {
|
||||
return import('../../filters/edit-filter');
|
||||
}
|
||||
|
||||
export function ReportModal() {
|
||||
return import('../components/modals/report-modal/report-modal');
|
||||
}
|
||||
|
||||
export function AccountModerationModal() {
|
||||
return import('../components/modals/account-moderation-modal/account-moderation-modal');
|
||||
}
|
||||
|
||||
export function MediaGallery() {
|
||||
return import('../../../components/media-gallery');
|
||||
}
|
||||
|
||||
export function Video() {
|
||||
return import('../../video');
|
||||
}
|
||||
|
||||
export function Audio() {
|
||||
return import('../../audio');
|
||||
}
|
||||
|
||||
export function MediaModal() {
|
||||
return import('../components/modals/media-modal');
|
||||
}
|
||||
|
||||
export function VideoModal() {
|
||||
return import('../components/modals/video-modal');
|
||||
}
|
||||
|
||||
export function BoostModal() {
|
||||
return import('../components/modals/boost-modal');
|
||||
}
|
||||
|
||||
export function ConfirmationModal() {
|
||||
return import('../components/modals/confirmation-modal');
|
||||
}
|
||||
|
||||
export function MissingDescriptionModal() {
|
||||
return import('../components/modals/missing-description-modal');
|
||||
}
|
||||
|
||||
export function ActionsModal() {
|
||||
return import('../components/modals/actions-modal');
|
||||
}
|
||||
|
||||
export function HotkeysModal() {
|
||||
return import('../components/modals/hotkeys-modal');
|
||||
}
|
||||
|
||||
export function ComposeModal() {
|
||||
return import('../components/modals/compose-modal');
|
||||
}
|
||||
|
||||
export function ReplyMentionsModal() {
|
||||
return import('../components/modals/reply-mentions-modal');
|
||||
}
|
||||
|
||||
export function UnauthorizedModal() {
|
||||
return import('../components/modals/unauthorized-modal');
|
||||
}
|
||||
|
||||
export function EditFederationModal() {
|
||||
return import('../components/modals/edit-federation-modal');
|
||||
}
|
||||
|
||||
export function EmbedModal() {
|
||||
return import('../components/modals/embed-modal');
|
||||
}
|
||||
|
||||
export function ComponentModal() {
|
||||
return import('../components/modals/component-modal');
|
||||
}
|
||||
|
||||
export function ReblogsModal() {
|
||||
return import('../components/modals/reblogs-modal');
|
||||
}
|
||||
|
||||
export function FavouritesModal() {
|
||||
return import('../components/modals/favourites-modal');
|
||||
}
|
||||
|
||||
export function DislikesModal() {
|
||||
return import('../components/modals/dislikes-modal');
|
||||
}
|
||||
|
||||
export function ReactionsModal() {
|
||||
return import('../components/modals/reactions-modal');
|
||||
}
|
||||
|
||||
export function MentionsModal() {
|
||||
return import('../components/modals/mentions-modal');
|
||||
}
|
||||
|
||||
export function LandingPageModal() {
|
||||
return import('../components/modals/landing-page-modal');
|
||||
}
|
||||
|
||||
export function BirthdaysModal() {
|
||||
return import('../components/modals/birthdays-modal');
|
||||
}
|
||||
|
||||
export function BirthdayPanel() {
|
||||
return import('../../../components/birthday-panel');
|
||||
}
|
||||
|
||||
export function ListEditor() {
|
||||
return import('../../list-editor');
|
||||
}
|
||||
|
||||
export function ListAdder() {
|
||||
return import('../../list-adder');
|
||||
}
|
||||
|
||||
export function Search() {
|
||||
return import('../../search');
|
||||
}
|
||||
|
||||
export function LoginPage() {
|
||||
return import('../../auth-login/components/login-page');
|
||||
}
|
||||
|
||||
export function ExternalLogin() {
|
||||
return import('../../external-login');
|
||||
}
|
||||
|
||||
export function LogoutPage() {
|
||||
return import('../../auth-login/components/logout');
|
||||
}
|
||||
|
||||
export function RegistrationPage() {
|
||||
return import('../../auth-login/components/registration-page');
|
||||
}
|
||||
|
||||
export function Settings() {
|
||||
return import('../../settings');
|
||||
}
|
||||
|
||||
export function EditProfile() {
|
||||
return import('../../edit-profile');
|
||||
}
|
||||
|
||||
export function EditEmail() {
|
||||
return import('../../edit-email');
|
||||
}
|
||||
|
||||
export function EmailConfirmation() {
|
||||
return import('../../email-confirmation');
|
||||
}
|
||||
|
||||
export function EditPassword() {
|
||||
return import('../../edit-password');
|
||||
}
|
||||
|
||||
export function DeleteAccount() {
|
||||
return import('../../delete-account');
|
||||
}
|
||||
|
||||
export function SoapboxConfig() {
|
||||
return import('../../soapbox-config');
|
||||
}
|
||||
|
||||
export function ExportData() {
|
||||
return import('../../export-data');
|
||||
}
|
||||
|
||||
export function ImportData() {
|
||||
return import('../../import-data');
|
||||
}
|
||||
|
||||
export function Backups() {
|
||||
return import('../../backups');
|
||||
}
|
||||
|
||||
export function PasswordReset() {
|
||||
return import('../../auth-login/components/password-reset');
|
||||
}
|
||||
|
||||
export function PasswordResetConfirm() {
|
||||
return import('../../auth-login/components/password-reset-confirm');
|
||||
}
|
||||
|
||||
export function MfaForm() {
|
||||
return import('../../security/mfa-form');
|
||||
}
|
||||
|
||||
export function ChatIndex() {
|
||||
return import('../../chats');
|
||||
}
|
||||
|
||||
export function ChatWidget() {
|
||||
return import('../../chats/components/chat-widget/chat-widget');
|
||||
}
|
||||
|
||||
export function ServerInfo() {
|
||||
return import('../../server-info');
|
||||
}
|
||||
|
||||
export function Dashboard() {
|
||||
return import('../../admin');
|
||||
}
|
||||
|
||||
export function ModerationLog() {
|
||||
return import('../../admin/moderation-log');
|
||||
}
|
||||
|
||||
export function ThemeEditor() {
|
||||
return import('../../theme-editor');
|
||||
}
|
||||
|
||||
export function UserPanel() {
|
||||
return import('../components/user-panel');
|
||||
}
|
||||
|
||||
export function PromoPanel() {
|
||||
return import('../components/promo-panel');
|
||||
}
|
||||
|
||||
export function SignUpPanel() {
|
||||
return import('../components/panels/sign-up-panel');
|
||||
}
|
||||
|
||||
export function CtaBanner() {
|
||||
return import('../components/cta-banner');
|
||||
}
|
||||
|
||||
export function FundingPanel() {
|
||||
return import('../components/funding-panel');
|
||||
}
|
||||
|
||||
export function TrendsPanel() {
|
||||
return import('../components/trends-panel');
|
||||
}
|
||||
|
||||
export function ProfileInfoPanel() {
|
||||
return import('../components/profile-info-panel');
|
||||
}
|
||||
|
||||
export function ProfileMediaPanel() {
|
||||
return import('../components/profile-media-panel');
|
||||
}
|
||||
|
||||
export function ProfileFieldsPanel() {
|
||||
return import('../components/profile-fields-panel');
|
||||
}
|
||||
|
||||
export function PinnedAccountsPanel() {
|
||||
return import('../components/pinned-accounts-panel');
|
||||
}
|
||||
|
||||
export function InstanceInfoPanel() {
|
||||
return import('../components/instance-info-panel');
|
||||
}
|
||||
|
||||
export function InstanceModerationPanel() {
|
||||
return import('../components/instance-moderation-panel');
|
||||
}
|
||||
|
||||
export function LatestAccountsPanel() {
|
||||
return import('../../admin/components/latest-accounts-panel');
|
||||
}
|
||||
|
||||
export function SidebarMenu() {
|
||||
return import('../../../components/sidebar-menu');
|
||||
}
|
||||
|
||||
export function ModalContainer() {
|
||||
return import('../containers/modal-container');
|
||||
}
|
||||
|
||||
export function ProfileHoverCard() {
|
||||
return import('soapbox/components/profile-hover-card');
|
||||
}
|
||||
|
||||
export function StatusHoverCard() {
|
||||
return import('soapbox/components/status-hover-card');
|
||||
}
|
||||
|
||||
export function CryptoDonate() {
|
||||
return import('../../crypto-donate');
|
||||
}
|
||||
|
||||
export function CryptoDonatePanel() {
|
||||
return import('../../crypto-donate/components/crypto-donate-panel');
|
||||
}
|
||||
|
||||
export function CryptoAddress() {
|
||||
return import('../../crypto-donate/components/crypto-address');
|
||||
}
|
||||
|
||||
export function CryptoDonateModal() {
|
||||
return import('../components/modals/crypto-donate-modal');
|
||||
}
|
||||
|
||||
export function ScheduledStatuses() {
|
||||
return import('../../scheduled-statuses');
|
||||
}
|
||||
|
||||
export function UserIndex() {
|
||||
return import('../../admin/user-index');
|
||||
}
|
||||
|
||||
export function FederationRestrictions() {
|
||||
return import('../../federation-restrictions');
|
||||
}
|
||||
|
||||
export function Aliases() {
|
||||
return import('../../aliases');
|
||||
}
|
||||
|
||||
export function Migration() {
|
||||
return import('../../migration');
|
||||
}
|
||||
|
||||
export function ScheduleForm() {
|
||||
return import('../../compose/components/schedule-form');
|
||||
}
|
||||
|
||||
export function WhoToFollowPanel() {
|
||||
return import('../components/who-to-follow-panel');
|
||||
}
|
||||
|
||||
export function FollowRecommendations() {
|
||||
return import('../../follow-recommendations');
|
||||
}
|
||||
|
||||
export function Directory() {
|
||||
return import('../../directory');
|
||||
}
|
||||
|
||||
export function RegisterInvite() {
|
||||
return import('../../register-invite');
|
||||
}
|
||||
|
||||
export function Share() {
|
||||
return import('../../share');
|
||||
}
|
||||
|
||||
export function NewStatus() {
|
||||
return import('../../new-status');
|
||||
}
|
||||
|
||||
export function IntentionalError() {
|
||||
return import('../../intentional-error');
|
||||
}
|
||||
|
||||
export function Developers() {
|
||||
return import('../../developers');
|
||||
}
|
||||
|
||||
export function CreateApp() {
|
||||
return import('../../developers/apps/create');
|
||||
}
|
||||
|
||||
export function SettingsStore() {
|
||||
return import('../../developers/settings-store');
|
||||
}
|
||||
|
||||
export function TestTimeline() {
|
||||
return import('../../test-timeline');
|
||||
}
|
||||
|
||||
export function ServiceWorkerInfo() {
|
||||
return import('../../developers/service-worker-info');
|
||||
}
|
||||
|
||||
export function DatePicker() {
|
||||
return import('../../birthdays/date-picker');
|
||||
}
|
||||
|
||||
export function OnboardingWizard() {
|
||||
return import('../../onboarding/onboarding-wizard');
|
||||
}
|
||||
|
||||
export function CompareHistoryModal() {
|
||||
return import('../components/modals/compare-history-modal');
|
||||
}
|
||||
|
||||
export function AuthTokenList() {
|
||||
return import('../../auth-token-list');
|
||||
}
|
||||
|
||||
export function FamiliarFollowersModal() {
|
||||
return import('../components/modals/familiar-followers-modal');
|
||||
}
|
||||
|
||||
export function AnnouncementsPanel() {
|
||||
return import('../../../components/announcements/announcements-panel');
|
||||
}
|
||||
|
||||
export function Quotes() {
|
||||
return import('../../quotes');
|
||||
}
|
||||
|
||||
export function ComposeEventModal() {
|
||||
return import('../components/modals/compose-event-modal/compose-event-modal');
|
||||
}
|
||||
|
||||
export function JoinEventModal() {
|
||||
return import('../components/modals/join-event-modal');
|
||||
}
|
||||
|
||||
export function EventHeader() {
|
||||
return import('../../event/components/event-header');
|
||||
}
|
||||
|
||||
export function EventInformation() {
|
||||
return import('../../event/event-information');
|
||||
}
|
||||
|
||||
export function EventDiscussion() {
|
||||
return import('../../event/event-discussion');
|
||||
}
|
||||
|
||||
export function EventMapModal() {
|
||||
return import('../components/modals/event-map-modal');
|
||||
}
|
||||
|
||||
export function EventParticipantsModal() {
|
||||
return import('../components/modals/event-participants-modal');
|
||||
}
|
||||
|
||||
export function Events() {
|
||||
return import('../../events');
|
||||
}
|
||||
|
||||
export function Groups() {
|
||||
return import('../../groups');
|
||||
}
|
||||
|
||||
export function GroupsDiscover() {
|
||||
return import('../../groups/discover');
|
||||
}
|
||||
|
||||
export function GroupsPopular() {
|
||||
return import('../../groups/popular');
|
||||
}
|
||||
|
||||
export function GroupsSuggested() {
|
||||
return import('../../groups/suggested');
|
||||
}
|
||||
|
||||
export function GroupsTag() {
|
||||
return import('../../groups/tag');
|
||||
}
|
||||
|
||||
export function GroupsTags() {
|
||||
return import('../../groups/tags');
|
||||
}
|
||||
|
||||
export function PendingGroupRequests() {
|
||||
return import('../../groups/pending-requests');
|
||||
}
|
||||
|
||||
export function GroupMembers() {
|
||||
return import('../../group/group-members');
|
||||
}
|
||||
|
||||
export function GroupTags() {
|
||||
return import('../../group/group-tags');
|
||||
}
|
||||
|
||||
export function GroupTagTimeline() {
|
||||
return import('../../group/group-tag-timeline');
|
||||
}
|
||||
|
||||
export function GroupTimeline() {
|
||||
return import('../../group/group-timeline');
|
||||
}
|
||||
|
||||
export function ManageGroup() {
|
||||
return import('../../group/manage-group');
|
||||
}
|
||||
|
||||
export function EditGroup() {
|
||||
return import('../../group/edit-group');
|
||||
}
|
||||
|
||||
export function GroupBlockedMembers() {
|
||||
return import('../../group/group-blocked-members');
|
||||
}
|
||||
|
||||
export function GroupMembershipRequests() {
|
||||
return import('../../group/group-membership-requests');
|
||||
}
|
||||
|
||||
export function GroupGallery() {
|
||||
return import('../../group/group-gallery');
|
||||
}
|
||||
|
||||
export function CreateGroupModal() {
|
||||
return import('../components/modals/manage-group-modal/create-group-modal');
|
||||
}
|
||||
|
||||
export function NewGroupPanel() {
|
||||
return import('../components/panels/new-group-panel');
|
||||
}
|
||||
|
||||
export function MyGroupsPanel() {
|
||||
return import('../components/panels/my-groups-panel');
|
||||
}
|
||||
|
||||
export function SuggestedGroupsPanel() {
|
||||
return import('../components/panels/suggested-groups-panel');
|
||||
}
|
||||
|
||||
export function GroupMediaPanel() {
|
||||
return import('../components/group-media-panel');
|
||||
}
|
||||
|
||||
export function NewEventPanel() {
|
||||
return import('../components/panels/new-event-panel');
|
||||
}
|
||||
|
||||
export function Announcements() {
|
||||
return import('../../admin/announcements');
|
||||
}
|
||||
|
||||
export function EditAnnouncementModal() {
|
||||
return import('../components/modals/edit-announcement-modal');
|
||||
}
|
||||
|
||||
export function FollowedTags() {
|
||||
return import('../../followed-tags');
|
||||
}
|
||||
|
||||
export function AccountNotePanel() {
|
||||
return import('../components/panels/account-note-panel');
|
||||
}
|
||||
|
||||
export function ComposeEditor() {
|
||||
return import('../../compose/editor');
|
||||
}
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const AboutPage = lazy(() => import('soapbox/features/about'));
|
||||
export const EmojiPicker = lazy(() => import('soapbox/features/emoji/components/emoji-picker'));
|
||||
export const Notifications = lazy(() => import('soapbox/features/notifications'));
|
||||
export const LandingTimeline = lazy(() => import('soapbox/features/landing-timeline'));
|
||||
export const HomeTimeline = lazy(() => import('soapbox/features/home-timeline'));
|
||||
export const PublicTimeline = lazy(() => import('soapbox/features/public-timeline'));
|
||||
export const RemoteTimeline = lazy(() => import('soapbox/features/remote-timeline'));
|
||||
export const CommunityTimeline = lazy(() => import('soapbox/features/community-timeline'));
|
||||
export const HashtagTimeline = lazy(() => import('soapbox/features/hashtag-timeline'));
|
||||
export const DirectTimeline = lazy(() => import('soapbox/features/direct-timeline'));
|
||||
export const Conversations = lazy(() => import('soapbox/features/conversations'));
|
||||
export const ListTimeline = lazy(() => import('soapbox/features/list-timeline'));
|
||||
export const Lists = lazy(() => import('soapbox/features/lists'));
|
||||
export const Bookmarks = lazy(() => import('soapbox/features/bookmarks'));
|
||||
export const Status = lazy(() => import('soapbox/features/status'));
|
||||
export const PinnedStatuses = lazy(() => import('soapbox/features/pinned-statuses'));
|
||||
export const AccountTimeline = lazy(() => import('soapbox/features/account-timeline'));
|
||||
export const AccountGallery = lazy(() => import('soapbox/features/account-gallery'));
|
||||
export const Followers = lazy(() => import('soapbox/features/followers'));
|
||||
export const Following = lazy(() => import('soapbox/features/following'));
|
||||
export const FollowRequests = lazy(() => import('soapbox/features/follow-requests'));
|
||||
export const GenericNotFound = lazy(() => import('soapbox/features/generic-not-found'));
|
||||
export const FavouritedStatuses = lazy(() => import('soapbox/features/favourited-statuses'));
|
||||
export const Blocks = lazy(() => import('soapbox/features/blocks'));
|
||||
export const DomainBlocks = lazy(() => import('soapbox/features/domain-blocks'));
|
||||
export const Mutes = lazy(() => import('soapbox/features/mutes'));
|
||||
export const MuteModal = lazy(() => import('soapbox/features/ui/components/modals/mute-modal'));
|
||||
export const Filters = lazy(() => import('soapbox/features/filters'));
|
||||
export const EditFilter = lazy(() => import('soapbox/features/filters/edit-filter'));
|
||||
export const ReportModal = lazy(() => import('soapbox/features/ui/components/modals/report-modal/report-modal'));
|
||||
export const AccountModerationModal = lazy(() => import('soapbox/features/ui/components/modals/account-moderation-modal/account-moderation-modal'));
|
||||
export const MediaGallery = lazy(() => import('soapbox/components/media-gallery'));
|
||||
export const Video = lazy(() => import('soapbox/features/video'));
|
||||
export const Audio = lazy(() => import('soapbox/features/audio'));
|
||||
export const MediaModal = lazy(() => import('soapbox/features/ui/components/modals/media-modal'));
|
||||
export const VideoModal = lazy(() => import('soapbox/features/ui/components/modals/video-modal'));
|
||||
export const BoostModal = lazy(() => import('soapbox/features/ui/components/modals/boost-modal'));
|
||||
export const ConfirmationModal = lazy(() => import('soapbox/features/ui/components/modals/confirmation-modal'));
|
||||
export const MissingDescriptionModal = lazy(() => import('soapbox/features/ui/components/modals/missing-description-modal'));
|
||||
export const ActionsModal = lazy(() => import('soapbox/features/ui/components/modals/actions-modal'));
|
||||
export const HotkeysModal = lazy(() => import('soapbox/features/ui/components/modals/hotkeys-modal'));
|
||||
export const ComposeModal = lazy(() => import('soapbox/features/ui/components/modals/compose-modal'));
|
||||
export const ReplyMentionsModal = lazy(() => import('soapbox/features/ui/components/modals/reply-mentions-modal'));
|
||||
export const UnauthorizedModal = lazy(() => import('soapbox/features/ui/components/modals/unauthorized-modal'));
|
||||
export const EditFederationModal = lazy(() => import('soapbox/features/ui/components/modals/edit-federation-modal'));
|
||||
export const EmbedModal = lazy(() => import('soapbox/features/ui/components/modals/embed-modal'));
|
||||
export const ComponentModal = lazy(() => import('soapbox/features/ui/components/modals/component-modal'));
|
||||
export const ReblogsModal = lazy(() => import('soapbox/features/ui/components/modals/reblogs-modal'));
|
||||
export const FavouritesModal = lazy(() => import('soapbox/features/ui/components/modals/favourites-modal'));
|
||||
export const DislikesModal = lazy(() => import('soapbox/features/ui/components/modals/dislikes-modal'));
|
||||
export const ReactionsModal = lazy(() => import('soapbox/features/ui/components/modals/reactions-modal'));
|
||||
export const MentionsModal = lazy(() => import('soapbox/features/ui/components/modals/mentions-modal'));
|
||||
export const LandingPageModal = lazy(() => import('soapbox/features/ui/components/modals/landing-page-modal'));
|
||||
export const BirthdaysModal = lazy(() => import('soapbox/features/ui/components/modals/birthdays-modal'));
|
||||
export const BirthdayPanel = lazy(() => import('soapbox/components/birthday-panel'));
|
||||
export const ListEditor = lazy(() => import('soapbox/features/list-editor'));
|
||||
export const ListAdder = lazy(() => import('soapbox/features/list-adder'));
|
||||
export const Search = lazy(() => import('soapbox/features/search'));
|
||||
export const LoginPage = lazy(() => import('soapbox/features/auth-login/components/login-page'));
|
||||
export const ExternalLogin = lazy(() => import('soapbox/features/external-login'));
|
||||
export const LogoutPage = lazy(() => import('soapbox/features/auth-login/components/logout'));
|
||||
export const RegistrationPage = lazy(() => import('soapbox/features/auth-login/components/registration-page'));
|
||||
export const Settings = lazy(() => import('soapbox/features/settings'));
|
||||
export const EditProfile = lazy(() => import('soapbox/features/edit-profile'));
|
||||
export const EditEmail = lazy(() => import('soapbox/features/edit-email'));
|
||||
export const EmailConfirmation = lazy(() => import('soapbox/features/email-confirmation'));
|
||||
export const EditPassword = lazy(() => import('soapbox/features/edit-password'));
|
||||
export const DeleteAccount = lazy(() => import('soapbox/features/delete-account'));
|
||||
export const SoapboxConfig = lazy(() => import('soapbox/features/soapbox-config'));
|
||||
export const ExportData = lazy(() => import('soapbox/features/export-data'));
|
||||
export const ImportData = lazy(() => import('soapbox/features/import-data'));
|
||||
export const Backups = lazy(() => import('soapbox/features/backups'));
|
||||
export const PasswordReset = lazy(() => import('soapbox/features/auth-login/components/password-reset'));
|
||||
export const PasswordResetConfirm = lazy(() => import('soapbox/features/auth-login/components/password-reset-confirm'));
|
||||
export const MfaForm = lazy(() => import('soapbox/features/security/mfa-form'));
|
||||
export const ChatIndex = lazy(() => import('soapbox/features/chats'));
|
||||
export const ChatWidget = lazy(() => import('soapbox/features/chats/components/chat-widget/chat-widget'));
|
||||
export const ServerInfo = lazy(() => import('soapbox/features/server-info'));
|
||||
export const Dashboard = lazy(() => import('soapbox/features/admin'));
|
||||
export const ModerationLog = lazy(() => import('soapbox/features/admin/moderation-log'));
|
||||
export const ThemeEditor = lazy(() => import('soapbox/features/theme-editor'));
|
||||
export const UserPanel = lazy(() => import('soapbox/features/ui/components/user-panel'));
|
||||
export const PromoPanel = lazy(() => import('soapbox/features/ui/components/promo-panel'));
|
||||
export const SignUpPanel = lazy(() => import('soapbox/features/ui/components/panels/sign-up-panel'));
|
||||
export const CtaBanner = lazy(() => import('soapbox/features/ui/components/cta-banner'));
|
||||
export const FundingPanel = lazy(() => import('soapbox/features/ui/components/funding-panel'));
|
||||
export const TrendsPanel = lazy(() => import('soapbox/features/ui/components/trends-panel'));
|
||||
export const ProfileInfoPanel = lazy(() => import('soapbox/features/ui/components/profile-info-panel'));
|
||||
export const ProfileMediaPanel = lazy(() => import('soapbox/features/ui/components/profile-media-panel'));
|
||||
export const ProfileFieldsPanel = lazy(() => import('soapbox/features/ui/components/profile-fields-panel'));
|
||||
export const PinnedAccountsPanel = lazy(() => import('soapbox/features/ui/components/pinned-accounts-panel'));
|
||||
export const InstanceInfoPanel = lazy(() => import('soapbox/features/ui/components/instance-info-panel'));
|
||||
export const InstanceModerationPanel = lazy(() => import('soapbox/features/ui/components/instance-moderation-panel'));
|
||||
export const LatestAccountsPanel = lazy(() => import('soapbox/features/admin/components/latest-accounts-panel'));
|
||||
export const SidebarMenu = lazy(() => import('soapbox/components/sidebar-menu'));
|
||||
export const ModalContainer = lazy(() => import('soapbox/features/ui/containers/modal-container'));
|
||||
export const ProfileHoverCard = lazy(() => import('soapbox/components/profile-hover-card'));
|
||||
export const StatusHoverCard = lazy(() => import('soapbox/components/status-hover-card'));
|
||||
export const CryptoDonate = lazy(() => import('soapbox/features/crypto-donate'));
|
||||
export const CryptoDonatePanel = lazy(() => import('soapbox/features/crypto-donate/components/crypto-donate-panel'));
|
||||
export const CryptoAddress = lazy(() => import('soapbox/features/crypto-donate/components/crypto-address'));
|
||||
export const CryptoDonateModal = lazy(() => import('soapbox/features/ui/components/modals/crypto-donate-modal'));
|
||||
export const ScheduledStatuses = lazy(() => import('soapbox/features/scheduled-statuses'));
|
||||
export const UserIndex = lazy(() => import('soapbox/features/admin/user-index'));
|
||||
export const FederationRestrictions = lazy(() => import('soapbox/features/federation-restrictions'));
|
||||
export const Aliases = lazy(() => import('soapbox/features/aliases'));
|
||||
export const Migration = lazy(() => import('soapbox/features/migration'));
|
||||
export const ScheduleForm = lazy(() => import('soapbox/features/compose/components/schedule-form'));
|
||||
export const WhoToFollowPanel = lazy(() => import('soapbox/features/ui/components/who-to-follow-panel'));
|
||||
export const FollowRecommendations = lazy(() => import('soapbox/features/follow-recommendations'));
|
||||
export const Directory = lazy(() => import('soapbox/features/directory'));
|
||||
export const RegisterInvite = lazy(() => import('soapbox/features/register-invite'));
|
||||
export const Share = lazy(() => import('soapbox/features/share'));
|
||||
export const NewStatus = lazy(() => import('soapbox/features/new-status'));
|
||||
export const IntentionalError = lazy(() => import('soapbox/features/intentional-error'));
|
||||
export const Developers = lazy(() => import('soapbox/features/developers'));
|
||||
export const CreateApp = lazy(() => import('soapbox/features/developers/apps/create'));
|
||||
export const SettingsStore = lazy(() => import('soapbox/features/developers/settings-store'));
|
||||
export const TestTimeline = lazy(() => import('soapbox/features/test-timeline'));
|
||||
export const ServiceWorkerInfo = lazy(() => import('soapbox/features/developers/service-worker-info'));
|
||||
export const DatePicker = lazy(() => import('soapbox/features/birthdays/date-picker'));
|
||||
export const OnboardingWizard = lazy(() => import('soapbox/features/onboarding/onboarding-wizard'));
|
||||
export const CompareHistoryModal = lazy(() => import('soapbox/features/ui/components/modals/compare-history-modal'));
|
||||
export const AuthTokenList = lazy(() => import('soapbox/features/auth-token-list'));
|
||||
export const FamiliarFollowersModal = lazy(() => import('soapbox/features/ui/components/modals/familiar-followers-modal'));
|
||||
export const AnnouncementsPanel = lazy(() => import('soapbox/components/announcements/announcements-panel'));
|
||||
export const Quotes = lazy(() => import('soapbox/features/quotes'));
|
||||
export const ComposeEventModal = lazy(() => import('soapbox/features/ui/components/modals/compose-event-modal/compose-event-modal'));
|
||||
export const JoinEventModal = lazy(() => import('soapbox/features/ui/components/modals/join-event-modal'));
|
||||
export const EventHeader = lazy(() => import('soapbox/features/event/components/event-header'));
|
||||
export const EventInformation = lazy(() => import('soapbox/features/event/event-information'));
|
||||
export const EventDiscussion = lazy(() => import('soapbox/features/event/event-discussion'));
|
||||
export const EventMapModal = lazy(() => import('soapbox/features/ui/components/modals/event-map-modal'));
|
||||
export const EventParticipantsModal = lazy(() => import('soapbox/features/ui/components/modals/event-participants-modal'));
|
||||
export const Events = lazy(() => import('soapbox/features/events'));
|
||||
export const Groups = lazy(() => import('soapbox/features/groups'));
|
||||
export const GroupsDiscover = lazy(() => import('soapbox/features/groups/discover'));
|
||||
export const GroupsPopular = lazy(() => import('soapbox/features/groups/popular'));
|
||||
export const GroupsSuggested = lazy(() => import('soapbox/features/groups/suggested'));
|
||||
export const GroupsTag = lazy(() => import('soapbox/features/groups/tag'));
|
||||
export const GroupsTags = lazy(() => import('soapbox/features/groups/tags'));
|
||||
export const PendingGroupRequests = lazy(() => import('soapbox/features/groups/pending-requests'));
|
||||
export const GroupMembers = lazy(() => import('soapbox/features/group/group-members'));
|
||||
export const GroupTags = lazy(() => import('soapbox/features/group/group-tags'));
|
||||
export const GroupTagTimeline = lazy(() => import('soapbox/features/group/group-tag-timeline'));
|
||||
export const GroupTimeline = lazy(() => import('soapbox/features/group/group-timeline'));
|
||||
export const ManageGroup = lazy(() => import('soapbox/features/group/manage-group'));
|
||||
export const EditGroup = lazy(() => import('soapbox/features/group/edit-group'));
|
||||
export const GroupBlockedMembers = lazy(() => import('soapbox/features/group/group-blocked-members'));
|
||||
export const GroupMembershipRequests = lazy(() => import('soapbox/features/group/group-membership-requests'));
|
||||
export const GroupGallery = lazy(() => import('soapbox/features/group/group-gallery'));
|
||||
export const CreateGroupModal = lazy(() => import('soapbox/features/ui/components/modals/manage-group-modal/create-group-modal'));
|
||||
export const NewGroupPanel = lazy(() => import('soapbox/features/ui/components/panels/new-group-panel'));
|
||||
export const MyGroupsPanel = lazy(() => import('soapbox/features/ui/components/panels/my-groups-panel'));
|
||||
export const SuggestedGroupsPanel = lazy(() => import('soapbox/features/ui/components/panels/suggested-groups-panel'));
|
||||
export const GroupMediaPanel = lazy(() => import('soapbox/features/ui/components/group-media-panel'));
|
||||
export const NewEventPanel = lazy(() => import('soapbox/features/ui/components/panels/new-event-panel'));
|
||||
export const Announcements = lazy(() => import('soapbox/features/admin/announcements'));
|
||||
export const EditAnnouncementModal = lazy(() => import('soapbox/features/ui/components/modals/edit-announcement-modal'));
|
||||
export const FollowedTags = lazy(() => import('soapbox/features/followed-tags'));
|
||||
export const AccountNotePanel = lazy(() => import('soapbox/features/ui/components/panels/account-note-panel'));
|
||||
export const ComposeEditor = lazy(() => import('soapbox/features/compose/editor'));
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
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';
|
||||
import { useOwnAccount, useSettings } from 'soapbox/hooks';
|
||||
|
||||
import BundleColumnError from '../components/bundle-column-error';
|
||||
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'];
|
||||
|
@ -17,7 +15,7 @@ type PageProps = {
|
|||
};
|
||||
|
||||
interface IWrappedRoute extends RouteProps {
|
||||
component: (...args: any[]) => any;
|
||||
component: React.LazyExoticComponent<any>;
|
||||
page?: React.ComponentType<PageProps>;
|
||||
content?: React.ReactNode;
|
||||
componentParams?: Record<string, any>;
|
||||
|
@ -29,7 +27,7 @@ interface IWrappedRoute extends RouteProps {
|
|||
}
|
||||
|
||||
const WrappedRoute: React.FC<IWrappedRoute> = ({
|
||||
component,
|
||||
component: Component,
|
||||
page: Page,
|
||||
content,
|
||||
componentParams = {},
|
||||
|
@ -48,32 +46,24 @@ const WrappedRoute: React.FC<IWrappedRoute> = ({
|
|||
const renderComponent = ({ match }: RouteComponentProps) => {
|
||||
if (Page) {
|
||||
return (
|
||||
<BundleContainer fetchComponent={component} loading={renderLoading} error={renderError}>
|
||||
{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} error={renderError}>
|
||||
{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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -89,7 +79,6 @@ const WrappedRoute: React.FC<IWrappedRoute> = ({
|
|||
|
||||
const renderLoading = () => renderWithLayout(<ColumnLoading />);
|
||||
const renderForbidden = () => renderWithLayout(<ColumnForbidden />);
|
||||
const renderError = (props: any) => renderWithLayout(<BundleColumnError {...props} />);
|
||||
|
||||
const loginRedirect = () => {
|
||||
const actualUrl = encodeURIComponent(`${history.location.pathname}${history.location.search}`);
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
@ -31,7 +30,7 @@ const EventPage: React.FC<IEventPage> = ({ params, children }) => {
|
|||
const history = useHistory();
|
||||
const statusId = params?.statusId!;
|
||||
|
||||
const status = useAppSelector(state => getStatus(state, { id: statusId }));
|
||||
const status = useAppSelector(state => getStatus(state, { id: statusId }) || undefined);
|
||||
|
||||
const event = status?.event;
|
||||
|
||||
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -3,11 +3,9 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
|||
import { useRouteMatch } from 'react-router-dom';
|
||||
|
||||
import { useGroup, useGroupMembershipRequests } from 'soapbox/api/hooks';
|
||||
import GroupLookupHoc from 'soapbox/components/hoc/group-lookup-hoc';
|
||||
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,
|
||||
|
@ -167,28 +165,20 @@ 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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GroupLookupHoc(GroupPage as any) as any;
|
||||
export default GroupPage;
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
@ -21,7 +20,7 @@ interface IRemoteInstancePage {
|
|||
|
||||
/** Page for viewing a remote instance timeline. */
|
||||
const RemoteInstancePage: React.FC<IRemoteInstancePage> = ({ children, params }) => {
|
||||
const host = params?.instance;
|
||||
const host = params!.instance!;
|
||||
|
||||
const { account } = useOwnAccount();
|
||||
const disclosed = useAppSelector(federationRestrictionsDisclosed);
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue