Rename pages to layouts
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
6ace7722a6
commit
7cc98b7293
52 changed files with 271 additions and 372 deletions
|
@ -7,10 +7,7 @@ import { isLoggedIn } from 'soapbox/utils/auth';
|
|||
|
||||
import { getClient, type PlfeResponse } from '../api';
|
||||
|
||||
import {
|
||||
importFetchedAccount,
|
||||
importFetchedAccounts,
|
||||
} from './importer';
|
||||
import { importFetchedAccount, importFetchedAccounts } from './importer';
|
||||
|
||||
import type { Map as ImmutableMap } from 'immutable';
|
||||
import type { MinifiedStatus } from 'soapbox/reducers/statuses';
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { type Account as BaseAccount, type Group, type Poll, type Status as BaseStatus } from 'pl-api';
|
||||
|
||||
import { importEntities } from 'soapbox/entity-store/actions';
|
||||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { normalizeAccount, normalizeGroup } from 'soapbox/normalizers';
|
||||
|
||||
import type { Account as BaseAccount, Group, Poll, Status as BaseStatus } from 'pl-api';
|
||||
import type { AppDispatch } from 'soapbox/store';
|
||||
|
||||
const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT';
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import IntlMessageFormat from 'intl-messageformat';
|
||||
import 'intl-pluralrules';
|
||||
import { type Account, type Notification as BaseNotification, type PaginatedResponse, type Status } from 'pl-api';
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
import { getClient } from 'soapbox/api';
|
||||
|
@ -23,6 +22,7 @@ import {
|
|||
import { saveMarker } from './markers';
|
||||
import { getSettings, saveSettings } from './settings';
|
||||
|
||||
import type { Account, Notification as BaseNotification, PaginatedResponse, Status } from 'pl-api';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
||||
const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE' as const;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { type BookmarkFolder } from 'pl-api';
|
||||
|
||||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { selectEntity } from 'soapbox/entity-store/selectors';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import { useBookmarkFolders } from './useBookmarkFolders';
|
||||
|
||||
import type{ BookmarkFolder } from 'pl-api';
|
||||
|
||||
const useBookmarkFolder = (folderId?: string) => {
|
||||
const {
|
||||
isError,
|
||||
|
|
|
@ -3,10 +3,7 @@ import debounce from 'lodash/debounce';
|
|||
import React, { useRef } from 'react';
|
||||
|
||||
import { fetchAccount } from 'soapbox/actions/accounts';
|
||||
import {
|
||||
openProfileHoverCard,
|
||||
closeProfileHoverCard,
|
||||
} from 'soapbox/actions/profile-hover-card';
|
||||
import { openProfileHoverCard, closeProfileHoverCard } from 'soapbox/actions/profile-hover-card';
|
||||
import { useAppDispatch } from 'soapbox/hooks';
|
||||
import { isMobile } from 'soapbox/is-mobile';
|
||||
|
||||
|
|
|
@ -3,10 +3,7 @@ import debounce from 'lodash/debounce';
|
|||
import React, { useRef } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import {
|
||||
openStatusHoverCard,
|
||||
closeStatusHoverCard,
|
||||
} from 'soapbox/actions/status-hover-card';
|
||||
import { openStatusHoverCard, closeStatusHoverCard } from 'soapbox/actions/status-hover-card';
|
||||
import { isMobile } from 'soapbox/is-mobile';
|
||||
|
||||
const showStatusHoverCard = debounce((dispatch, ref, statusId) => {
|
||||
|
|
|
@ -5,10 +5,7 @@ import { usePopper } from 'react-popper';
|
|||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { fetchRelationships } from 'soapbox/actions/accounts';
|
||||
import {
|
||||
closeProfileHoverCard,
|
||||
updateProfileHoverCard,
|
||||
} from 'soapbox/actions/profile-hover-card';
|
||||
import { closeProfileHoverCard, updateProfileHoverCard } from 'soapbox/actions/profile-hover-card';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import Badge from 'soapbox/components/badge';
|
||||
import ActionButton from 'soapbox/features/ui/components/action-button';
|
||||
|
|
|
@ -4,10 +4,7 @@ import { useIntl } from 'react-intl';
|
|||
import { usePopper } from 'react-popper';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
closeStatusHoverCard,
|
||||
updateStatusHoverCard,
|
||||
} from 'soapbox/actions/status-hover-card';
|
||||
import { closeStatusHoverCard, updateStatusHoverCard } from 'soapbox/actions/status-hover-card';
|
||||
import { fetchStatus } from 'soapbox/actions/statuses';
|
||||
import StatusContainer from 'soapbox/containers/status-container';
|
||||
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { importEntities } from 'soapbox/entity-store/actions';
|
||||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { type Entity } from 'soapbox/entity-store/types';
|
||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch';
|
||||
import { useGetState } from 'soapbox/hooks/useGetState';
|
||||
|
||||
import type { Entity } from 'soapbox/entity-store/types';
|
||||
|
||||
type ChangeEntityFn<TEntity extends Entity> = (entity: TEntity) => TEntity
|
||||
|
||||
const useChangeEntity = <TEntity extends Entity = Entity>(entityType: Entities) => {
|
||||
|
|
|
@ -70,7 +70,7 @@ const RegistrationForm: React.FC<IRegistrationForm> = ({ inviteToken }) => {
|
|||
const controller = useRef(new AbortController());
|
||||
|
||||
const onInputChange: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement> = e => {
|
||||
setParams(params => ({ ...params, [e.target.name]: e.target.value }));
|
||||
setParams(params => ({ ...params, [e.target.name]: e.target.value }));
|
||||
};
|
||||
|
||||
const onUsernameChange: React.ChangeEventHandler<HTMLInputElement> = e => {
|
||||
|
|
|
@ -20,9 +20,7 @@ import {
|
|||
$isHeadingNode,
|
||||
HeadingTagType,
|
||||
} from '@lexical/rich-text';
|
||||
import {
|
||||
$setBlocksType,
|
||||
} from '@lexical/selection';
|
||||
import { $setBlocksType } from '@lexical/selection';
|
||||
import { $findMatchingParent, $getNearestNodeOfType, mergeRegister } from '@lexical/utils';
|
||||
import clsx from 'clsx';
|
||||
import {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
||||
import { $createRemarkExport } from '@mkljczk/lexical-remark';
|
||||
import { type LanguageIdentificationModel } from 'fasttext.wasm.js/dist/models/language-identification/common.js';
|
||||
import { $getRoot } from 'lexical';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
@ -11,6 +10,8 @@ import { fetchStatus } from 'soapbox/actions/statuses';
|
|||
import { useAppDispatch, useFeatures } from 'soapbox/hooks';
|
||||
import { getStatusIdsFromLinksInContent } from 'soapbox/utils/status';
|
||||
|
||||
import type { LanguageIdentificationModel } from 'fasttext.wasm.js/dist/models/language-identification/common.js';
|
||||
|
||||
let lidModel: LanguageIdentificationModel;
|
||||
|
||||
interface IStatePlugin {
|
||||
|
|
|
@ -3,10 +3,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||
import { useIntl, FormattedMessage, defineMessages } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
setupMfa,
|
||||
confirmMfa,
|
||||
} from 'soapbox/actions/mfa';
|
||||
import { setupMfa, confirmMfa } from 'soapbox/actions/mfa';
|
||||
import { Button, Form, FormActions, FormGroup, Input, Stack, Text } from 'soapbox/components/ui';
|
||||
import { useAppDispatch } from 'soapbox/hooks';
|
||||
import toast from 'soapbox/toast';
|
||||
|
|
|
@ -4,7 +4,6 @@ import { List as ImmutableList, OrderedSet as ImmutableOrderedSet } from 'immuta
|
|||
import React, { useEffect, useRef } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { type VirtuosoHandle } from 'react-virtuoso';
|
||||
|
||||
import { type ComposeReplyAction, mentionCompose, replyCompose } from 'soapbox/actions/compose';
|
||||
import { reblog, toggleFavourite, unreblog } from 'soapbox/actions/interactions';
|
||||
|
@ -25,6 +24,7 @@ import { textForScreenReader } from 'soapbox/utils/status';
|
|||
import DetailedStatus from './detailed-status';
|
||||
import ThreadStatus from './thread-status';
|
||||
|
||||
import type { VirtuosoHandle } from 'react-virtuoso';
|
||||
import type { Account, Status } from 'soapbox/normalizers';
|
||||
import type { SelectedStatus } from 'soapbox/selectors';
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import type { BaseModalProps } from '../modal-root';
|
|||
import type { MediaAttachment } from 'pl-api';
|
||||
import type { Account } from 'soapbox/normalizers';
|
||||
|
||||
|
||||
type VideoModalProps = {
|
||||
media: MediaAttachment;
|
||||
statusId: string;
|
||||
|
|
|
@ -18,22 +18,22 @@ import SidebarNavigation from 'soapbox/components/sidebar-navigation';
|
|||
import ThumbNavigation from 'soapbox/components/thumb-navigation';
|
||||
import { Layout } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useAppSelector, useOwnAccount, useSoapboxConfig, useFeatures, useDraggedFiles, useInstance, useLoggedIn } from 'soapbox/hooks';
|
||||
import AdminPage from 'soapbox/pages/admin-page';
|
||||
import ChatsPage from 'soapbox/pages/chats-page';
|
||||
import DefaultPage from 'soapbox/pages/default-page';
|
||||
import EmptyPage from 'soapbox/pages/empty-page';
|
||||
import EventPage from 'soapbox/pages/event-page';
|
||||
import EventsPage from 'soapbox/pages/events-page';
|
||||
import ExternalLoginPage from 'soapbox/pages/external-login-page';
|
||||
import GroupPage from 'soapbox/pages/group-page';
|
||||
import GroupsPage from 'soapbox/pages/groups-page';
|
||||
import HomePage from 'soapbox/pages/home-page';
|
||||
import LandingPage from 'soapbox/pages/landing-page';
|
||||
import ManageGroupsPage from 'soapbox/pages/manage-groups-page';
|
||||
import ProfilePage from 'soapbox/pages/profile-page';
|
||||
import RemoteInstancePage from 'soapbox/pages/remote-instance-page';
|
||||
import SearchPage from 'soapbox/pages/search-page';
|
||||
import StatusPage from 'soapbox/pages/status-page';
|
||||
import AdminLayout from 'soapbox/layouts/admin-layout';
|
||||
import ChatsLayout from 'soapbox/layouts/chats-layout';
|
||||
import DefaultLayout from 'soapbox/layouts/default-layout';
|
||||
import EmptyLayout from 'soapbox/layouts/empty-layout';
|
||||
import EventLayout from 'soapbox/layouts/event-layout';
|
||||
import EventsLayout from 'soapbox/layouts/events-layout';
|
||||
import ExternalLoginLayout from 'soapbox/layouts/external-login-layout';
|
||||
import GroupLayout from 'soapbox/layouts/group-layout';
|
||||
import GroupsLayout from 'soapbox/layouts/groups-layout';
|
||||
import HomeLayout from 'soapbox/layouts/home-layout';
|
||||
import LandingLayout from 'soapbox/layouts/landing-layout';
|
||||
import ManageGroupsLayout from 'soapbox/layouts/manage-groups-layout';
|
||||
import ProfileLayout from 'soapbox/layouts/profile-layout';
|
||||
import RemoteInstanceLayout from 'soapbox/layouts/remote-instance-layout';
|
||||
import SearchLayout from 'soapbox/layouts/search-layout';
|
||||
import StatusLayout from 'soapbox/layouts/status-layout';
|
||||
import { getVapidKey } from 'soapbox/utils/auth';
|
||||
import { isStandalone } from 'soapbox/utils/state';
|
||||
|
||||
|
@ -160,24 +160,24 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
|||
<Switch>
|
||||
{standalone && <Redirect from='/' to='/login/external' exact />}
|
||||
|
||||
<WrappedRoute path='/logout' page={EmptyPage} component={LogoutPage} publicRoute exact />
|
||||
<WrappedRoute path='/logout' layout={EmptyLayout} component={LogoutPage} publicRoute exact />
|
||||
|
||||
{isLoggedIn ? (
|
||||
<WrappedRoute path='/' exact page={HomePage} component={HomeTimeline} content={children} />
|
||||
<WrappedRoute path='/' exact layout={HomeLayout} component={HomeTimeline} content={children} />
|
||||
) : (
|
||||
<WrappedRoute path='/' exact page={LandingPage} component={LandingTimeline} content={children} publicRoute />
|
||||
<WrappedRoute path='/' exact layout={LandingLayout} component={LandingTimeline} content={children} publicRoute />
|
||||
)}
|
||||
|
||||
{/*
|
||||
NOTE: we cannot nest routes in a fragment
|
||||
https://stackoverflow.com/a/68637108
|
||||
*/}
|
||||
{features.federating && <WrappedRoute path='/timeline/local' exact page={HomePage} component={CommunityTimeline} content={children} publicRoute />}
|
||||
{features.federating && <WrappedRoute path='/timeline/fediverse' exact page={HomePage} component={PublicTimeline} content={children} publicRoute />}
|
||||
{features.bubbleTimeline && <WrappedRoute path='/timeline/bubble' exact page={HomePage} component={BubbleTimeline} content={children} publicRoute />}
|
||||
{features.federating && <WrappedRoute path='/timeline/:instance' exact page={RemoteInstancePage} component={RemoteTimeline} content={children} />}
|
||||
{features.federating && <WrappedRoute path='/timeline/local' exact layout={HomeLayout} component={CommunityTimeline} content={children} publicRoute />}
|
||||
{features.federating && <WrappedRoute path='/timeline/fediverse' exact layout={HomeLayout} component={PublicTimeline} content={children} publicRoute />}
|
||||
{features.bubbleTimeline && <WrappedRoute path='/timeline/bubble' exact layout={HomeLayout} component={BubbleTimeline} content={children} publicRoute />}
|
||||
{features.federating && <WrappedRoute path='/timeline/:instance' exact layout={RemoteInstanceLayout} component={RemoteTimeline} content={children} />}
|
||||
|
||||
{features.conversations && <WrappedRoute path='/conversations' page={DefaultPage} component={Conversations} content={children} />}
|
||||
{features.conversations && <WrappedRoute path='/conversations' layout={DefaultLayout} component={Conversations} content={children} />}
|
||||
{features.conversations && <Redirect from='/messages' to='/conversations' />}
|
||||
|
||||
{/* Mastodon web routes */}
|
||||
|
@ -195,7 +195,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
|||
<Redirect from='/main/friends' to='/' />
|
||||
<Redirect from='/tag/:id' to='/tags/:id' />
|
||||
<Redirect from='/user-settings' to='/settings/profile' />
|
||||
<WrappedRoute path='/notice/:statusId' publicRoute exact page={DefaultPage} component={Status} content={children} />
|
||||
<WrappedRoute path='/notice/:statusId' publicRoute exact layout={DefaultLayout} component={Status} content={children} />
|
||||
<Redirect from='/users/:username/statuses/:statusId' to='/@:username/posts/:statusId' />
|
||||
<Redirect from='/users/:username/chats' to='/chats' />
|
||||
<Redirect from='/users/:username' to='/@:username' />
|
||||
|
@ -226,120 +226,120 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
|||
<Redirect from='/auth/password/new' to='/reset-password' />
|
||||
<Redirect from='/auth/password/edit' to={`/edit-password${search}`} />
|
||||
|
||||
<WrappedRoute path='/tags/:id' publicRoute page={DefaultPage} component={HashtagTimeline} content={children} />
|
||||
<WrappedRoute path='/tags/:id' publicRoute layout={DefaultLayout} component={HashtagTimeline} content={children} />
|
||||
|
||||
{features.lists && <WrappedRoute path='/lists' page={DefaultPage} component={Lists} content={children} />}
|
||||
{features.lists && <WrappedRoute path='/list/:id' page={DefaultPage} component={ListTimeline} content={children} />}
|
||||
{features.bookmarks && <WrappedRoute path='/bookmarks/all' page={DefaultPage} component={Bookmarks} content={children} />}
|
||||
{features.bookmarks && <WrappedRoute path='/bookmarks/:id' page={DefaultPage} component={Bookmarks} content={children} />}
|
||||
<WrappedRoute path='/bookmarks' page={DefaultPage} component={BookmarkFolders} content={children} />
|
||||
{features.lists && <WrappedRoute path='/lists' layout={DefaultLayout} component={Lists} content={children} />}
|
||||
{features.lists && <WrappedRoute path='/list/:id' layout={DefaultLayout} component={ListTimeline} content={children} />}
|
||||
{features.bookmarks && <WrappedRoute path='/bookmarks/all' layout={DefaultLayout} component={Bookmarks} content={children} />}
|
||||
{features.bookmarks && <WrappedRoute path='/bookmarks/:id' layout={DefaultLayout} component={Bookmarks} content={children} />}
|
||||
<WrappedRoute path='/bookmarks' layout={DefaultLayout} component={BookmarkFolders} content={children} />
|
||||
|
||||
<WrappedRoute path='/notifications' page={DefaultPage} component={Notifications} content={children} />
|
||||
<WrappedRoute path='/notifications' layout={DefaultLayout} component={Notifications} content={children} />
|
||||
|
||||
<WrappedRoute path='/search' page={SearchPage} component={Search} content={children} publicRoute />
|
||||
{features.suggestions && <WrappedRoute path='/suggestions' publicRoute page={DefaultPage} component={FollowRecommendations} content={children} />}
|
||||
{features.profileDirectory && <WrappedRoute path='/directory' publicRoute page={DefaultPage} component={Directory} content={children} />}
|
||||
{features.events && <WrappedRoute path='/events' page={EventsPage} component={Events} content={children} />}
|
||||
<WrappedRoute path='/search' layout={SearchLayout} component={Search} content={children} publicRoute />
|
||||
{features.suggestions && <WrappedRoute path='/suggestions' publicRoute layout={DefaultLayout} component={FollowRecommendations} content={children} />}
|
||||
{features.profileDirectory && <WrappedRoute path='/directory' publicRoute layout={DefaultLayout} component={Directory} content={children} />}
|
||||
{features.events && <WrappedRoute path='/events' layout={EventsLayout} component={Events} content={children} />}
|
||||
|
||||
{features.chats && <WrappedRoute path='/chats' exact page={ChatsPage} component={ChatIndex} content={children} />}
|
||||
{features.chats && <WrappedRoute path='/chats/new' page={ChatsPage} component={ChatIndex} content={children} />}
|
||||
{features.chats && <WrappedRoute path='/chats/settings' page={ChatsPage} component={ChatIndex} content={children} />}
|
||||
{features.chats && <WrappedRoute path='/chats/:chatId' page={ChatsPage} component={ChatIndex} content={children} />}
|
||||
{features.chats && <WrappedRoute path='/chats' exact layout={ChatsLayout} component={ChatIndex} content={children} />}
|
||||
{features.chats && <WrappedRoute path='/chats/new' layout={ChatsLayout} component={ChatIndex} content={children} />}
|
||||
{features.chats && <WrappedRoute path='/chats/settings' layout={ChatsLayout} component={ChatIndex} content={children} />}
|
||||
{features.chats && <WrappedRoute path='/chats/:chatId' layout={ChatsLayout} component={ChatIndex} content={children} />}
|
||||
|
||||
<WrappedRoute path='/follow_requests' page={DefaultPage} component={FollowRequests} content={children} />
|
||||
<WrappedRoute path='/blocks' page={DefaultPage} component={Blocks} content={children} />
|
||||
{features.federating && <WrappedRoute path='/domain_blocks' page={DefaultPage} component={DomainBlocks} content={children} />}
|
||||
<WrappedRoute path='/mutes' page={DefaultPage} component={Mutes} content={children} />
|
||||
{(features.filters || features.filtersV2) && <WrappedRoute path='/filters/new' page={DefaultPage} component={EditFilter} content={children} />}
|
||||
{(features.filters || features.filtersV2) && <WrappedRoute path='/filters/:id' page={DefaultPage} component={EditFilter} content={children} />}
|
||||
{(features.filters || features.filtersV2) && <WrappedRoute path='/filters' page={DefaultPage} component={Filters} content={children} />}
|
||||
{(features.followedHashtagsList) && <WrappedRoute path='/followed_tags' page={DefaultPage} component={FollowedTags} content={children} />}
|
||||
<WrappedRoute path='/@:username' publicRoute exact component={AccountTimeline} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/with_replies' publicRoute={!authenticatedProfile} component={AccountTimeline} page={ProfilePage} content={children} componentParams={{ withReplies: true }} />
|
||||
<WrappedRoute path='/@:username/followers' publicRoute={!authenticatedProfile} component={Followers} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/following' publicRoute={!authenticatedProfile} component={Following} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/media' publicRoute={!authenticatedProfile} component={AccountGallery} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/tagged/:tag' exact component={AccountTimeline} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/favorites' component={FavouritedStatuses} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/pins' component={PinnedStatuses} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/posts/:statusId' publicRoute exact page={StatusPage} component={Status} content={children} />
|
||||
<WrappedRoute path='/@:username/posts/:statusId/quotes' publicRoute page={StatusPage} component={Quotes} content={children} />
|
||||
{features.events && <WrappedRoute path='/@:username/events/:statusId' publicRoute exact page={EventPage} component={EventInformation} content={children} />}
|
||||
{features.events && <WrappedRoute path='/@:username/events/:statusId/discussion' publicRoute exact page={EventPage} component={EventDiscussion} content={children} />}
|
||||
<WrappedRoute path='/follow_requests' layout={DefaultLayout} component={FollowRequests} content={children} />
|
||||
<WrappedRoute path='/blocks' layout={DefaultLayout} component={Blocks} content={children} />
|
||||
{features.federating && <WrappedRoute path='/domain_blocks' layout={DefaultLayout} component={DomainBlocks} content={children} />}
|
||||
<WrappedRoute path='/mutes' layout={DefaultLayout} component={Mutes} content={children} />
|
||||
{(features.filters || features.filtersV2) && <WrappedRoute path='/filters/new' layout={DefaultLayout} component={EditFilter} content={children} />}
|
||||
{(features.filters || features.filtersV2) && <WrappedRoute path='/filters/:id' layout={DefaultLayout} component={EditFilter} content={children} />}
|
||||
{(features.filters || features.filtersV2) && <WrappedRoute path='/filters' layout={DefaultLayout} component={Filters} content={children} />}
|
||||
{(features.followedHashtagsList) && <WrappedRoute path='/followed_tags' layout={DefaultLayout} component={FollowedTags} content={children} />}
|
||||
<WrappedRoute path='/@:username' publicRoute exact layout={ProfileLayout} component={AccountTimeline} content={children} />
|
||||
<WrappedRoute path='/@:username/with_replies' publicRoute={!authenticatedProfile} layout={ProfileLayout} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
|
||||
<WrappedRoute path='/@:username/followers' publicRoute={!authenticatedProfile} layout={ProfileLayout} component={Followers} content={children} />
|
||||
<WrappedRoute path='/@:username/following' publicRoute={!authenticatedProfile} layout={ProfileLayout} component={Following} content={children} />
|
||||
<WrappedRoute path='/@:username/media' publicRoute={!authenticatedProfile} layout={ProfileLayout} component={AccountGallery} content={children} />
|
||||
<WrappedRoute path='/@:username/tagged/:tag' exact layout={ProfileLayout} component={AccountTimeline} content={children} />
|
||||
<WrappedRoute path='/@:username/favorites' layout={ProfileLayout} component={FavouritedStatuses} content={children} />
|
||||
<WrappedRoute path='/@:username/pins' layout={ProfileLayout} component={PinnedStatuses} content={children} />
|
||||
<WrappedRoute path='/@:username/posts/:statusId' publicRoute exact layout={StatusLayout} component={Status} content={children} />
|
||||
<WrappedRoute path='/@:username/posts/:statusId/quotes' publicRoute layout={StatusLayout} component={Quotes} content={children} />
|
||||
{features.events && <WrappedRoute path='/@:username/events/:statusId' publicRoute exact layout={EventLayout} component={EventInformation} content={children} />}
|
||||
{features.events && <WrappedRoute path='/@:username/events/:statusId/discussion' publicRoute exact layout={EventLayout} component={EventDiscussion} content={children} />}
|
||||
<Redirect from='/@:username/:statusId' to='/@:username/posts/:statusId' />
|
||||
<WrappedRoute path='/posts/:statusId' publicRoute exact page={DefaultPage} component={Status} content={children} />
|
||||
<WrappedRoute path='/posts/:statusId' publicRoute exact layout={DefaultLayout} component={Status} content={children} />
|
||||
|
||||
{features.groups && <WrappedRoute path='/groups' exact page={GroupsPage} component={Groups} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId' exact page={GroupPage} component={GroupTimeline} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/members' exact page={GroupPage} component={GroupMembers} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/media' publicRoute={!authenticatedProfile} component={GroupGallery} page={GroupPage} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/manage' exact page={ManageGroupsPage} component={ManageGroup} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/manage/edit' exact page={ManageGroupsPage} component={EditGroup} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/manage/blocks' exact page={ManageGroupsPage} component={GroupBlockedMembers} content={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.groups && <WrappedRoute path='/groups' exact layout={GroupsLayout} component={Groups} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId' exact layout={GroupLayout} component={GroupTimeline} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/members' exact layout={GroupLayout} component={GroupMembers} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/media' publicRoute={!authenticatedProfile} layout={GroupLayout} component={GroupGallery} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/manage' exact layout={ManageGroupsLayout} component={ManageGroup} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/manage/edit' exact layout={ManageGroupsLayout} component={EditGroup} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/manage/blocks' exact layout={ManageGroupsLayout} component={GroupBlockedMembers} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/manage/requests' exact layout={ManageGroupsLayout} component={GroupMembershipRequests} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/groups/:groupId/posts/:statusId' exact layout={StatusLayout} component={Status} content={children} />}
|
||||
|
||||
<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} />}
|
||||
<WrappedRoute path='/draft_statuses' page={DefaultPage} component={DraftStatuses} content={children} />
|
||||
<WrappedRoute path='/statuses/new' layout={DefaultLayout} component={NewStatus} content={children} exact />
|
||||
<WrappedRoute path='/statuses/:statusId' exact layout={StatusLayout} component={Status} content={children} />
|
||||
{features.scheduledStatuses && <WrappedRoute path='/scheduled_statuses' layout={DefaultLayout} component={ScheduledStatuses} content={children} />}
|
||||
<WrappedRoute path='/draft_statuses' layout={DefaultLayout} component={DraftStatuses} content={children} />
|
||||
|
||||
<WrappedRoute path='/circle' page={DefaultPage} component={Circle} content={children} />
|
||||
<WrappedRoute path='/circle' layout={DefaultLayout} component={Circle} content={children} />
|
||||
|
||||
<WrappedRoute path='/settings/profile' page={DefaultPage} component={EditProfile} content={children} />
|
||||
{features.exportData && <WrappedRoute path='/settings/export' page={DefaultPage} component={ExportData} content={children} />}
|
||||
{(features.importBlocks || features.importFollows || features.importMutes) && <WrappedRoute path='/settings/import' page={DefaultPage} component={ImportData} content={children} />}
|
||||
{features.manageAccountAliases && <WrappedRoute path='/settings/aliases' page={DefaultPage} component={Aliases} content={children} />}
|
||||
{features.accountMoving && <WrappedRoute path='/settings/migration' page={DefaultPage} component={Migration} content={children} />}
|
||||
{features.accountBackups && <WrappedRoute path='/settings/backups' page={DefaultPage} component={Backups} content={children} />}
|
||||
<WrappedRoute path='/settings/email' page={DefaultPage} component={EditEmail} content={children} />
|
||||
<WrappedRoute path='/settings/password' page={DefaultPage} component={EditPassword} content={children} />
|
||||
<WrappedRoute path='/settings/account' page={DefaultPage} component={DeleteAccount} content={children} />
|
||||
<WrappedRoute path='/settings/mfa' page={DefaultPage} component={MfaForm} exact />
|
||||
<WrappedRoute path='/settings/tokens' page={DefaultPage} component={AuthTokenList} content={children} />
|
||||
<WrappedRoute path='/settings' page={DefaultPage} component={Settings} content={children} />
|
||||
<WrappedRoute path='/soapbox/config' adminOnly page={DefaultPage} component={SoapboxConfig} content={children} />
|
||||
<WrappedRoute path='/settings/profile' layout={DefaultLayout} component={EditProfile} content={children} />
|
||||
{features.exportData && <WrappedRoute path='/settings/export' layout={DefaultLayout} component={ExportData} content={children} />}
|
||||
{(features.importBlocks || features.importFollows || features.importMutes) && <WrappedRoute path='/settings/import' layout={DefaultLayout} component={ImportData} content={children} />}
|
||||
{features.manageAccountAliases && <WrappedRoute path='/settings/aliases' layout={DefaultLayout} component={Aliases} content={children} />}
|
||||
{features.accountMoving && <WrappedRoute path='/settings/migration' layout={DefaultLayout} component={Migration} content={children} />}
|
||||
{features.accountBackups && <WrappedRoute path='/settings/backups' layout={DefaultLayout} component={Backups} content={children} />}
|
||||
<WrappedRoute path='/settings/email' layout={DefaultLayout} component={EditEmail} content={children} />
|
||||
<WrappedRoute path='/settings/password' layout={DefaultLayout} component={EditPassword} content={children} />
|
||||
<WrappedRoute path='/settings/account' layout={DefaultLayout} component={DeleteAccount} content={children} />
|
||||
<WrappedRoute path='/settings/mfa' layout={DefaultLayout} component={MfaForm} exact />
|
||||
<WrappedRoute path='/settings/tokens' layout={DefaultLayout} component={AuthTokenList} content={children} />
|
||||
<WrappedRoute path='/settings' layout={DefaultLayout} component={Settings} content={children} />
|
||||
<WrappedRoute path='/soapbox/config' adminOnly layout={DefaultLayout} component={SoapboxConfig} content={children} />
|
||||
|
||||
<WrappedRoute path='/soapbox/admin' staffOnly page={AdminPage} component={Dashboard} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/approval' staffOnly page={AdminPage} component={Dashboard} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/reports' staffOnly page={AdminPage} component={Dashboard} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/log' staffOnly page={AdminPage} component={ModerationLog} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/users' staffOnly page={AdminPage} component={UserIndex} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/theme' staffOnly page={AdminPage} component={ThemeEditor} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/relays' staffOnly page={AdminPage} component={Relays} content={children} exact />
|
||||
{features.adminAnnouncements && <WrappedRoute path='/soapbox/admin/announcements' staffOnly page={AdminPage} component={Announcements} content={children} exact />}
|
||||
{features.domains && <WrappedRoute path='/soapbox/admin/domains' staffOnly page={AdminPage} component={Domains} content={children} exact />}
|
||||
{features.adminRules && <WrappedRoute path='/soapbox/admin/rules' staffOnly page={AdminPage} component={Rules} content={children} exact />}
|
||||
<WrappedRoute path='/info' page={EmptyPage} component={ServerInfo} content={children} />
|
||||
<WrappedRoute path='/soapbox/admin' staffOnly layout={AdminLayout} component={Dashboard} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/approval' staffOnly layout={AdminLayout} component={Dashboard} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/reports' staffOnly layout={AdminLayout} component={Dashboard} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/log' staffOnly layout={AdminLayout} component={ModerationLog} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/users' staffOnly layout={AdminLayout} component={UserIndex} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/theme' staffOnly layout={AdminLayout} component={ThemeEditor} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/relays' staffOnly layout={AdminLayout} component={Relays} content={children} exact />
|
||||
{features.adminAnnouncements && <WrappedRoute path='/soapbox/admin/announcements' staffOnly layout={AdminLayout} component={Announcements} content={children} exact />}
|
||||
{features.domains && <WrappedRoute path='/soapbox/admin/domains' staffOnly layout={AdminLayout} component={Domains} content={children} exact />}
|
||||
{features.adminRules && <WrappedRoute path='/soapbox/admin/rules' staffOnly layout={AdminLayout} component={Rules} content={children} exact />}
|
||||
<WrappedRoute path='/info' layout={EmptyLayout} component={ServerInfo} content={children} />
|
||||
|
||||
<WrappedRoute path='/developers/apps/create' developerOnly page={DefaultPage} component={CreateApp} content={children} />
|
||||
<WrappedRoute path='/developers/settings_store' developerOnly page={DefaultPage} component={SettingsStore} content={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={lazy(() => Promise.reject(new TypeError('Failed to fetch dynamically imported module: TEST')))} content={children} />
|
||||
<WrappedRoute path='/error' developerOnly page={EmptyPage} component={IntentionalError} content={children} />
|
||||
<WrappedRoute path='/developers/apps/create' developerOnly layout={DefaultLayout} component={CreateApp} content={children} />
|
||||
<WrappedRoute path='/developers/settings_store' developerOnly layout={DefaultLayout} component={SettingsStore} content={children} />
|
||||
<WrappedRoute path='/developers/timeline' developerOnly layout={DefaultLayout} component={TestTimeline} content={children} />
|
||||
<WrappedRoute path='/developers/sw' developerOnly layout={DefaultLayout} component={ServiceWorkerInfo} content={children} />
|
||||
<WrappedRoute path='/developers' layout={DefaultLayout} component={Developers} content={children} />
|
||||
<WrappedRoute path='/error/network' developerOnly layout={EmptyLayout} component={lazy(() => Promise.reject(new TypeError('Failed to fetch dynamically imported module: TEST')))} content={children} />
|
||||
<WrappedRoute path='/error' developerOnly layout={EmptyLayout} component={IntentionalError} content={children} />
|
||||
|
||||
{hasCrypto && <WrappedRoute path='/donate/crypto' publicRoute page={DefaultPage} component={CryptoDonate} content={children} />}
|
||||
{features.federating && <WrappedRoute path='/federation_restrictions' publicRoute page={DefaultPage} component={FederationRestrictions} content={children} />}
|
||||
{hasCrypto && <WrappedRoute path='/donate/crypto' publicRoute layout={DefaultLayout} component={CryptoDonate} content={children} />}
|
||||
{features.federating && <WrappedRoute path='/federation_restrictions' publicRoute layout={DefaultLayout} component={FederationRestrictions} content={children} />}
|
||||
|
||||
<WrappedRoute path='/share' page={DefaultPage} component={Share} content={children} exact />
|
||||
<WrappedRoute path='/share' layout={DefaultLayout} component={Share} content={children} exact />
|
||||
|
||||
<WrappedRoute path='/about/:slug?' page={DefaultPage} component={AboutPage} publicRoute exact />
|
||||
<WrappedRoute path='/about/:slug?' layout={DefaultLayout} component={AboutPage} publicRoute exact />
|
||||
|
||||
{(features.accountCreation && instance.registrations.enabled) && (
|
||||
<WrappedRoute path='/signup' page={EmptyPage} component={RegistrationPage} publicRoute exact />
|
||||
<WrappedRoute path='/signup' layout={EmptyLayout} component={RegistrationPage} publicRoute exact />
|
||||
)}
|
||||
|
||||
<WrappedRoute path='/login/external' page={ExternalLoginPage} component={ExternalLogin} publicRoute exact />
|
||||
<WrappedRoute path='/login/add' page={DefaultPage} component={LoginPage} publicRoute exact />
|
||||
<WrappedRoute path='/login' page={DefaultPage} component={LoginPage} publicRoute exact />
|
||||
<WrappedRoute path='/reset-password' page={DefaultPage} component={PasswordReset} publicRoute exact />
|
||||
<WrappedRoute path='/invite/:token' page={DefaultPage} component={RegisterInvite} publicRoute exact />
|
||||
<WrappedRoute path='/login/external' layout={ExternalLoginLayout} component={ExternalLogin} publicRoute exact />
|
||||
<WrappedRoute path='/login/add' layout={DefaultLayout} component={LoginPage} publicRoute exact />
|
||||
<WrappedRoute path='/login' layout={DefaultLayout} component={LoginPage} publicRoute exact />
|
||||
<WrappedRoute path='/reset-password' layout={DefaultLayout} component={PasswordReset} publicRoute exact />
|
||||
<WrappedRoute path='/invite/:token' layout={DefaultLayout} component={RegisterInvite} publicRoute exact />
|
||||
<Redirect from='/auth/password/new' to='/reset-password' />
|
||||
<Redirect from='/auth/password/edit' to={`/edit-password${search}`} />
|
||||
|
||||
<WrappedRoute page={EmptyPage} component={GenericNotFound} content={children} />
|
||||
<WrappedRoute layout={EmptyLayout} component={GenericNotFound} content={children} />
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -9,14 +9,14 @@ import ColumnForbidden from '../components/column-forbidden';
|
|||
import ColumnLoading from '../components/column-loading';
|
||||
import ErrorColumn from '../components/error-column';
|
||||
|
||||
type PageProps = {
|
||||
type LayoutProps = {
|
||||
params?: MatchType['params'];
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
interface IWrappedRoute extends RouteProps {
|
||||
component: React.LazyExoticComponent<any>;
|
||||
page: React.ComponentType<PageProps>;
|
||||
layout: React.ComponentType<LayoutProps>;
|
||||
content?: React.ReactNode;
|
||||
componentParams?: Record<string, any>;
|
||||
publicRoute?: boolean;
|
||||
|
@ -27,7 +27,7 @@ interface IWrappedRoute extends RouteProps {
|
|||
|
||||
const WrappedRoute: React.FC<IWrappedRoute> = ({
|
||||
component: Component,
|
||||
page: Page,
|
||||
layout: Layout,
|
||||
content,
|
||||
componentParams = {},
|
||||
publicRoute = false,
|
||||
|
@ -44,11 +44,11 @@ const WrappedRoute: React.FC<IWrappedRoute> = ({
|
|||
const renderComponent = ({ match }: RouteComponentProps) => (
|
||||
<ErrorBoundary FallbackComponent={FallbackError}>
|
||||
<Suspense fallback={<FallbackLoading />}>
|
||||
<Page params={match.params} {...componentParams}>
|
||||
<Layout params={match.params} {...componentParams}>
|
||||
<Component params={match.params} {...componentParams}>
|
||||
{content}
|
||||
</Component>
|
||||
</Page>
|
||||
</Layout>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
import React from 'react';
|
||||
|
||||
import { Layout } from 'soapbox/components/ui';
|
||||
import {
|
||||
LatestAccountsPanel,
|
||||
} from 'soapbox/features/ui/util/async-components';
|
||||
import { LatestAccountsPanel } from 'soapbox/features/ui/util/async-components';
|
||||
|
||||
import LinkFooter from '../features/ui/components/link-footer';
|
||||
|
||||
interface IAdminPage {
|
||||
interface IAdminLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const AdminPage: React.FC<IAdminPage> = ({ children }) => (
|
||||
const AdminLayout: React.FC<IAdminLayout> = ({ children }) => (
|
||||
<>
|
||||
<Layout.Main>
|
||||
{children}
|
||||
|
@ -24,4 +22,4 @@ const AdminPage: React.FC<IAdminPage> = ({ children }) => (
|
|||
</>
|
||||
);
|
||||
|
||||
export { AdminPage as default };
|
||||
export { AdminLayout as default };
|
|
@ -1,14 +1,14 @@
|
|||
import React from 'react';
|
||||
|
||||
interface IChatsPage {
|
||||
interface IChatsLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/** Custom layout for chats on desktop. */
|
||||
const ChatsPage: React.FC<IChatsPage> = ({ children }) => (
|
||||
const ChatsLayout: React.FC<IChatsLayout> = ({ children }) => (
|
||||
<div className='black:border-gray-800 md:col-span-12 lg:col-span-9 lg:black:border-l'>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export { ChatsPage as default };
|
||||
export { ChatsLayout as default };
|
|
@ -11,11 +11,11 @@ import { useAppSelector, useFeatures } from 'soapbox/hooks';
|
|||
|
||||
import { Layout } from '../components/ui';
|
||||
|
||||
interface IDefaultPage {
|
||||
interface IDefaultLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const DefaultPage: React.FC<IDefaultPage> = ({ children }) => {
|
||||
const DefaultLayout: React.FC<IDefaultLayout> = ({ children }) => {
|
||||
const me = useAppSelector(state => state.me);
|
||||
const features = useFeatures();
|
||||
|
||||
|
@ -45,4 +45,4 @@ const DefaultPage: React.FC<IDefaultPage> = ({ children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export { DefaultPage as default };
|
||||
export { DefaultLayout as default };
|
|
@ -2,11 +2,11 @@ import React from 'react';
|
|||
|
||||
import { Layout } from '../components/ui';
|
||||
|
||||
interface IEmptyPage {
|
||||
interface IEmptyLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const EmptyPage: React.FC<IEmptyPage> = ({ children }) => (
|
||||
const EmptyLayout: React.FC<IEmptyLayout> = ({ children }) => (
|
||||
<>
|
||||
<Layout.Main>
|
||||
{children}
|
||||
|
@ -16,4 +16,4 @@ const EmptyPage: React.FC<IEmptyPage> = ({ children }) => (
|
|||
</>
|
||||
);
|
||||
|
||||
export { EmptyPage as default };
|
||||
export { EmptyLayout as default };
|
|
@ -17,14 +17,14 @@ import { makeGetStatus } from 'soapbox/selectors';
|
|||
|
||||
const getStatus = makeGetStatus();
|
||||
|
||||
interface IEventPage {
|
||||
interface IEventLayout {
|
||||
params?: {
|
||||
statusId?: string;
|
||||
};
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const EventPage: React.FC<IEventPage> = ({ params, children }) => {
|
||||
const EventLayout: React.FC<IEventLayout> = ({ params, children }) => {
|
||||
const me = useAppSelector(state => state.me);
|
||||
const features = useFeatures();
|
||||
|
||||
|
@ -96,4 +96,4 @@ const EventPage: React.FC<IEventPage> = ({ params, children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export { EventPage as default };
|
||||
export { EventLayout as default };
|
|
@ -9,12 +9,12 @@ import {
|
|||
} from 'soapbox/features/ui/util/async-components';
|
||||
import { useFeatures } from 'soapbox/hooks';
|
||||
|
||||
interface IEventsPage {
|
||||
interface IEventsLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/** Page to display events list. */
|
||||
const EventsPage: React.FC<IEventsPage> = ({ children }) => {
|
||||
/** Layout to display events list. */
|
||||
const EventsLayout: React.FC<IEventsLayout> = ({ children }) => {
|
||||
const features = useFeatures();
|
||||
|
||||
return (
|
||||
|
@ -37,4 +37,4 @@ const EventsPage: React.FC<IEventsPage> = ({ children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export { EventsPage as default };
|
||||
export { EventsLayout as default };
|
|
@ -12,11 +12,11 @@ import { isStandalone } from 'soapbox/utils/state';
|
|||
|
||||
import { Layout } from '../components/ui';
|
||||
|
||||
interface IExternalLoginPage {
|
||||
interface IExternalLoginLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const ExternalLoginPage: React.FC<IExternalLoginPage> = ({ children }) => {
|
||||
const ExternalLoginLayout: React.FC<IExternalLoginLayout> = ({ children }) => {
|
||||
const me = useAppSelector(state => state.me);
|
||||
const features = useFeatures();
|
||||
const standalone = useAppSelector(isStandalone);
|
||||
|
@ -47,4 +47,4 @@ const ExternalLoginPage: React.FC<IExternalLoginPage> = ({ children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export { ExternalLoginPage as default };
|
||||
export { ExternalLoginLayout as default };
|
|
@ -19,7 +19,7 @@ const messages = defineMessages({
|
|||
media: { id: 'group.tabs.media', defaultMessage: 'Media' },
|
||||
});
|
||||
|
||||
interface IGroupPage {
|
||||
interface IGroupLayout {
|
||||
params?: {
|
||||
groupId?: string;
|
||||
};
|
||||
|
@ -44,8 +44,8 @@ const PrivacyBlankslate = () => (
|
|||
</Stack>
|
||||
);
|
||||
|
||||
/** Page to display a group. */
|
||||
const GroupPage: React.FC<IGroupPage> = ({ params, children }) => {
|
||||
/** Layout to display a group. */
|
||||
const GroupLayout: React.FC<IGroupLayout> = ({ params, children }) => {
|
||||
const intl = useIntl();
|
||||
const match = useRouteMatch();
|
||||
const { account: me } = useOwnAccount();
|
||||
|
@ -122,4 +122,4 @@ const GroupPage: React.FC<IGroupPage> = ({ params, children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export { GroupPage as default };
|
||||
export { GroupLayout as default };
|
|
@ -4,12 +4,12 @@ import { Column, Layout } from 'soapbox/components/ui';
|
|||
import LinkFooter from 'soapbox/features/ui/components/link-footer';
|
||||
import { MyGroupsPanel, NewGroupPanel } from 'soapbox/features/ui/util/async-components';
|
||||
|
||||
interface IGroupsPage {
|
||||
interface IGroupsLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/** Page to display groups. */
|
||||
const GroupsPage: React.FC<IGroupsPage> = ({ children }) => (
|
||||
/** Layout to display groups. */
|
||||
const GroupsLayout: React.FC<IGroupsLayout> = ({ children }) => (
|
||||
<>
|
||||
<Layout.Main>
|
||||
<Column withHeader={false}>
|
||||
|
@ -28,4 +28,4 @@ const GroupsPage: React.FC<IGroupsPage> = ({ children }) => (
|
|||
</>
|
||||
);
|
||||
|
||||
export { GroupsPage as default };
|
||||
export { GroupsLayout as default };
|
|
@ -21,11 +21,11 @@ import { useIsMobile } from 'soapbox/hooks/useIsMobile';
|
|||
import { Avatar, Card, CardBody, HStack, Layout } from '../components/ui';
|
||||
import ComposeForm from '../features/compose/components/compose-form';
|
||||
|
||||
interface IHomePage {
|
||||
interface IHomeLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const HomePage: React.FC<IHomePage> = ({ children }) => {
|
||||
const HomeLayout: React.FC<IHomeLayout> = ({ children }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
|
@ -114,4 +114,4 @@ const HomePage: React.FC<IHomePage> = ({ children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export { HomePage as default };
|
||||
export { HomeLayout as default };
|
|
@ -10,11 +10,11 @@ import { useAppSelector, useFeatures } from 'soapbox/hooks';
|
|||
|
||||
import { Layout } from '../components/ui';
|
||||
|
||||
interface ILandingPage {
|
||||
interface ILandingLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const LandingPage: React.FC<ILandingPage> = ({ children }) => {
|
||||
const LandingLayout: React.FC<ILandingLayout> = ({ children }) => {
|
||||
const me = useAppSelector(state => state.me);
|
||||
const features = useFeatures();
|
||||
|
||||
|
@ -41,4 +41,4 @@ const LandingPage: React.FC<ILandingPage> = ({ children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export { LandingPage as default };
|
||||
export { LandingLayout as default };
|
|
@ -4,12 +4,12 @@ import { Layout } from 'soapbox/components/ui';
|
|||
import LinkFooter from 'soapbox/features/ui/components/link-footer';
|
||||
import { MyGroupsPanel, NewGroupPanel } from 'soapbox/features/ui/util/async-components';
|
||||
|
||||
interface IGroupsPage {
|
||||
interface IGroupsLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/** Page to display groups. */
|
||||
const ManageGroupsPage: React.FC<IGroupsPage> = ({ children }) => (
|
||||
/** Layout to display groups. */
|
||||
const ManageGroupsLayout: React.FC<IGroupsLayout> = ({ children }) => (
|
||||
<>
|
||||
<Layout.Main>
|
||||
{children}
|
||||
|
@ -23,4 +23,4 @@ const ManageGroupsPage: React.FC<IGroupsPage> = ({ children }) => (
|
|||
</>
|
||||
);
|
||||
|
||||
export { ManageGroupsPage as default };
|
||||
export { ManageGroupsLayout as default };
|
|
@ -19,15 +19,15 @@ import {
|
|||
import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
|
||||
import { getAcct } from 'soapbox/utils/accounts';
|
||||
|
||||
interface IProfilePage {
|
||||
interface IProfileLayout {
|
||||
params?: {
|
||||
username?: string;
|
||||
};
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/** Page to display a user's profile. */
|
||||
const ProfilePage: React.FC<IProfilePage> = ({ params, children }) => {
|
||||
/** Layout to display a user's profile. */
|
||||
const ProfileLayout: React.FC<IProfileLayout> = ({ params, children }) => {
|
||||
const history = useHistory();
|
||||
const username = params?.username || '';
|
||||
|
||||
|
@ -129,4 +129,4 @@ const ProfilePage: React.FC<IProfilePage> = ({ params, children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export { ProfilePage as default };
|
||||
export { ProfileLayout as default };
|
|
@ -11,15 +11,15 @@ import { federationRestrictionsDisclosed } from 'soapbox/utils/state';
|
|||
|
||||
import { Layout } from '../components/ui';
|
||||
|
||||
interface IRemoteInstancePage {
|
||||
interface IRemoteInstanceLayout {
|
||||
params?: {
|
||||
instance?: string;
|
||||
};
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/** Page for viewing a remote instance timeline. */
|
||||
const RemoteInstancePage: React.FC<IRemoteInstancePage> = ({ children, params }) => {
|
||||
/** Layout for viewing a remote instance timeline. */
|
||||
const RemoteInstanceLayout: React.FC<IRemoteInstanceLayout> = ({ children, params }) => {
|
||||
const host = params!.instance!;
|
||||
|
||||
const { account } = useOwnAccount();
|
||||
|
@ -43,4 +43,4 @@ const RemoteInstancePage: React.FC<IRemoteInstancePage> = ({ children, params })
|
|||
);
|
||||
};
|
||||
|
||||
export { RemoteInstancePage as default };
|
||||
export { RemoteInstanceLayout as default };
|
|
@ -11,11 +11,11 @@ import { useAppSelector, useFeatures } from 'soapbox/hooks';
|
|||
|
||||
import { Layout } from '../components/ui';
|
||||
|
||||
interface ISearchPage {
|
||||
interface ISearchLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const SearchPage: React.FC<ISearchPage> = ({ children }) => {
|
||||
const SearchLayout: React.FC<ISearchLayout> = ({ children }) => {
|
||||
const me = useAppSelector(state => state.me);
|
||||
const features = useFeatures();
|
||||
|
||||
|
@ -48,4 +48,4 @@ const SearchPage: React.FC<ISearchPage> = ({ children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export { SearchPage as default };
|
||||
export { SearchLayout as default };
|
|
@ -11,11 +11,11 @@ import { useAppSelector, useFeatures } from 'soapbox/hooks';
|
|||
|
||||
import { Layout } from '../components/ui';
|
||||
|
||||
interface IStatusPage {
|
||||
interface IStatusLayout {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const StatusPage: React.FC<IStatusPage> = ({ children }) => {
|
||||
const StatusLayout: React.FC<IStatusLayout> = ({ children }) => {
|
||||
const me = useAppSelector(state => state.me);
|
||||
const features = useFeatures();
|
||||
|
||||
|
@ -45,4 +45,4 @@ const StatusPage: React.FC<IStatusPage> = ({ children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export { StatusPage as default };
|
||||
export { StatusLayout as default };
|
|
@ -1,4 +1,4 @@
|
|||
import { type ChatMessage as BaseChatMessage } from 'pl-api';
|
||||
import type { ChatMessage as BaseChatMessage } from 'pl-api';
|
||||
|
||||
const normalizeChatMessage = (chatMessage: BaseChatMessage & { pending?: boolean; deleting?: boolean }) => ({
|
||||
type: 'message' as const,
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import {
|
||||
BACKUPS_FETCH_SUCCESS,
|
||||
BACKUPS_CREATE_SUCCESS,
|
||||
} from '../actions/backups';
|
||||
import { BACKUPS_FETCH_SUCCESS, BACKUPS_CREATE_SUCCESS } from '../actions/backups';
|
||||
|
||||
import type { Backup } from 'pl-api';
|
||||
import type { AnyAction } from 'redux';
|
||||
|
|
|
@ -6,10 +6,7 @@ import {
|
|||
|
||||
import { STATUS_IMPORT, STATUSES_IMPORT } from 'soapbox/actions/importer';
|
||||
|
||||
import {
|
||||
ACCOUNT_BLOCK_SUCCESS,
|
||||
ACCOUNT_MUTE_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from '../actions/accounts';
|
||||
import {
|
||||
CONTEXT_FETCH_SUCCESS,
|
||||
STATUS_CREATE_REQUEST,
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import { Record as ImmutableRecord } from 'immutable';
|
||||
|
||||
import {
|
||||
DROPDOWN_MENU_OPEN,
|
||||
DROPDOWN_MENU_CLOSE,
|
||||
} from '../actions/dropdown-menu';
|
||||
import { DROPDOWN_MENU_OPEN, DROPDOWN_MENU_CLOSE } from '../actions/dropdown-menu';
|
||||
|
||||
import type { AnyAction } from 'redux';
|
||||
|
||||
|
|
|
@ -13,14 +13,8 @@ import {
|
|||
ACCOUNT_REMOVE_FROM_FOLLOWERS_SUCCESS,
|
||||
RELATIONSHIPS_FETCH_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import {
|
||||
DOMAIN_BLOCK_SUCCESS,
|
||||
DOMAIN_UNBLOCK_SUCCESS,
|
||||
} from '../actions/domain-blocks';
|
||||
import {
|
||||
ACCOUNT_IMPORT,
|
||||
ACCOUNTS_IMPORT,
|
||||
} from '../actions/importer';
|
||||
import { DOMAIN_BLOCK_SUCCESS, DOMAIN_UNBLOCK_SUCCESS } from '../actions/domain-blocks';
|
||||
import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer';
|
||||
|
||||
import type { AnyAction } from 'redux';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
|
|
@ -5,10 +5,7 @@ import {
|
|||
MFA_CONFIRM_SUCCESS,
|
||||
MFA_DISABLE_SUCCESS,
|
||||
} from '../actions/mfa';
|
||||
import {
|
||||
FETCH_TOKENS_SUCCESS,
|
||||
REVOKE_TOKEN_SUCCESS,
|
||||
} from '../actions/security';
|
||||
import { FETCH_TOKENS_SUCCESS, REVOKE_TOKEN_SUCCESS } from '../actions/security';
|
||||
|
||||
import type { OauthToken } from 'pl-api';
|
||||
import type { AnyAction } from 'redux';
|
||||
|
|
|
@ -54,10 +54,7 @@ import {
|
|||
UNPIN_SUCCESS,
|
||||
type InteractionsAction,
|
||||
} from '../actions/interactions';
|
||||
import {
|
||||
PINNED_STATUSES_FETCH_SUCCESS,
|
||||
type PinStatusesAction,
|
||||
} from '../actions/pin-statuses';
|
||||
import { PINNED_STATUSES_FETCH_SUCCESS, type PinStatusesAction } from '../actions/pin-statuses';
|
||||
import {
|
||||
SCHEDULED_STATUSES_FETCH_REQUEST,
|
||||
SCHEDULED_STATUSES_FETCH_SUCCESS,
|
||||
|
|
|
@ -4,10 +4,7 @@ import omit from 'lodash/omit';
|
|||
import { normalizeStatus, normalizeTranslation, Status as StatusRecord } from 'soapbox/normalizers';
|
||||
import { simulateEmojiReact, simulateUnEmojiReact } from 'soapbox/utils/emoji-reacts';
|
||||
|
||||
import {
|
||||
EMOJI_REACT_REQUEST,
|
||||
UNEMOJI_REACT_REQUEST,
|
||||
} from '../actions/emoji-reacts';
|
||||
import { EMOJI_REACT_REQUEST, UNEMOJI_REACT_REQUEST } from '../actions/emoji-reacts';
|
||||
import {
|
||||
EVENT_JOIN_REQUEST,
|
||||
EVENT_JOIN_FAIL,
|
||||
|
|
|
@ -6,15 +6,9 @@ import {
|
|||
} from 'immutable';
|
||||
import sample from 'lodash/sample';
|
||||
|
||||
import {
|
||||
ACCOUNT_BLOCK_SUCCESS,
|
||||
ACCOUNT_MUTE_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from '../actions/accounts';
|
||||
import { PIN_SUCCESS, UNPIN_SUCCESS } from '../actions/interactions';
|
||||
import {
|
||||
STATUS_CREATE_REQUEST,
|
||||
STATUS_CREATE_SUCCESS,
|
||||
} from '../actions/statuses';
|
||||
import { STATUS_CREATE_REQUEST, STATUS_CREATE_SUCCESS } from '../actions/statuses';
|
||||
import {
|
||||
TIMELINE_UPDATE,
|
||||
TIMELINE_DELETE,
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import { OrderedSet as ImmutableOrderedSet, Record as ImmutableRecord } from 'immutable';
|
||||
|
||||
import {
|
||||
TRENDING_STATUSES_FETCH_REQUEST,
|
||||
TRENDING_STATUSES_FETCH_SUCCESS,
|
||||
} from 'soapbox/actions/trending-statuses';
|
||||
import { TRENDING_STATUSES_FETCH_REQUEST, TRENDING_STATUSES_FETCH_SUCCESS } from 'soapbox/actions/trending-statuses';
|
||||
|
||||
import type { Status } from 'pl-api';
|
||||
import type { AnyAction } from 'redux';
|
||||
|
|
|
@ -34,9 +34,7 @@ import {
|
|||
EVENT_PARTICIPATION_REQUEST_AUTHORIZE_SUCCESS,
|
||||
EVENT_PARTICIPATION_REQUEST_REJECT_SUCCESS,
|
||||
} from 'soapbox/actions/events';
|
||||
import {
|
||||
FAMILIAR_FOLLOWERS_FETCH_SUCCESS,
|
||||
} from 'soapbox/actions/familiar-followers';
|
||||
import { FAMILIAR_FOLLOWERS_FETCH_SUCCESS } from 'soapbox/actions/familiar-followers';
|
||||
import {
|
||||
GROUP_BLOCKS_FETCH_REQUEST,
|
||||
GROUP_BLOCKS_FETCH_SUCCESS,
|
||||
|
@ -51,9 +49,7 @@ import {
|
|||
DISLIKES_FETCH_SUCCESS,
|
||||
REACTIONS_FETCH_SUCCESS,
|
||||
} from 'soapbox/actions/interactions';
|
||||
import {
|
||||
NOTIFICATIONS_UPDATE,
|
||||
} from 'soapbox/actions/notifications';
|
||||
import { NOTIFICATIONS_UPDATE } from 'soapbox/actions/notifications';
|
||||
|
||||
import type { Account, Notification, PaginatedResponse } from 'pl-api';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
|
|
@ -9,7 +9,6 @@ import { createSelector } from 'reselect';
|
|||
|
||||
import { getLocale, getSettings } from 'soapbox/actions/settings';
|
||||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { type MRFSimple } from 'soapbox/schemas/pleroma';
|
||||
import { getDomain } from 'soapbox/utils/accounts';
|
||||
import { validId } from 'soapbox/utils/auth';
|
||||
import ConfigDB from 'soapbox/utils/config-db';
|
||||
|
@ -20,6 +19,7 @@ import type { EntityStore } from 'soapbox/entity-store/types';
|
|||
import type { Account, Group, Notification } from 'soapbox/normalizers';
|
||||
import type { MinifiedNotification } from 'soapbox/reducers/notifications';
|
||||
import type { MinifiedStatus } from 'soapbox/reducers/statuses';
|
||||
import type { MRFSimple } from 'soapbox/schemas/pleroma';
|
||||
import type { RootState } from 'soapbox/store';
|
||||
|
||||
const normalizeId = (id: any): string => typeof id === 'string' ? id : typeof id === 'object' ? normalizeId(id.id) : '';
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
import {
|
||||
AdminAccountRecord,
|
||||
AdminReportRecord,
|
||||
} from 'soapbox/normalizers';
|
||||
import { AdminAccountRecord, AdminReportRecord } from 'soapbox/normalizers';
|
||||
|
||||
type AdminAccount = ReturnType<typeof AdminAccountRecord>;
|
||||
type AdminReport = ReturnType<typeof AdminReportRecord>;
|
||||
|
|
|
@ -24,23 +24,23 @@ const ALLOWED_EMOJI = ImmutableList([
|
|||
describe('sortEmoji', () => {
|
||||
describe('with an unsorted list of emoji', () => {
|
||||
const emojiReacts = ImmutableList([
|
||||
{ 'count': 7, 'me': true, 'name': '😃' },
|
||||
{ 'count': 7, 'me': true, 'name': '😯' },
|
||||
{ 'count': 3, 'me': true, 'name': '😢' },
|
||||
{ 'count': 1, 'me': true, 'name': '😡' },
|
||||
{ 'count': 7, 'me': true, 'name': '😃' },
|
||||
{ 'count': 7, 'me': true, 'name': '😯' },
|
||||
{ 'count': 3, 'me': true, 'name': '😢' },
|
||||
{ 'count': 1, 'me': true, 'name': '😡' },
|
||||
{ 'count': 20, 'me': true, 'name': '👍' },
|
||||
{ 'count': 7, 'me': true, 'name': '😂' },
|
||||
{ 'count': 7, 'me': true, 'name': '😂' },
|
||||
{ 'count': 15, 'me': true, 'name': '❤' },
|
||||
].map((react) => emojiReactionSchema.parse(react)));
|
||||
it('sorts the emoji by count', () => {
|
||||
expect(sortEmoji(emojiReacts, ALLOWED_EMOJI)).toEqual(fromJS([
|
||||
{ 'count': 20, 'me': true, 'name': '👍' },
|
||||
{ 'count': 15, 'me': true, 'name': '❤' },
|
||||
{ 'count': 7, 'me': true, 'name': '😯' },
|
||||
{ 'count': 7, 'me': true, 'name': '😂' },
|
||||
{ 'count': 7, 'me': true, 'name': '😃' },
|
||||
{ 'count': 3, 'me': true, 'name': '😢' },
|
||||
{ 'count': 1, 'me': true, 'name': '😡' },
|
||||
{ 'count': 7, 'me': true, 'name': '😯' },
|
||||
{ 'count': 7, 'me': true, 'name': '😂' },
|
||||
{ 'count': 7, 'me': true, 'name': '😃' },
|
||||
{ 'count': 3, 'me': true, 'name': '😢' },
|
||||
{ 'count': 1, 'me': true, 'name': '😡' },
|
||||
]));
|
||||
});
|
||||
});
|
||||
|
@ -54,13 +54,13 @@ describe('mergeEmojiFavourites', () => {
|
|||
const emojiReacts = ImmutableList([
|
||||
{ 'count': 20, 'me': false, 'name': '👍', 'url': undefined },
|
||||
{ 'count': 15, 'me': false, 'name': '❤', 'url': undefined },
|
||||
{ 'count': 7, 'me': false, 'name': '😯', 'url': undefined },
|
||||
{ 'count': 7, 'me': false, 'name': '😯', 'url': undefined },
|
||||
].map((react) => emojiReactionSchema.parse(react)));
|
||||
it('combines 👍 reacts with favourites', () => {
|
||||
expect(mergeEmojiFavourites(emojiReacts, favouritesCount, favourited)).toEqual(fromJS([
|
||||
{ 'count': 32, 'me': true, 'name': '👍', 'url': undefined },
|
||||
{ 'count': 32, 'me': true, 'name': '👍', 'url': undefined },
|
||||
{ 'count': 15, 'me': false, 'name': '❤', 'url': undefined },
|
||||
{ 'count': 7, 'me': false, 'name': '😯', 'url': undefined },
|
||||
{ 'count': 7, 'me': false, 'name': '😯', 'url': undefined },
|
||||
]));
|
||||
});
|
||||
});
|
||||
|
@ -68,19 +68,19 @@ describe('mergeEmojiFavourites', () => {
|
|||
describe('without existing 👍 reacts', () => {
|
||||
const emojiReacts = ImmutableList([
|
||||
{ 'count': 15, 'me': false, 'name': '❤' },
|
||||
{ 'count': 7, 'me': false, 'name': '😯' },
|
||||
{ 'count': 7, 'me': false, 'name': '😯' },
|
||||
].map((react) => emojiReactionSchema.parse(react)));
|
||||
it('adds 👍 reacts to the map equaling favourite count', () => {
|
||||
expect(mergeEmojiFavourites(emojiReacts, favouritesCount, favourited)).toEqual(fromJS([
|
||||
{ 'count': 15, 'me': false, 'name': '❤' },
|
||||
{ 'count': 7, 'me': false, 'name': '😯' },
|
||||
{ 'count': 12, 'me': true, 'name': '👍' },
|
||||
{ 'count': 7, 'me': false, 'name': '😯' },
|
||||
{ 'count': 12, 'me': true, 'name': '👍' },
|
||||
]));
|
||||
});
|
||||
it('does not add 👍 reacts when there are no favourites', () => {
|
||||
expect(mergeEmojiFavourites(emojiReacts, 0, false)).toEqual(fromJS([
|
||||
{ 'count': 15, 'me': false, 'name': '❤' },
|
||||
{ 'count': 7, 'me': false, 'name': '😯' },
|
||||
{ 'count': 15, 'me': false, 'name': '❤' },
|
||||
{ 'count': 7, 'me': false, 'name': '😯' },
|
||||
]));
|
||||
});
|
||||
});
|
||||
|
@ -89,29 +89,29 @@ describe('mergeEmojiFavourites', () => {
|
|||
describe('reduceEmoji', () => {
|
||||
describe('with a clusterfuck of emoji', () => {
|
||||
const emojiReacts = ImmutableList([
|
||||
{ 'count': 1, 'me': false, 'name': '😡' },
|
||||
{ 'count': 1, 'me': true, 'name': '🔪' },
|
||||
{ 'count': 7, 'me': true, 'name': '😯' },
|
||||
{ 'count': 3, 'me': false, 'name': '😢' },
|
||||
{ 'count': 1, 'me': true, 'name': '🌵' },
|
||||
{ 'count': 20, 'me': true, 'name': '👍' },
|
||||
{ 'count': 7, 'me': false, 'name': '😂' },
|
||||
{ 'count': 15, 'me': true, 'name': '❤' },
|
||||
{ 'count': 1, 'me': false, 'name': '👀' },
|
||||
{ 'count': 1, 'me': false, 'name': '🍩' },
|
||||
{ 'count': 1, 'me': false, 'name': '😡' },
|
||||
{ 'count': 1, 'me': true, 'name': '🔪' },
|
||||
{ 'count': 7, 'me': true, 'name': '😯' },
|
||||
{ 'count': 3, 'me': false, 'name': '😢' },
|
||||
{ 'count': 1, 'me': true, 'name': '🌵' },
|
||||
{ 'count': 20, 'me': true, 'name': '👍' },
|
||||
{ 'count': 7, 'me': false, 'name': '😂' },
|
||||
{ 'count': 15, 'me': true, 'name': '❤' },
|
||||
{ 'count': 1, 'me': false, 'name': '👀' },
|
||||
{ 'count': 1, 'me': false, 'name': '🍩' },
|
||||
].map((react) => emojiReactionSchema.parse(react)));
|
||||
it('sorts, filters, and combines emoji and favourites', () => {
|
||||
expect(reduceEmoji(emojiReacts, 7, true, ALLOWED_EMOJI)).toEqual(fromJS([
|
||||
{ 'count': 27, 'me': true, 'name': '👍' },
|
||||
{ 'count': 15, 'me': true, 'name': '❤' },
|
||||
{ 'count': 7, 'me': true, 'name': '😯' },
|
||||
{ 'count': 7, 'me': false, 'name': '😂' },
|
||||
{ 'count': 3, 'me': false, 'name': '😢' },
|
||||
{ 'count': 1, 'me': false, 'name': '😡' },
|
||||
{ 'count': 1, 'me': true, 'name': '🔪' },
|
||||
{ 'count': 1, 'me': true, 'name': '🌵' },
|
||||
{ 'count': 1, 'me': false, 'name': '👀' },
|
||||
{ 'count': 1, 'me': false, 'name': '🍩' },
|
||||
{ 'count': 27, 'me': true, 'name': '👍' },
|
||||
{ 'count': 15, 'me': true, 'name': '❤' },
|
||||
{ 'count': 7, 'me': true, 'name': '😯' },
|
||||
{ 'count': 7, 'me': false, 'name': '😂' },
|
||||
{ 'count': 3, 'me': false, 'name': '😢' },
|
||||
{ 'count': 1, 'me': false, 'name': '😡' },
|
||||
{ 'count': 1, 'me': true, 'name': '🔪' },
|
||||
{ 'count': 1, 'me': true, 'name': '🌵' },
|
||||
{ 'count': 1, 'me': false, 'name': '👀' },
|
||||
{ 'count': 1, 'me': false, 'name': '🍩' },
|
||||
]));
|
||||
});
|
||||
});
|
||||
|
@ -124,9 +124,9 @@ describe('getReactForStatus', () => {
|
|||
pleroma: {
|
||||
emoji_reactions: [
|
||||
{ 'count': 20, 'me': false, 'name': '👍' },
|
||||
{ 'count': 15, 'me': true, 'name': '❤' },
|
||||
{ 'count': 7, 'me': true, 'name': '😯' },
|
||||
{ 'count': 7, 'me': false, 'name': '😂' },
|
||||
{ 'count': 15, 'me': true, 'name': '❤' },
|
||||
{ 'count': 7, 'me': true, 'name': '😯' },
|
||||
{ 'count': 7, 'me': false, 'name': '😂' },
|
||||
],
|
||||
},
|
||||
}));
|
||||
|
@ -145,10 +145,10 @@ describe('getReactForStatus', () => {
|
|||
|
||||
it('returns undefined when a status has no valid reacts (or favourites)', () => {
|
||||
const status = normalizeStatus(fromJS([
|
||||
{ 'count': 1, 'me': true, 'name': '🔪' },
|
||||
{ 'count': 1, 'me': true, 'name': '🌵' },
|
||||
{ 'count': 1, 'me': false, 'name': '👀' },
|
||||
{ 'count': 1, 'me': false, 'name': '🍩' },
|
||||
{ 'count': 1, 'me': true, 'name': '🔪' },
|
||||
{ 'count': 1, 'me': true, 'name': '🌵' },
|
||||
{ 'count': 1, 'me': false, 'name': '👀' },
|
||||
{ 'count': 1, 'me': false, 'name': '🍩' },
|
||||
]));
|
||||
expect(getReactForStatus(status)).toEqual(undefined);
|
||||
});
|
||||
|
@ -162,7 +162,7 @@ describe('simulateEmojiReact', () => {
|
|||
].map((react) => emojiReactionSchema.parse(react)));
|
||||
expect(simulateEmojiReact(emojiReacts, '❤')).toEqual(fromJS([
|
||||
{ 'count': 2, 'me': false, 'name': '👍', 'url': undefined },
|
||||
{ 'count': 3, 'me': true, 'name': '❤', 'url': undefined },
|
||||
{ 'count': 3, 'me': true, 'name': '❤', 'url': undefined },
|
||||
]));
|
||||
});
|
||||
|
||||
|
@ -174,7 +174,7 @@ describe('simulateEmojiReact', () => {
|
|||
expect(simulateEmojiReact(emojiReacts, '😯')).toEqual(fromJS([
|
||||
{ 'count': 2, 'me': false, 'name': '👍', 'url': undefined },
|
||||
{ 'count': 2, 'me': false, 'name': '❤', 'url': undefined },
|
||||
{ 'count': 1, 'me': true, 'name': '😯', 'url': undefined },
|
||||
{ 'count': 1, 'me': true, 'name': '😯', 'url': undefined },
|
||||
]));
|
||||
});
|
||||
|
||||
|
@ -185,8 +185,8 @@ describe('simulateEmojiReact', () => {
|
|||
].map((react) => emojiReactionSchema.parse(react)));
|
||||
expect(simulateEmojiReact(emojiReacts, 'soapbox', 'https://gleasonator.com/emoji/Gleasonator/soapbox.png')).toEqual(fromJS([
|
||||
{ 'count': 2, 'me': false, 'name': '👍', 'url': undefined },
|
||||
{ 'count': 2, 'me': false, 'name': '❤', 'url': undefined },
|
||||
{ 'count': 1, 'me': true, 'name': 'soapbox', 'url': 'https://gleasonator.com/emoji/Gleasonator/soapbox.png' },
|
||||
{ 'count': 2, 'me': false, 'name': '❤', 'url': undefined },
|
||||
{ 'count': 1, 'me': true, 'name': 'soapbox', 'url': 'https://gleasonator.com/emoji/Gleasonator/soapbox.png' },
|
||||
]));
|
||||
});
|
||||
});
|
||||
|
@ -199,7 +199,7 @@ describe('simulateUnEmojiReact', () => {
|
|||
].map((react) => emojiReactionSchema.parse(react)));
|
||||
expect(simulateUnEmojiReact(emojiReacts, '❤')).toEqual(fromJS([
|
||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||
{ 'count': 2, 'me': false, 'name': '❤' },
|
||||
{ 'count': 2, 'me': false, 'name': '❤' },
|
||||
]));
|
||||
});
|
||||
|
||||
|
@ -207,7 +207,7 @@ describe('simulateUnEmojiReact', () => {
|
|||
const emojiReacts = ImmutableList([
|
||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||
{ 'count': 2, 'me': false, 'name': '❤' },
|
||||
{ 'count': 1, 'me': true, 'name': '😯' },
|
||||
{ 'count': 1, 'me': true, 'name': '😯' },
|
||||
].map((react) => emojiReactionSchema.parse(react)));
|
||||
expect(simulateUnEmojiReact(emojiReacts, '😯')).toEqual(fromJS([
|
||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||
|
@ -219,7 +219,7 @@ describe('simulateUnEmojiReact', () => {
|
|||
const emojiReacts = ImmutableList([
|
||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||
{ 'count': 2, 'me': false, 'name': '❤' },
|
||||
{ 'count': 1, 'me': true, 'name': 'soapbox', 'url': 'https://gleasonator.com/emoji/Gleasonator/soapbox.png' },
|
||||
{ 'count': 1, 'me': true, 'name': 'soapbox', 'url': 'https://gleasonator.com/emoji/Gleasonator/soapbox.png' },
|
||||
].map((react) => emojiReactionSchema.parse(react)));
|
||||
expect(simulateUnEmojiReact(emojiReacts, 'soapbox')).toEqual(fromJS([
|
||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||
|
|
|
@ -96,4 +96,4 @@ const createFaviconService = () => {
|
|||
|
||||
const FaviconService = createFaviconService();
|
||||
|
||||
export { FaviconService as default };
|
||||
export { checkCanvasExtractPermission, FaviconService as default };
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { type Notification } from 'pl-api';
|
||||
import type { Notification } from 'pl-api';
|
||||
|
||||
/** Notification types known to Soapbox. */
|
||||
const NOTIFICATION_TYPES = [
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { checkCanvasExtractPermission } from './favicon-service';
|
||||
|
||||
/* eslint-disable no-case-declarations */
|
||||
const DEFAULT_MAX_PIXELS = 1920 * 1080;
|
||||
|
||||
|
@ -45,47 +47,6 @@ const dropOrientationIfNeeded = (orientation: number) => new Promise<number>(res
|
|||
}
|
||||
});
|
||||
|
||||
// /**
|
||||
// *Some browsers don't allow reading from a canvas and instead return all-white
|
||||
// * or randomized data. Use a pre-defined image to check if reading the canvas
|
||||
// * works.
|
||||
// */
|
||||
// const checkCanvasReliability = () => new Promise<void>((resolve, reject) => {
|
||||
// switch(_browser_quirks['canvas-read-unreliable']) {
|
||||
// case true:
|
||||
// reject('Canvas reading unreliable');
|
||||
// break;
|
||||
// case false:
|
||||
// resolve();
|
||||
// break;
|
||||
// default:
|
||||
// // 2×2 GIF with white, red, green and blue pixels
|
||||
// const testImageURL =
|
||||
// 'data:image/gif;base64,R0lGODdhAgACAKEDAAAA//8AAAD/AP///ywAAAAAAgACAAACA1wEBQA7';
|
||||
// const refData =
|
||||
// [255, 255, 255, 255, 255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255];
|
||||
// const img = new Image();
|
||||
// img.onload = () => {
|
||||
// const canvas = document.createElement('canvas');
|
||||
// const context = canvas.getContext('2d');
|
||||
// context?.drawImage(img, 0, 0, 2, 2);
|
||||
// const imageData = context?.getImageData(0, 0, 2, 2);
|
||||
// if (imageData?.data.every((x, i) => refData[i] === x)) {
|
||||
// _browser_quirks['canvas-read-unreliable'] = false;
|
||||
// resolve();
|
||||
// } else {
|
||||
// _browser_quirks['canvas-read-unreliable'] = true;
|
||||
// reject('Canvas reading unreliable');
|
||||
// }
|
||||
// };
|
||||
// img.onerror = () => {
|
||||
// _browser_quirks['canvas-read-unreliable'] = true;
|
||||
// reject('Failed to load test image');
|
||||
// };
|
||||
// img.src = testImageURL;
|
||||
// }
|
||||
// });
|
||||
|
||||
/** Convert the file into a local blob URL. */
|
||||
const getImageUrl = (inputFile: File) => new Promise<string>((resolve, reject) => {
|
||||
// @ts-ignore: This is a browser capabilities check.
|
||||
|
@ -203,9 +164,8 @@ const resizeImage = (
|
|||
const newWidth = Math.round(Math.sqrt(maxPixels * (width / height)));
|
||||
const newHeight = Math.round(Math.sqrt(maxPixels * (height / width)));
|
||||
|
||||
// Skip canvas reliability check for now (it's unreliable)
|
||||
// checkCanvasReliability()
|
||||
// .then(getOrientation(img, type))
|
||||
if (!checkCanvasExtractPermission()) return reject();
|
||||
|
||||
getOrientation(img, type)
|
||||
.then(orientation => processImage(img, {
|
||||
width: newWidth,
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import aspectRatioPlugin from '@tailwindcss/aspect-ratio';
|
||||
import formsPlugin from '@tailwindcss/forms';
|
||||
import typographyPlugin from '@tailwindcss/typography';
|
||||
import { type Config } from 'tailwindcss';
|
||||
import plugin from 'tailwindcss/plugin';
|
||||
|
||||
import { parseColorMatrix } from './tailwind/colors';
|
||||
|
||||
import type { Config } from 'tailwindcss';
|
||||
|
||||
const blackVariantPlugin = plugin(({ addVariant }) => addVariant('black', '.black &'));
|
||||
const reducedMotionPlugin = plugin(({ addVariant }) => addVariant('no-reduce-motion', '.no-reduce-motion &'));
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { type RecursiveKeyValuePair } from 'tailwindcss/types/config';
|
||||
import type{ RecursiveKeyValuePair } from 'tailwindcss/types/config';
|
||||
|
||||
/** https://tailwindcss.com/docs/customizing-colors#using-css-variables */
|
||||
const withOpacityValue = (variable: string): string => `rgb(var(${variable}) / <alpha-value>)`;
|
||||
|
|
Loading…
Reference in a new issue