Merge remote-tracking branch 'origin/main' into renovate/node-21.x
This commit is contained in:
commit
c567f8d3a7
|
@ -61,7 +61,7 @@ module.exports = {
|
|||
'URLSearchParams', // core-js
|
||||
],
|
||||
tailwindcss: {
|
||||
config: 'tailwind.config.cjs',
|
||||
config: 'tailwind.config.ts',
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -268,7 +268,7 @@ module.exports = {
|
|||
'error',
|
||||
{
|
||||
classRegex: '^(base|container|icon|item|list|outer|wrapper)?[c|C]lass(Name)?$',
|
||||
config: 'tailwind.config.cjs',
|
||||
config: 'tailwind.config.ts',
|
||||
},
|
||||
],
|
||||
'tailwindcss/migration-from-tailwind-2': 'error',
|
||||
|
|
38
package.json
38
package.json
|
@ -50,12 +50,12 @@
|
|||
"@fontsource/roboto-mono": "^5.0.0",
|
||||
"@fontsource/tajawal": "^5.0.8",
|
||||
"@gamestdio/websocket": "^0.3.2",
|
||||
"@lexical/clipboard": "^0.12.2",
|
||||
"@lexical/hashtag": "^0.12.2",
|
||||
"@lexical/link": "^0.12.2",
|
||||
"@lexical/react": "^0.12.2",
|
||||
"@lexical/selection": "^0.12.2",
|
||||
"@lexical/utils": "^0.12.2",
|
||||
"@lexical/clipboard": "^0.12.4",
|
||||
"@lexical/hashtag": "^0.12.4",
|
||||
"@lexical/link": "^0.12.4",
|
||||
"@lexical/react": "^0.12.4",
|
||||
"@lexical/selection": "^0.12.4",
|
||||
"@lexical/utils": "^0.12.4",
|
||||
"@popperjs/core": "^2.11.5",
|
||||
"@reach/combobox": "^0.18.0",
|
||||
"@reach/menu-button": "^0.18.0",
|
||||
|
@ -63,13 +63,13 @@
|
|||
"@reach/rect": "^0.18.0",
|
||||
"@reach/tabs": "^0.18.0",
|
||||
"@reduxjs/toolkit": "^1.8.1",
|
||||
"@sentry/browser": "^7.37.2",
|
||||
"@sentry/react": "^7.37.2",
|
||||
"@sentry/tracing": "^7.37.2",
|
||||
"@sentry/browser": "^7.74.1",
|
||||
"@sentry/react": "^7.74.1",
|
||||
"@soapbox.pub/wasmboy": "^0.8.0",
|
||||
"@tabler/icons": "^2.0.0",
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@tanstack/react-query": "^5.0.0",
|
||||
"@types/escape-html": "^1.0.1",
|
||||
"@types/http-link-header": "^1.0.3",
|
||||
|
@ -82,7 +82,7 @@
|
|||
"@types/react-datepicker": "^4.4.2",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@types/react-helmet": "^6.1.5",
|
||||
"@types/react-motion": "^0.0.35",
|
||||
"@types/react-motion": "^0.0.39",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-sparklines": "^1.7.2",
|
||||
"@types/react-swipeable-views": "^0.13.1",
|
||||
|
@ -100,6 +100,7 @@
|
|||
"bowser": "^2.11.0",
|
||||
"browserslist": "^4.16.6",
|
||||
"clsx": "^2.0.0",
|
||||
"comlink": "^4.4.1",
|
||||
"core-js": "^3.27.2",
|
||||
"cryptocurrency-icons": "^0.18.1",
|
||||
"cssnano": "^6.0.0",
|
||||
|
@ -115,10 +116,10 @@
|
|||
"immer": "^10.0.0",
|
||||
"immutable": "^4.2.1",
|
||||
"intersection-observer": "^0.12.2",
|
||||
"intl-messageformat": "10.5.4",
|
||||
"intl-messageformat": "10.5.8",
|
||||
"intl-pluralrules": "^2.0.0",
|
||||
"leaflet": "^1.8.0",
|
||||
"lexical": "^0.12.2",
|
||||
"lexical": "^0.12.4",
|
||||
"line-awesome": "^1.3.0",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash": "^4.7.11",
|
||||
|
@ -134,6 +135,7 @@
|
|||
"react-color": "^2.19.3",
|
||||
"react-datepicker": "^4.8.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-hot-toast": "^2.4.0",
|
||||
"react-hotkeys": "^1.1.4",
|
||||
|
@ -143,7 +145,7 @@
|
|||
"react-motion": "^0.5.2",
|
||||
"react-overlays": "^0.9.0",
|
||||
"react-popper": "^2.3.0",
|
||||
"react-redux": "^8.0.0",
|
||||
"react-redux": "^9.0.0",
|
||||
"react-router-dom": "^5.3.0",
|
||||
"react-router-dom-v5-compat": "^6.6.2",
|
||||
"react-router-scroll-4": "^1.0.0-beta.2",
|
||||
|
@ -200,16 +202,16 @@
|
|||
"eslint-plugin-tailwindcss": "^3.13.0",
|
||||
"fake-indexeddb": "^5.0.0",
|
||||
"husky": "^8.0.0",
|
||||
"jsdom": "^22.1.0",
|
||||
"jsdom": "^23.0.0",
|
||||
"lint-staged": ">=10",
|
||||
"react-intl-translations-manager": "^5.0.3",
|
||||
"react-refresh": "^0.14.0",
|
||||
"rollup-plugin-visualizer": "^5.9.2",
|
||||
"stylelint": "^15.10.3",
|
||||
"stylelint-config-standard-scss": "^11.0.0",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"vite-plugin-checker": "^0.6.2",
|
||||
"vite-plugin-pwa": "^0.16.5",
|
||||
"vite-plugin-pwa": "^0.17.0",
|
||||
"vitest": "^0.34.4"
|
||||
},
|
||||
"resolutions": {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import api from '../api';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AnyAction } from 'redux';
|
||||
import type { RootState } from 'soapbox/store';
|
||||
|
||||
|
@ -31,7 +30,7 @@ const submitAccountNoteSuccess = (relationship: any) => ({
|
|||
relationship,
|
||||
});
|
||||
|
||||
const submitAccountNoteFail = (error: AxiosError) => ({
|
||||
const submitAccountNoteFail = (error: unknown) => ({
|
||||
type: ACCOUNT_NOTE_SUBMIT_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -224,7 +224,7 @@ const fetchAccountSuccess = (account: APIEntity) => ({
|
|||
account,
|
||||
});
|
||||
|
||||
const fetchAccountFail = (id: string | null, error: AxiosError) => ({
|
||||
const fetchAccountFail = (id: string | null, error: unknown) => ({
|
||||
type: ACCOUNT_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -272,7 +272,7 @@ const blockAccountSuccess = (relationship: APIEntity, statuses: ImmutableMap<str
|
|||
statuses,
|
||||
});
|
||||
|
||||
const blockAccountFail = (error: AxiosError) => ({
|
||||
const blockAccountFail = (error: unknown) => ({
|
||||
type: ACCOUNT_BLOCK_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -287,7 +287,7 @@ const unblockAccountSuccess = (relationship: APIEntity) => ({
|
|||
relationship,
|
||||
});
|
||||
|
||||
const unblockAccountFail = (error: AxiosError) => ({
|
||||
const unblockAccountFail = (error: unknown) => ({
|
||||
type: ACCOUNT_UNBLOCK_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -350,7 +350,7 @@ const muteAccountSuccess = (relationship: APIEntity, statuses: ImmutableMap<stri
|
|||
statuses,
|
||||
});
|
||||
|
||||
const muteAccountFail = (error: AxiosError) => ({
|
||||
const muteAccountFail = (error: unknown) => ({
|
||||
type: ACCOUNT_MUTE_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -365,7 +365,7 @@ const unmuteAccountSuccess = (relationship: APIEntity) => ({
|
|||
relationship,
|
||||
});
|
||||
|
||||
const unmuteAccountFail = (error: AxiosError) => ({
|
||||
const unmuteAccountFail = (error: unknown) => ({
|
||||
type: ACCOUNT_UNMUTE_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -404,7 +404,7 @@ const subscribeAccountSuccess = (relationship: APIEntity) => ({
|
|||
relationship,
|
||||
});
|
||||
|
||||
const subscribeAccountFail = (error: AxiosError) => ({
|
||||
const subscribeAccountFail = (error: unknown) => ({
|
||||
type: ACCOUNT_SUBSCRIBE_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -419,7 +419,7 @@ const unsubscribeAccountSuccess = (relationship: APIEntity) => ({
|
|||
relationship,
|
||||
});
|
||||
|
||||
const unsubscribeAccountFail = (error: AxiosError) => ({
|
||||
const unsubscribeAccountFail = (error: unknown) => ({
|
||||
type: ACCOUNT_UNSUBSCRIBE_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -446,7 +446,7 @@ const removeFromFollowersSuccess = (relationship: APIEntity) => ({
|
|||
relationship,
|
||||
});
|
||||
|
||||
const removeFromFollowersFail = (id: string, error: AxiosError) => ({
|
||||
const removeFromFollowersFail = (id: string, error: unknown) => ({
|
||||
type: ACCOUNT_REMOVE_FROM_FOLLOWERS_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -482,7 +482,7 @@ const fetchFollowersSuccess = (id: string, accounts: APIEntity[], next: string |
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchFollowersFail = (id: string, error: AxiosError) => ({
|
||||
const fetchFollowersFail = (id: string, error: unknown) => ({
|
||||
type: FOLLOWERS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -526,7 +526,7 @@ const expandFollowersSuccess = (id: string, accounts: APIEntity[], next: string
|
|||
next,
|
||||
});
|
||||
|
||||
const expandFollowersFail = (id: string, error: AxiosError) => ({
|
||||
const expandFollowersFail = (id: string, error: unknown) => ({
|
||||
type: FOLLOWERS_EXPAND_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -562,7 +562,7 @@ const fetchFollowingSuccess = (id: string, accounts: APIEntity[], next: string |
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchFollowingFail = (id: string, error: AxiosError) => ({
|
||||
const fetchFollowingFail = (id: string, error: unknown) => ({
|
||||
type: FOLLOWING_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -606,7 +606,7 @@ const expandFollowingSuccess = (id: string, accounts: APIEntity[], next: string
|
|||
next,
|
||||
});
|
||||
|
||||
const expandFollowingFail = (id: string, error: AxiosError) => ({
|
||||
const expandFollowingFail = (id: string, error: unknown) => ({
|
||||
type: FOLLOWING_EXPAND_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -646,7 +646,7 @@ const fetchRelationshipsSuccess = (relationships: APIEntity[]) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const fetchRelationshipsFail = (error: AxiosError) => ({
|
||||
const fetchRelationshipsFail = (error: unknown) => ({
|
||||
type: RELATIONSHIPS_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
|
@ -678,7 +678,7 @@ const fetchFollowRequestsSuccess = (accounts: APIEntity[], next: string | null)
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchFollowRequestsFail = (error: AxiosError) => ({
|
||||
const fetchFollowRequestsFail = (error: unknown) => ({
|
||||
type: FOLLOW_REQUESTS_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -715,7 +715,7 @@ const expandFollowRequestsSuccess = (accounts: APIEntity[], next: string | null)
|
|||
next,
|
||||
});
|
||||
|
||||
const expandFollowRequestsFail = (error: AxiosError) => ({
|
||||
const expandFollowRequestsFail = (error: unknown) => ({
|
||||
type: FOLLOW_REQUESTS_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -742,7 +742,7 @@ const authorizeFollowRequestSuccess = (id: string) => ({
|
|||
id,
|
||||
});
|
||||
|
||||
const authorizeFollowRequestFail = (id: string, error: AxiosError) => ({
|
||||
const authorizeFollowRequestFail = (id: string, error: unknown) => ({
|
||||
type: FOLLOW_REQUEST_AUTHORIZE_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -770,7 +770,7 @@ const rejectFollowRequestSuccess = (id: string) => ({
|
|||
id,
|
||||
});
|
||||
|
||||
const rejectFollowRequestFail = (id: string, error: AxiosError) => ({
|
||||
const rejectFollowRequestFail = (id: string, error: unknown) => ({
|
||||
type: FOLLOW_REQUEST_REJECT_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -823,7 +823,7 @@ const pinAccountSuccess = (relationship: APIEntity) => ({
|
|||
relationship,
|
||||
});
|
||||
|
||||
const pinAccountFail = (error: AxiosError) => ({
|
||||
const pinAccountFail = (error: unknown) => ({
|
||||
type: ACCOUNT_PIN_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -838,7 +838,7 @@ const unpinAccountSuccess = (relationship: APIEntity) => ({
|
|||
relationship,
|
||||
});
|
||||
|
||||
const unpinAccountFail = (error: AxiosError) => ({
|
||||
const unpinAccountFail = (error: unknown) => ({
|
||||
type: ACCOUNT_UNPIN_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -867,7 +867,7 @@ const fetchPinnedAccountsSuccess = (id: string, accounts: APIEntity[], next: str
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchPinnedAccountsFail = (id: string, error: AxiosError) => ({
|
||||
const fetchPinnedAccountsFail = (id: string, error: unknown) => ({
|
||||
type: PINNED_ACCOUNTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
|
|
@ -9,7 +9,6 @@ import api from '../api';
|
|||
import { importFetchedAccounts } from './importer';
|
||||
import { patchMeSuccess } from './me';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
||||
|
@ -61,7 +60,7 @@ const fetchAliasesSuccess = (aliases: unknown[]) => ({
|
|||
value: aliases,
|
||||
});
|
||||
|
||||
const fetchAliasesFail = (error: AxiosError) => ({
|
||||
const fetchAliasesFail = (error: unknown) => ({
|
||||
type: ALIASES_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -143,7 +142,7 @@ const addToAliasesSuccess = () => ({
|
|||
type: ALIASES_ADD_SUCCESS,
|
||||
});
|
||||
|
||||
const addToAliasesFail = (error: AxiosError) => ({
|
||||
const addToAliasesFail = (error: unknown) => ({
|
||||
type: ALIASES_ADD_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -196,7 +195,7 @@ const removeFromAliasesSuccess = () => ({
|
|||
type: ALIASES_REMOVE_SUCCESS,
|
||||
});
|
||||
|
||||
const removeFromAliasesFail = (error: AxiosError) => ({
|
||||
const removeFromAliasesFail = (error: unknown) => ({
|
||||
type: ALIASES_REMOVE_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@ import { getFeatures } from 'soapbox/utils/features';
|
|||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -61,7 +60,7 @@ export const fetchAnnouncementsSuccess = (announcements: APIEntity) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const fetchAnnouncementsFail = (error: AxiosError) => ({
|
||||
export const fetchAnnouncementsFail = (error: unknown) => ({
|
||||
type: ANNOUNCEMENTS_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
|
@ -94,7 +93,7 @@ export const dismissAnnouncementSuccess = (announcementId: string) => ({
|
|||
id: announcementId,
|
||||
});
|
||||
|
||||
export const dismissAnnouncementFail = (announcementId: string, error: AxiosError) => ({
|
||||
export const dismissAnnouncementFail = (announcementId: string, error: unknown) => ({
|
||||
type: ANNOUNCEMENTS_DISMISS_FAIL,
|
||||
id: announcementId,
|
||||
error,
|
||||
|
@ -141,7 +140,7 @@ export const addReactionSuccess = (announcementId: string, name: string, already
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const addReactionFail = (announcementId: string, name: string, error: AxiosError) => ({
|
||||
export const addReactionFail = (announcementId: string, name: string, error: unknown) => ({
|
||||
type: ANNOUNCEMENTS_REACTION_ADD_FAIL,
|
||||
id: announcementId,
|
||||
name,
|
||||
|
@ -174,7 +173,7 @@ export const removeReactionSuccess = (announcementId: string, name: string) => (
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
export const removeReactionFail = (announcementId: string, name: string, error: AxiosError) => ({
|
||||
export const removeReactionFail = (announcementId: string, name: string, error: unknown) => ({
|
||||
type: ANNOUNCEMENTS_REACTION_REMOVE_FAIL,
|
||||
id: announcementId,
|
||||
name,
|
||||
|
|
|
@ -6,7 +6,6 @@ import api, { getLinks } from '../api';
|
|||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
||||
const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST';
|
||||
|
@ -46,7 +45,7 @@ function fetchBlocksSuccess(accounts: any, next: any) {
|
|||
};
|
||||
}
|
||||
|
||||
function fetchBlocksFail(error: AxiosError) {
|
||||
function fetchBlocksFail(error: unknown) {
|
||||
return {
|
||||
type: BLOCKS_FETCH_FAIL,
|
||||
error,
|
||||
|
@ -90,7 +89,7 @@ function expandBlocksSuccess(accounts: any, next: any) {
|
|||
};
|
||||
}
|
||||
|
||||
function expandBlocksFail(error: AxiosError) {
|
||||
function expandBlocksFail(error: unknown) {
|
||||
return {
|
||||
type: BLOCKS_EXPAND_FAIL,
|
||||
error,
|
||||
|
|
|
@ -2,7 +2,6 @@ import api, { getLinks } from '../api';
|
|||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -43,7 +42,7 @@ const fetchBookmarkedStatusesSuccess = (statuses: APIEntity[], next: string | nu
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchBookmarkedStatusesFail = (error: AxiosError) => ({
|
||||
const fetchBookmarkedStatusesFail = (error: unknown) => ({
|
||||
type: BOOKMARKED_STATUSES_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -77,7 +76,7 @@ const expandBookmarkedStatusesSuccess = (statuses: APIEntity[], next: string | n
|
|||
next,
|
||||
});
|
||||
|
||||
const expandBookmarkedStatusesFail = (error: AxiosError) => ({
|
||||
const expandBookmarkedStatusesFail = (error: unknown) => ({
|
||||
type: BOOKMARKED_STATUSES_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import axios, { AxiosError, Canceler } from 'axios';
|
||||
import axios, { Canceler } from 'axios';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import throttle from 'lodash/throttle';
|
||||
import { defineMessages, IntlShape } from 'react-intl';
|
||||
|
@ -388,7 +388,7 @@ const submitComposeSuccess = (composeId: string, status: APIEntity) => ({
|
|||
status: status,
|
||||
});
|
||||
|
||||
const submitComposeFail = (composeId: string, error: AxiosError) => ({
|
||||
const submitComposeFail = (composeId: string, error: unknown) => ({
|
||||
type: COMPOSE_SUBMIT_FAIL,
|
||||
id: composeId,
|
||||
error: error,
|
||||
|
@ -451,7 +451,7 @@ const uploadComposeSuccess = (composeId: string, media: APIEntity, file: File) =
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const uploadComposeFail = (composeId: string, error: AxiosError | true) => ({
|
||||
const uploadComposeFail = (composeId: string, error: unknown) => ({
|
||||
type: COMPOSE_UPLOAD_FAIL,
|
||||
id: composeId,
|
||||
error: error,
|
||||
|
@ -484,7 +484,7 @@ const changeUploadComposeSuccess = (composeId: string, media: APIEntity) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const changeUploadComposeFail = (composeId: string, id: string, error: AxiosError) => ({
|
||||
const changeUploadComposeFail = (composeId: string, id: string, error: unknown) => ({
|
||||
type: COMPOSE_UPLOAD_CHANGE_FAIL,
|
||||
composeId,
|
||||
id,
|
||||
|
|
|
@ -8,7 +8,6 @@ import {
|
|||
importFetchedStatus,
|
||||
} from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -76,7 +75,7 @@ const expandConversationsSuccess = (conversations: APIEntity[], next: string | n
|
|||
isLoadingRecent,
|
||||
});
|
||||
|
||||
const expandConversationsFail = (error: AxiosError) => ({
|
||||
const expandConversationsFail = (error: unknown) => ({
|
||||
type: CONVERSATIONS_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import api from '../api';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -33,7 +32,7 @@ const fetchCustomEmojisSuccess = (custom_emojis: APIEntity[]) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const fetchCustomEmojisFail = (error: AxiosError) => ({
|
||||
const fetchCustomEmojisFail = (error: unknown) => ({
|
||||
type: CUSTOM_EMOJIS_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
|
|
|
@ -3,7 +3,6 @@ import api from '../api';
|
|||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -35,7 +34,7 @@ const fetchDirectorySuccess = (accounts: APIEntity[]) => ({
|
|||
accounts,
|
||||
});
|
||||
|
||||
const fetchDirectoryFail = (error: AxiosError) => ({
|
||||
const fetchDirectoryFail = (error: unknown) => ({
|
||||
type: DIRECTORY_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -62,7 +61,7 @@ const expandDirectorySuccess = (accounts: APIEntity[]) => ({
|
|||
accounts,
|
||||
});
|
||||
|
||||
const expandDirectoryFail = (error: AxiosError) => ({
|
||||
const expandDirectoryFail = (error: unknown) => ({
|
||||
type: DIRECTORY_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@ import { isLoggedIn } from 'soapbox/utils/auth';
|
|||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { EntityStore } from 'soapbox/entity-store/types';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
@ -50,7 +49,7 @@ const blockDomainSuccess = (domain: string, accounts: string[]) => ({
|
|||
accounts,
|
||||
});
|
||||
|
||||
const blockDomainFail = (domain: string, error: AxiosError) => ({
|
||||
const blockDomainFail = (domain: string, error: unknown) => ({
|
||||
type: DOMAIN_BLOCK_FAIL,
|
||||
domain,
|
||||
error,
|
||||
|
@ -88,7 +87,7 @@ const unblockDomainSuccess = (domain: string, accounts: string[]) => ({
|
|||
accounts,
|
||||
});
|
||||
|
||||
const unblockDomainFail = (domain: string, error: AxiosError) => ({
|
||||
const unblockDomainFail = (domain: string, error: unknown) => ({
|
||||
type: DOMAIN_UNBLOCK_FAIL,
|
||||
domain,
|
||||
error,
|
||||
|
@ -118,7 +117,7 @@ const fetchDomainBlocksSuccess = (domains: string[], next: string | null) => ({
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchDomainBlocksFail = (error: AxiosError) => ({
|
||||
const fetchDomainBlocksFail = (error: unknown) => ({
|
||||
type: DOMAIN_BLOCKS_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -162,7 +161,7 @@ const expandDomainBlocksSuccess = (domains: string[], next: string | null) => ({
|
|||
next,
|
||||
});
|
||||
|
||||
const expandDomainBlocksFail = (error: AxiosError) => ({
|
||||
const expandDomainBlocksFail = (error: unknown) => ({
|
||||
type: DOMAIN_BLOCKS_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
|
@ -7,9 +7,8 @@ import api from '../api';
|
|||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
import { favourite, unfavourite } from './interactions';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity, Status } from 'soapbox/types/entities';
|
||||
import type { APIEntity, EmojiReaction, Status } from 'soapbox/types/entities';
|
||||
|
||||
const EMOJI_REACT_REQUEST = 'EMOJI_REACT_REQUEST';
|
||||
const EMOJI_REACT_SUCCESS = 'EMOJI_REACT_SUCCESS';
|
||||
|
@ -27,17 +26,17 @@ const noOp = () => () => new Promise(f => f(undefined));
|
|||
|
||||
const simpleEmojiReact = (status: Status, emoji: string, custom?: string) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
const emojiReacts: ImmutableList<ImmutableMap<string, any>> = status.pleroma.get('emoji_reactions') || ImmutableList();
|
||||
const emojiReacts: ImmutableList<EmojiReaction> = status.reactions || ImmutableList();
|
||||
|
||||
if (emoji === '👍' && status.favourited) return dispatch(unfavourite(status));
|
||||
|
||||
const undo = emojiReacts.filter(e => e.get('me') === true && e.get('name') === emoji).count() > 0;
|
||||
const undo = emojiReacts.filter(e => e.me === true && e.name === emoji).count() > 0;
|
||||
if (undo) return dispatch(unEmojiReact(status, emoji));
|
||||
|
||||
return Promise.all([
|
||||
...emojiReacts
|
||||
.filter((emojiReact) => emojiReact.get('me') === true)
|
||||
.map(emojiReact => dispatch(unEmojiReact(status, emojiReact.get('name')))).toArray(),
|
||||
.filter((emojiReact) => emojiReact.me === true)
|
||||
.map(emojiReact => dispatch(unEmojiReact(status, emojiReact.name))).toArray(),
|
||||
status.favourited && dispatch(unfavourite(status)),
|
||||
]).then(() => {
|
||||
if (emoji === '👍') {
|
||||
|
@ -114,7 +113,7 @@ const fetchEmojiReactsSuccess = (id: string, emojiReacts: APIEntity[]) => ({
|
|||
emojiReacts,
|
||||
});
|
||||
|
||||
const fetchEmojiReactsFail = (id: string, error: AxiosError) => ({
|
||||
const fetchEmojiReactsFail = (id: string, error: unknown) => ({
|
||||
type: EMOJI_REACTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -135,7 +134,7 @@ const emojiReactSuccess = (status: Status, emoji: string) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const emojiReactFail = (status: Status, emoji: string, error: AxiosError) => ({
|
||||
const emojiReactFail = (status: Status, emoji: string, error: unknown) => ({
|
||||
type: EMOJI_REACT_FAIL,
|
||||
status,
|
||||
emoji,
|
||||
|
@ -157,7 +156,7 @@ const unEmojiReactSuccess = (status: Status, emoji: string) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const unEmojiReactFail = (status: Status, emoji: string, error: AxiosError) => ({
|
||||
const unEmojiReactFail = (status: Status, emoji: string, error: unknown) => ({
|
||||
type: UNEMOJI_REACT_FAIL,
|
||||
status,
|
||||
emoji,
|
||||
|
|
|
@ -12,7 +12,6 @@ import {
|
|||
STATUS_FETCH_SOURCE_SUCCESS,
|
||||
} from './statuses';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { ReducerStatus } from 'soapbox/reducers/statuses';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity, Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
@ -184,7 +183,7 @@ const uploadEventBannerSuccess = (media: APIEntity, file: File) => ({
|
|||
file,
|
||||
});
|
||||
|
||||
const uploadEventBannerFail = (error: AxiosError | true) => ({
|
||||
const uploadEventBannerFail = (error: unknown) => ({
|
||||
type: EVENT_BANNER_UPLOAD_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -253,7 +252,7 @@ const submitEventSuccess = (status: APIEntity) => ({
|
|||
status,
|
||||
});
|
||||
|
||||
const submitEventFail = (error: AxiosError) => ({
|
||||
const submitEventFail = (error: unknown) => ({
|
||||
type: EVENT_SUBMIT_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -295,7 +294,7 @@ const joinEventSuccess = (status: APIEntity) => ({
|
|||
id: status.id,
|
||||
});
|
||||
|
||||
const joinEventFail = (error: AxiosError, status: StatusEntity, previousState: string | null) => ({
|
||||
const joinEventFail = (error: unknown, status: StatusEntity, previousState: string | null) => ({
|
||||
type: EVENT_JOIN_FAIL,
|
||||
error,
|
||||
id: status.id,
|
||||
|
@ -330,7 +329,7 @@ const leaveEventSuccess = (status: APIEntity) => ({
|
|||
id: status.id,
|
||||
});
|
||||
|
||||
const leaveEventFail = (error: AxiosError, status: StatusEntity) => ({
|
||||
const leaveEventFail = (error: unknown, status: StatusEntity) => ({
|
||||
type: EVENT_LEAVE_FAIL,
|
||||
id: status.id,
|
||||
error,
|
||||
|
@ -361,7 +360,7 @@ const fetchEventParticipationsSuccess = (id: string, accounts: APIEntity[], next
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchEventParticipationsFail = (id: string, error: AxiosError) => ({
|
||||
const fetchEventParticipationsFail = (id: string, error: unknown) => ({
|
||||
type: EVENT_PARTICIPATIONS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -398,7 +397,7 @@ const expandEventParticipationsSuccess = (id: string, accounts: APIEntity[], nex
|
|||
next,
|
||||
});
|
||||
|
||||
const expandEventParticipationsFail = (id: string, error: AxiosError) => ({
|
||||
const expandEventParticipationsFail = (id: string, error: unknown) => ({
|
||||
type: EVENT_PARTICIPATIONS_EXPAND_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -429,7 +428,7 @@ const fetchEventParticipationRequestsSuccess = (id: string, participations: APIE
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchEventParticipationRequestsFail = (id: string, error: AxiosError) => ({
|
||||
const fetchEventParticipationRequestsFail = (id: string, error: unknown) => ({
|
||||
type: EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -466,7 +465,7 @@ const expandEventParticipationRequestsSuccess = (id: string, participations: API
|
|||
next,
|
||||
});
|
||||
|
||||
const expandEventParticipationRequestsFail = (id: string, error: AxiosError) => ({
|
||||
const expandEventParticipationRequestsFail = (id: string, error: unknown) => ({
|
||||
type: EVENT_PARTICIPATION_REQUESTS_EXPAND_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -497,7 +496,7 @@ const authorizeEventParticipationRequestSuccess = (id: string, accountId: string
|
|||
accountId,
|
||||
});
|
||||
|
||||
const authorizeEventParticipationRequestFail = (id: string, accountId: string, error: AxiosError) => ({
|
||||
const authorizeEventParticipationRequestFail = (id: string, accountId: string, error: unknown) => ({
|
||||
type: EVENT_PARTICIPATION_REQUEST_AUTHORIZE_FAIL,
|
||||
id,
|
||||
accountId,
|
||||
|
@ -529,7 +528,7 @@ const rejectEventParticipationRequestSuccess = (id: string, accountId: string) =
|
|||
accountId,
|
||||
});
|
||||
|
||||
const rejectEventParticipationRequestFail = (id: string, accountId: string, error: AxiosError) => ({
|
||||
const rejectEventParticipationRequestFail = (id: string, accountId: string, error: unknown) => ({
|
||||
type: EVENT_PARTICIPATION_REQUEST_REJECT_FAIL,
|
||||
id,
|
||||
accountId,
|
||||
|
|
|
@ -4,7 +4,6 @@ import api, { getLinks } from '../api';
|
|||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -55,7 +54,7 @@ const fetchFavouritedStatusesSuccess = (statuses: APIEntity[], next: string | nu
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const fetchFavouritedStatusesFail = (error: AxiosError) => ({
|
||||
const fetchFavouritedStatusesFail = (error: unknown) => ({
|
||||
type: FAVOURITED_STATUSES_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
|
@ -92,7 +91,7 @@ const expandFavouritedStatusesSuccess = (statuses: APIEntity[], next: string | n
|
|||
next,
|
||||
});
|
||||
|
||||
const expandFavouritedStatusesFail = (error: AxiosError) => ({
|
||||
const expandFavouritedStatusesFail = (error: unknown) => ({
|
||||
type: FAVOURITED_STATUSES_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -130,7 +129,7 @@ const fetchAccountFavouritedStatusesSuccess = (accountId: string, statuses: APIE
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const fetchAccountFavouritedStatusesFail = (accountId: string, error: AxiosError) => ({
|
||||
const fetchAccountFavouritedStatusesFail = (accountId: string, error: unknown) => ({
|
||||
type: ACCOUNT_FAVOURITED_STATUSES_FETCH_FAIL,
|
||||
accountId,
|
||||
error,
|
||||
|
@ -170,7 +169,7 @@ const expandAccountFavouritedStatusesSuccess = (accountId: string, statuses: API
|
|||
next,
|
||||
});
|
||||
|
||||
const expandAccountFavouritedStatusesFail = (accountId: string, error: AxiosError) => ({
|
||||
const expandAccountFavouritedStatusesFail = (accountId: string, error: unknown) => ({
|
||||
type: ACCOUNT_FAVOURITED_STATUSES_EXPAND_FAIL,
|
||||
accountId,
|
||||
error,
|
||||
|
|
|
@ -5,7 +5,6 @@ import api, { getLinks } from '../api';
|
|||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedGroups, importFetchedAccounts } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { GroupRole } from 'soapbox/reducers/group-memberships';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
@ -104,7 +103,7 @@ const deleteGroupSuccess = (id: string) => ({
|
|||
id,
|
||||
});
|
||||
|
||||
const deleteGroupFail = (id: string, error: AxiosError) => ({
|
||||
const deleteGroupFail = (id: string, error: unknown) => ({
|
||||
type: GROUP_DELETE_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -132,7 +131,7 @@ const fetchGroupSuccess = (group: APIEntity) => ({
|
|||
group,
|
||||
});
|
||||
|
||||
const fetchGroupFail = (id: string, error: AxiosError) => ({
|
||||
const fetchGroupFail = (id: string, error: unknown) => ({
|
||||
type: GROUP_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -158,7 +157,7 @@ const fetchGroupsSuccess = (groups: APIEntity[]) => ({
|
|||
groups,
|
||||
});
|
||||
|
||||
const fetchGroupsFail = (error: AxiosError) => ({
|
||||
const fetchGroupsFail = (error: unknown) => ({
|
||||
type: GROUPS_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -194,7 +193,7 @@ const fetchGroupRelationshipsSuccess = (relationships: APIEntity[]) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const fetchGroupRelationshipsFail = (error: AxiosError) => ({
|
||||
const fetchGroupRelationshipsFail = (error: unknown) => ({
|
||||
type: GROUP_RELATIONSHIPS_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
|
@ -222,7 +221,7 @@ const groupKickSuccess = (groupId: string, accountId: string) => ({
|
|||
accountId,
|
||||
});
|
||||
|
||||
const groupKickFail = (groupId: string, accountId: string, error: AxiosError) => ({
|
||||
const groupKickFail = (groupId: string, accountId: string, error: unknown) => ({
|
||||
type: GROUP_KICK_SUCCESS,
|
||||
groupId,
|
||||
accountId,
|
||||
|
@ -255,7 +254,7 @@ const fetchGroupBlocksSuccess = (id: string, accounts: APIEntity[], next: string
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchGroupBlocksFail = (id: string, error: AxiosError) => ({
|
||||
const fetchGroupBlocksFail = (id: string, error: unknown) => ({
|
||||
type: GROUP_BLOCKS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -295,7 +294,7 @@ const expandGroupBlocksSuccess = (id: string, accounts: APIEntity[], next: strin
|
|||
next,
|
||||
});
|
||||
|
||||
const expandGroupBlocksFail = (id: string, error: AxiosError) => ({
|
||||
const expandGroupBlocksFail = (id: string, error: unknown) => ({
|
||||
type: GROUP_BLOCKS_EXPAND_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -322,7 +321,7 @@ const groupBlockSuccess = (groupId: string, accountId: string) => ({
|
|||
accountId,
|
||||
});
|
||||
|
||||
const groupBlockFail = (groupId: string, accountId: string, error: AxiosError) => ({
|
||||
const groupBlockFail = (groupId: string, accountId: string, error: unknown) => ({
|
||||
type: GROUP_BLOCK_FAIL,
|
||||
groupId,
|
||||
accountId,
|
||||
|
@ -350,7 +349,7 @@ const groupUnblockSuccess = (groupId: string, accountId: string) => ({
|
|||
accountId,
|
||||
});
|
||||
|
||||
const groupUnblockFail = (groupId: string, accountId: string, error: AxiosError) => ({
|
||||
const groupUnblockFail = (groupId: string, accountId: string, error: unknown) => ({
|
||||
type: GROUP_UNBLOCK_FAIL,
|
||||
groupId,
|
||||
accountId,
|
||||
|
@ -379,7 +378,7 @@ const groupPromoteAccountSuccess = (groupId: string, accountId: string, membersh
|
|||
memberships,
|
||||
});
|
||||
|
||||
const groupPromoteAccountFail = (groupId: string, accountId: string, error: AxiosError) => ({
|
||||
const groupPromoteAccountFail = (groupId: string, accountId: string, error: unknown) => ({
|
||||
type: GROUP_PROMOTE_FAIL,
|
||||
groupId,
|
||||
accountId,
|
||||
|
@ -408,7 +407,7 @@ const groupDemoteAccountSuccess = (groupId: string, accountId: string, membershi
|
|||
memberships,
|
||||
});
|
||||
|
||||
const groupDemoteAccountFail = (groupId: string, accountId: string, error: AxiosError) => ({
|
||||
const groupDemoteAccountFail = (groupId: string, accountId: string, error: unknown) => ({
|
||||
type: GROUP_DEMOTE_FAIL,
|
||||
groupId,
|
||||
accountId,
|
||||
|
@ -443,7 +442,7 @@ const fetchGroupMembershipsSuccess = (id: string, role: GroupRole, memberships:
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchGroupMembershipsFail = (id: string, role: GroupRole, error: AxiosError) => ({
|
||||
const fetchGroupMembershipsFail = (id: string, role: GroupRole, error: unknown) => ({
|
||||
type: GROUP_MEMBERSHIPS_FETCH_FAIL,
|
||||
id,
|
||||
role,
|
||||
|
@ -486,7 +485,7 @@ const expandGroupMembershipsSuccess = (id: string, role: GroupRole, memberships:
|
|||
next,
|
||||
});
|
||||
|
||||
const expandGroupMembershipsFail = (id: string, role: GroupRole, error: AxiosError) => ({
|
||||
const expandGroupMembershipsFail = (id: string, role: GroupRole, error: unknown) => ({
|
||||
type: GROUP_MEMBERSHIPS_EXPAND_FAIL,
|
||||
id,
|
||||
role,
|
||||
|
@ -519,7 +518,7 @@ const fetchGroupMembershipRequestsSuccess = (id: string, accounts: APIEntity[],
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchGroupMembershipRequestsFail = (id: string, error: AxiosError) => ({
|
||||
const fetchGroupMembershipRequestsFail = (id: string, error: unknown) => ({
|
||||
type: GROUP_MEMBERSHIP_REQUESTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -559,7 +558,7 @@ const expandGroupMembershipRequestsSuccess = (id: string, accounts: APIEntity[],
|
|||
next,
|
||||
});
|
||||
|
||||
const expandGroupMembershipRequestsFail = (id: string, error: AxiosError) => ({
|
||||
const expandGroupMembershipRequestsFail = (id: string, error: unknown) => ({
|
||||
type: GROUP_MEMBERSHIP_REQUESTS_EXPAND_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -587,7 +586,7 @@ const authorizeGroupMembershipRequestSuccess = (groupId: string, accountId: stri
|
|||
accountId,
|
||||
});
|
||||
|
||||
const authorizeGroupMembershipRequestFail = (groupId: string, accountId: string, error: AxiosError) => ({
|
||||
const authorizeGroupMembershipRequestFail = (groupId: string, accountId: string, error: unknown) => ({
|
||||
type: GROUP_MEMBERSHIP_REQUEST_AUTHORIZE_FAIL,
|
||||
groupId,
|
||||
accountId,
|
||||
|
@ -616,7 +615,7 @@ const rejectGroupMembershipRequestSuccess = (groupId: string, accountId: string)
|
|||
accountId,
|
||||
});
|
||||
|
||||
const rejectGroupMembershipRequestFail = (groupId: string, accountId: string, error?: AxiosError) => ({
|
||||
const rejectGroupMembershipRequestFail = (groupId: string, accountId: string, error?: unknown) => ({
|
||||
type: GROUP_MEMBERSHIP_REQUEST_REJECT_FAIL,
|
||||
groupId,
|
||||
accountId,
|
||||
|
|
|
@ -2,7 +2,6 @@ import api from 'soapbox/api';
|
|||
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -37,7 +36,7 @@ const fetchHistorySuccess = (statusId: String, history: APIEntity[]) => ({
|
|||
history,
|
||||
});
|
||||
|
||||
const fetchHistoryFail = (error: AxiosError) => ({
|
||||
const fetchHistoryFail = (error: unknown) => ({
|
||||
type: HISTORY_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -9,7 +9,6 @@ import { fetchRelationships } from './accounts';
|
|||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
import { expandGroupFeaturedTimeline } from './timelines';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity, Group, Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -135,7 +134,7 @@ const reblogSuccess = (status: StatusEntity) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const reblogFail = (status: StatusEntity, error: AxiosError) => ({
|
||||
const reblogFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: REBLOG_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
|
@ -154,7 +153,7 @@ const unreblogSuccess = (status: StatusEntity) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const unreblogFail = (status: StatusEntity, error: AxiosError) => ({
|
||||
const unreblogFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: UNREBLOG_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
|
@ -208,7 +207,7 @@ const favouriteSuccess = (status: StatusEntity) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const favouriteFail = (status: StatusEntity, error: AxiosError) => ({
|
||||
const favouriteFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: FAVOURITE_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
|
@ -227,7 +226,7 @@ const unfavouriteSuccess = (status: StatusEntity) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const unfavouriteFail = (status: StatusEntity, error: AxiosError) => ({
|
||||
const unfavouriteFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: UNFAVOURITE_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
|
@ -281,7 +280,7 @@ const dislikeSuccess = (status: StatusEntity) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const dislikeFail = (status: StatusEntity, error: AxiosError) => ({
|
||||
const dislikeFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: DISLIKE_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
|
@ -300,7 +299,7 @@ const undislikeSuccess = (status: StatusEntity) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const undislikeFail = (status: StatusEntity, error: AxiosError) => ({
|
||||
const undislikeFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: UNDISLIKE_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
|
@ -356,7 +355,7 @@ const bookmarkSuccess = (status: StatusEntity, response: APIEntity) => ({
|
|||
response: response,
|
||||
});
|
||||
|
||||
const bookmarkFail = (status: StatusEntity, error: AxiosError) => ({
|
||||
const bookmarkFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: BOOKMARK_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
|
@ -373,7 +372,7 @@ const unbookmarkSuccess = (status: StatusEntity, response: APIEntity) => ({
|
|||
response: response,
|
||||
});
|
||||
|
||||
const unbookmarkFail = (status: StatusEntity, error: AxiosError) => ({
|
||||
const unbookmarkFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: UNBOOKMARK_FAIL,
|
||||
status: status,
|
||||
error,
|
||||
|
@ -407,7 +406,7 @@ const fetchReblogsSuccess = (id: string, accounts: APIEntity[], next: string | n
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchReblogsFail = (id: string, error: AxiosError) => ({
|
||||
const fetchReblogsFail = (id: string, error: unknown) => ({
|
||||
type: REBLOGS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -432,7 +431,7 @@ const expandReblogsSuccess = (id: string, accounts: APIEntity[], next: string |
|
|||
next,
|
||||
});
|
||||
|
||||
const expandReblogsFail = (id: string, error: AxiosError) => ({
|
||||
const expandReblogsFail = (id: string, error: unknown) => ({
|
||||
type: REBLOGS_EXPAND_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -466,7 +465,7 @@ const fetchFavouritesSuccess = (id: string, accounts: APIEntity[], next: string
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchFavouritesFail = (id: string, error: AxiosError) => ({
|
||||
const fetchFavouritesFail = (id: string, error: unknown) => ({
|
||||
type: FAVOURITES_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -491,7 +490,7 @@ const expandFavouritesSuccess = (id: string, accounts: APIEntity[], next: string
|
|||
next,
|
||||
});
|
||||
|
||||
const expandFavouritesFail = (id: string, error: AxiosError) => ({
|
||||
const expandFavouritesFail = (id: string, error: unknown) => ({
|
||||
type: FAVOURITES_EXPAND_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -523,7 +522,7 @@ const fetchDislikesSuccess = (id: string, accounts: APIEntity[]) => ({
|
|||
accounts,
|
||||
});
|
||||
|
||||
const fetchDislikesFail = (id: string, error: AxiosError) => ({
|
||||
const fetchDislikesFail = (id: string, error: unknown) => ({
|
||||
type: DISLIKES_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -552,7 +551,7 @@ const fetchReactionsSuccess = (id: string, reactions: APIEntity[]) => ({
|
|||
reactions,
|
||||
});
|
||||
|
||||
const fetchReactionsFail = (id: string, error: AxiosError) => ({
|
||||
const fetchReactionsFail = (id: string, error: unknown) => ({
|
||||
type: REACTIONS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -598,7 +597,7 @@ const pinSuccess = (status: StatusEntity) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const pinFail = (status: StatusEntity, error: AxiosError) => ({
|
||||
const pinFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: PIN_FAIL,
|
||||
status,
|
||||
error,
|
||||
|
@ -640,7 +639,7 @@ const unpinSuccess = (status: StatusEntity) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const unpinFail = (status: StatusEntity, error: AxiosError) => ({
|
||||
const unpinFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: UNPIN_FAIL,
|
||||
status,
|
||||
error,
|
||||
|
@ -676,7 +675,7 @@ const remoteInteractionSuccess = (ap_id: string, profile: string, url: string) =
|
|||
url,
|
||||
});
|
||||
|
||||
const remoteInteractionFail = (ap_id: string, profile: string, error: AxiosError) => ({
|
||||
const remoteInteractionFail = (ap_id: string, profile: string, error: unknown) => ({
|
||||
type: REMOTE_INTERACTION_FAIL,
|
||||
ap_id,
|
||||
profile,
|
||||
|
|
|
@ -6,7 +6,6 @@ import api from '../api';
|
|||
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -81,7 +80,7 @@ const fetchListSuccess = (list: APIEntity) => ({
|
|||
list,
|
||||
});
|
||||
|
||||
const fetchListFail = (id: string | number, error: AxiosError) => ({
|
||||
const fetchListFail = (id: string | number, error: unknown) => ({
|
||||
type: LIST_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -106,7 +105,7 @@ const fetchListsSuccess = (lists: APIEntity[]) => ({
|
|||
lists,
|
||||
});
|
||||
|
||||
const fetchListsFail = (error: AxiosError) => ({
|
||||
const fetchListsFail = (error: unknown) => ({
|
||||
type: LISTS_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -159,7 +158,7 @@ const createListSuccess = (list: APIEntity) => ({
|
|||
list,
|
||||
});
|
||||
|
||||
const createListFail = (error: AxiosError) => ({
|
||||
const createListFail = (error: unknown) => ({
|
||||
type: LIST_CREATE_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -188,7 +187,7 @@ const updateListSuccess = (list: APIEntity) => ({
|
|||
list,
|
||||
});
|
||||
|
||||
const updateListFail = (id: string | number, error: AxiosError) => ({
|
||||
const updateListFail = (id: string | number, error: unknown) => ({
|
||||
type: LIST_UPDATE_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -218,7 +217,7 @@ const deleteListSuccess = (id: string | number) => ({
|
|||
id,
|
||||
});
|
||||
|
||||
const deleteListFail = (id: string | number, error: AxiosError) => ({
|
||||
const deleteListFail = (id: string | number, error: unknown) => ({
|
||||
type: LIST_DELETE_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -247,7 +246,7 @@ const fetchListAccountsSuccess = (id: string | number, accounts: APIEntity[], ne
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchListAccountsFail = (id: string | number, error: AxiosError) => ({
|
||||
const fetchListAccountsFail = (id: string | number, error: unknown) => ({
|
||||
type: LIST_ACCOUNTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
|
@ -343,7 +342,7 @@ const removeFromListSuccess = (listId: string | number, accountId: string) => ({
|
|||
accountId,
|
||||
});
|
||||
|
||||
const removeFromListFail = (listId: string | number, accountId: string, error: AxiosError) => ({
|
||||
const removeFromListFail = (listId: string | number, accountId: string, error: unknown) => ({
|
||||
type: LIST_EDITOR_REMOVE_FAIL,
|
||||
listId,
|
||||
accountId,
|
||||
|
@ -384,7 +383,7 @@ const fetchAccountListsSuccess = (id: string, lists: APIEntity[]) => ({
|
|||
lists,
|
||||
});
|
||||
|
||||
const fetchAccountListsFail = (id: string, err: AxiosError) => ({
|
||||
const fetchAccountListsFail = (id: string, err: unknown) => ({
|
||||
type: LIST_ADDER_LISTS_FETCH_FAIL,
|
||||
id,
|
||||
err,
|
||||
|
|
|
@ -8,7 +8,7 @@ import api from '../api';
|
|||
import { loadCredentials } from './auth';
|
||||
import { importFetchedAccount } from './importer';
|
||||
|
||||
import type { AxiosError, RawAxiosRequestHeaders } from 'axios';
|
||||
import type { RawAxiosRequestHeaders } from 'axios';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
@ -125,7 +125,7 @@ const patchMeSuccess = (me: APIEntity) =>
|
|||
dispatch(action);
|
||||
};
|
||||
|
||||
const patchMeFail = (error: AxiosError) => ({
|
||||
const patchMeFail = (error: unknown) => ({
|
||||
type: ME_PATCH_FAIL,
|
||||
error,
|
||||
skipAlert: true,
|
||||
|
|
|
@ -8,7 +8,6 @@ import resizeImage from 'soapbox/utils/resize-image';
|
|||
|
||||
import api from '../api';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -59,7 +58,7 @@ const uploadFile = (
|
|||
file: File,
|
||||
intl: IntlShape,
|
||||
onSuccess: (data: APIEntity) => void = () => {},
|
||||
onFail: (error: AxiosError | true) => void = () => {},
|
||||
onFail: (error: unknown) => void = () => {},
|
||||
onProgress: (loaded: number) => void = () => {},
|
||||
changeTotal: (value: number) => void = () => {},
|
||||
) =>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import api from '../api';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
||||
const MFA_FETCH_REQUEST = 'MFA_FETCH_REQUEST';
|
||||
|
@ -50,7 +49,7 @@ const setupMfa = (method: string) =>
|
|||
return api(getState).get(`/api/pleroma/accounts/mfa/setup/${method}`).then(({ data }) => {
|
||||
dispatch({ type: MFA_SETUP_SUCCESS, data });
|
||||
return data;
|
||||
}).catch((error: AxiosError) => {
|
||||
}).catch((error: unknown) => {
|
||||
dispatch({ type: MFA_SETUP_FAIL });
|
||||
throw error;
|
||||
});
|
||||
|
@ -63,7 +62,7 @@ const confirmMfa = (method: string, code: string, password: string) =>
|
|||
return api(getState).post(`/api/pleroma/accounts/mfa/confirm/${method}`, params).then(({ data }) => {
|
||||
dispatch({ type: MFA_CONFIRM_SUCCESS, method, code });
|
||||
return data;
|
||||
}).catch((error: AxiosError) => {
|
||||
}).catch((error: unknown) => {
|
||||
dispatch({ type: MFA_CONFIRM_FAIL, method, code, error, skipAlert: true });
|
||||
throw error;
|
||||
});
|
||||
|
@ -75,7 +74,7 @@ const disableMfa = (method: string, password: string) =>
|
|||
return api(getState).delete(`/api/pleroma/accounts/mfa/${method}`, { data: { password } }).then(({ data }) => {
|
||||
dispatch({ type: MFA_DISABLE_SUCCESS, method });
|
||||
return data;
|
||||
}).catch((error: AxiosError) => {
|
||||
}).catch((error: unknown) => {
|
||||
dispatch({ type: MFA_DISABLE_FAIL, method, skipAlert: true });
|
||||
throw error;
|
||||
});
|
||||
|
|
|
@ -9,7 +9,6 @@ import { Stack, Text } from 'soapbox/components/ui';
|
|||
import AccountContainer from 'soapbox/containers/account-container';
|
||||
import { selectAccount } from 'soapbox/selectors';
|
||||
import toast from 'soapbox/toast';
|
||||
import { isLocal } from 'soapbox/utils/accounts';
|
||||
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
||||
|
@ -79,7 +78,7 @@ const deleteUserModal = (intl: IntlShape, accountId: string, afterConfirm = () =
|
|||
const account = selectAccount(state, accountId)!;
|
||||
const acct = account.acct;
|
||||
const name = account.username;
|
||||
const local = isLocal(account);
|
||||
const local = account.local;
|
||||
|
||||
const message = (
|
||||
<Stack space={4}>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Map as ImmutableMap, Set as ImmutableSet } from 'immutable';
|
||||
import { Set as ImmutableSet } from 'immutable';
|
||||
|
||||
import ConfigDB from 'soapbox/utils/config-db';
|
||||
|
||||
|
@ -7,9 +7,9 @@ import { fetchConfig, updateConfig } from './admin';
|
|||
import type { MRFSimple } from 'soapbox/schemas/pleroma';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
|
||||
const simplePolicyMerge = (simplePolicy: MRFSimple, host: string, restrictions: ImmutableMap<string, any>) => {
|
||||
const simplePolicyMerge = (simplePolicy: MRFSimple, host: string, restrictions: Record<string, any>) => {
|
||||
const entries = Object.entries(simplePolicy).map(([key, hosts]) => {
|
||||
const isRestricted = restrictions.get(key);
|
||||
const isRestricted = restrictions[key];
|
||||
|
||||
if (isRestricted) {
|
||||
return [key, ImmutableSet(hosts).add(host).toJS()];
|
||||
|
@ -21,7 +21,7 @@ const simplePolicyMerge = (simplePolicy: MRFSimple, host: string, restrictions:
|
|||
return Object.fromEntries(entries);
|
||||
};
|
||||
|
||||
const updateMrf = (host: string, restrictions: ImmutableMap<string, any>) =>
|
||||
const updateMrf = (host: string, restrictions: Record<string, any>) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||
dispatch(fetchConfig())
|
||||
.then(() => {
|
||||
|
|
|
@ -22,7 +22,6 @@ import {
|
|||
import { saveMarker } from './markers';
|
||||
import { getSettings, saveSettings } from './settings';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity, Status } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -262,7 +261,7 @@ const expandNotificationsSuccess = (notifications: APIEntity[], next: string | n
|
|||
skipLoading: !isLoadingMore,
|
||||
});
|
||||
|
||||
const expandNotificationsFail = (error: AxiosError, isLoadingMore: boolean) => ({
|
||||
const expandNotificationsFail = (error: unknown, isLoadingMore: boolean) => ({
|
||||
type: NOTIFICATIONS_EXPAND_FAIL,
|
||||
error,
|
||||
skipLoading: !isLoadingMore,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import api from '../api';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -38,7 +37,7 @@ const importFetchedInstance = (instance: APIEntity) => ({
|
|||
instance,
|
||||
});
|
||||
|
||||
const fetchInstanceFail = (error: AxiosError) => ({
|
||||
const fetchInstanceFail = (error: unknown) => ({
|
||||
type: PATRON_INSTANCE_FETCH_FAIL,
|
||||
error,
|
||||
skipAlert: true,
|
||||
|
@ -49,7 +48,7 @@ const importFetchedAccount = (account: APIEntity) => ({
|
|||
account,
|
||||
});
|
||||
|
||||
const fetchAccountFail = (error: AxiosError) => ({
|
||||
const fetchAccountFail = (error: unknown) => ({
|
||||
type: PATRON_ACCOUNT_FETCH_FAIL,
|
||||
error,
|
||||
skipAlert: true,
|
||||
|
|
|
@ -4,7 +4,6 @@ import api from '../api';
|
|||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -37,7 +36,7 @@ const fetchPinnedStatusesSuccess = (statuses: APIEntity[], next: string | null)
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchPinnedStatusesFail = (error: AxiosError) => ({
|
||||
const fetchPinnedStatusesFail = (error: unknown) => ({
|
||||
type: PINNED_STATUSES_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -2,7 +2,6 @@ import api from '../api';
|
|||
|
||||
import { importFetchedPoll } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -47,7 +46,7 @@ const voteSuccess = (poll: APIEntity) => ({
|
|||
poll,
|
||||
});
|
||||
|
||||
const voteFail = (error: AxiosError) => ({
|
||||
const voteFail = (error: unknown) => ({
|
||||
type: POLL_VOTE_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -61,7 +60,7 @@ const fetchPollSuccess = (poll: APIEntity) => ({
|
|||
poll,
|
||||
});
|
||||
|
||||
const fetchPollFail = (error: AxiosError) => ({
|
||||
const fetchPollFail = (error: unknown) => ({
|
||||
type: POLL_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -2,7 +2,6 @@ import api from '../api';
|
|||
|
||||
import { openModal } from './modals';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { ChatMessage, Group, Status } from 'soapbox/types/entities';
|
||||
|
@ -83,7 +82,7 @@ const submitReportSuccess = () => ({
|
|||
type: REPORT_SUBMIT_SUCCESS,
|
||||
});
|
||||
|
||||
const submitReportFail = (error: AxiosError) => ({
|
||||
const submitReportFail = (error: unknown) => ({
|
||||
type: REPORT_SUBMIT_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -2,7 +2,6 @@ import { getFeatures } from 'soapbox/utils/features';
|
|||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -61,7 +60,7 @@ const fetchScheduledStatusesSuccess = (statuses: APIEntity[], next: string | nul
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchScheduledStatusesFail = (error: AxiosError) => ({
|
||||
const fetchScheduledStatusesFail = (error: unknown) => ({
|
||||
type: SCHEDULED_STATUSES_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -94,7 +93,7 @@ const expandScheduledStatusesSuccess = (statuses: APIEntity[], next: string | nu
|
|||
next,
|
||||
});
|
||||
|
||||
const expandScheduledStatusesFail = (error: AxiosError) => ({
|
||||
const expandScheduledStatusesFail = (error: unknown) => ({
|
||||
type: SCHEDULED_STATUSES_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@ import api, { getLinks } from '../api';
|
|||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts, importFetchedStatuses } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { SearchFilter } from 'soapbox/reducers/search';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
@ -105,7 +104,7 @@ const fetchSearchSuccess = (results: APIEntity[], searchTerm: string, searchType
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchSearchFail = (error: AxiosError) => ({
|
||||
const fetchSearchFail = (error: unknown) => ({
|
||||
type: SEARCH_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -178,7 +177,7 @@ const expandSearchSuccess = (results: APIEntity[], searchTerm: string, searchTyp
|
|||
next,
|
||||
});
|
||||
|
||||
const expandSearchFail = (error: AxiosError) => ({
|
||||
const expandSearchFail = (error: unknown) => ({
|
||||
type: SEARCH_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -8,7 +8,6 @@ import { getFeatures } from 'soapbox/utils/features';
|
|||
|
||||
import api, { staticClient } from '../api';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -106,7 +105,7 @@ const importSoapboxConfig = (soapboxConfig: APIEntity, host: string | null) => {
|
|||
};
|
||||
};
|
||||
|
||||
const soapboxConfigFail = (error: AxiosError, host: string | null) => ({
|
||||
const soapboxConfigFail = (error: unknown, host: string | null) => ({
|
||||
type: SOAPBOX_CONFIG_REQUEST_FAIL,
|
||||
error,
|
||||
skipAlert: true,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import api, { getLinks } from '../api';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -44,7 +43,7 @@ const fetchHashtagSuccess = (name: string, tag: APIEntity) => ({
|
|||
tag,
|
||||
});
|
||||
|
||||
const fetchHashtagFail = (error: AxiosError) => ({
|
||||
const fetchHashtagFail = (error: unknown) => ({
|
||||
type: HASHTAG_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -70,7 +69,7 @@ const followHashtagSuccess = (name: string, tag: APIEntity) => ({
|
|||
tag,
|
||||
});
|
||||
|
||||
const followHashtagFail = (name: string, error: AxiosError) => ({
|
||||
const followHashtagFail = (name: string, error: unknown) => ({
|
||||
type: HASHTAG_FOLLOW_FAIL,
|
||||
name,
|
||||
error,
|
||||
|
@ -97,7 +96,7 @@ const unfollowHashtagSuccess = (name: string, tag: APIEntity) => ({
|
|||
tag,
|
||||
});
|
||||
|
||||
const unfollowHashtagFail = (name: string, error: AxiosError) => ({
|
||||
const unfollowHashtagFail = (name: string, error: unknown) => ({
|
||||
type: HASHTAG_UNFOLLOW_FAIL,
|
||||
name,
|
||||
error,
|
||||
|
@ -124,7 +123,7 @@ const fetchFollowedHashtagsSuccess = (followed_tags: APIEntity[], next: string |
|
|||
next,
|
||||
});
|
||||
|
||||
const fetchFollowedHashtagsFail = (error: AxiosError) => ({
|
||||
const fetchFollowedHashtagsFail = (error: unknown) => ({
|
||||
type: FOLLOWED_HASHTAGS_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
@ -156,7 +155,7 @@ const expandFollowedHashtagsSuccess = (followed_tags: APIEntity[], next: string
|
|||
next,
|
||||
});
|
||||
|
||||
const expandFollowedHashtagsFail = (error: AxiosError) => ({
|
||||
const expandFollowedHashtagsFail = (error: unknown) => ({
|
||||
type: FOLLOWED_HASHTAGS_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -9,7 +9,6 @@ import api, { getNextLink, getPrevLink } from '../api';
|
|||
import { fetchGroupRelationships } from './groups';
|
||||
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity, Status } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -284,7 +283,7 @@ const expandTimelineSuccess = (
|
|||
skipLoading: !isLoadingMore,
|
||||
});
|
||||
|
||||
const expandTimelineFail = (timeline: string, error: AxiosError, isLoadingMore: boolean) => ({
|
||||
const expandTimelineFail = (timeline: string, error: unknown, isLoadingMore: boolean) => ({
|
||||
type: TIMELINE_EXPAND_FAIL,
|
||||
timeline,
|
||||
error,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import api from '../api';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity } from 'soapbox/types/entities';
|
||||
|
||||
|
@ -28,7 +27,7 @@ const fetchTrendsSuccess = (tags: APIEntity[]) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const fetchTrendsFail = (error: AxiosError) => ({
|
||||
const fetchTrendsFail = (error: unknown) => ({
|
||||
type: TRENDS_FETCH_FAIL,
|
||||
error,
|
||||
skipLoading: true,
|
||||
|
|
|
@ -36,7 +36,7 @@ function useSignerStream() {
|
|||
|
||||
const respMsg = {
|
||||
id: reqMsg.data.id,
|
||||
result: await signEvent(reqMsg.data.params[0]),
|
||||
result: await signEvent(reqMsg.data.params[0], reqMsg.data.params[1]),
|
||||
};
|
||||
|
||||
const respEvent = await signEvent({
|
||||
|
|
|
@ -187,7 +187,7 @@ const Account = ({
|
|||
|
||||
return (
|
||||
<div data-testid='account' className='group block w-full shrink-0' ref={overflowRef}>
|
||||
<HStack alignItems={actionAlignment} justifyContent='between'>
|
||||
<HStack alignItems={actionAlignment} space={3} justifyContent='between'>
|
||||
<HStack alignItems={withAccountNote || note ? 'top' : 'center'} space={3} className='overflow-hidden'>
|
||||
<ProfilePopper
|
||||
condition={showProfileHoverCard}
|
||||
|
|
|
@ -12,7 +12,7 @@ const BigCard: React.FC<IBigCard> = ({ title, subtitle, children }) => {
|
|||
return (
|
||||
<Card variant='rounded' size='xl'>
|
||||
<CardBody>
|
||||
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-800 sm:-mx-10 sm:pb-10'>
|
||||
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 sm:-mx-10 sm:pb-10 dark:border-gray-800'>
|
||||
<Stack space={2}>
|
||||
<Text size='2xl' align='center' weight='bold'>{title}</Text>
|
||||
{subtitle && <Text theme='muted' align='center'>{subtitle}</Text>}
|
||||
|
|
|
@ -1,222 +0,0 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||
import * as BuildConfig from 'soapbox/build-config';
|
||||
import { HStack, Text, Stack } from 'soapbox/components/ui';
|
||||
import { captureException } from 'soapbox/monitoring';
|
||||
import KVStore from 'soapbox/storage/kv-store';
|
||||
import sourceCode from 'soapbox/utils/code';
|
||||
import { unregisterSW } from 'soapbox/utils/sw';
|
||||
|
||||
import SiteLogo from './site-logo';
|
||||
|
||||
import type { RootState } from 'soapbox/store';
|
||||
|
||||
interface Props extends ReturnType<typeof mapStateToProps> {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
type State = {
|
||||
hasError: boolean;
|
||||
error: any;
|
||||
componentStack: any;
|
||||
browser?: Bowser.Parser.Parser;
|
||||
}
|
||||
|
||||
class ErrorBoundary extends React.PureComponent<Props, State> {
|
||||
|
||||
state: State = {
|
||||
hasError: false,
|
||||
error: undefined,
|
||||
componentStack: undefined,
|
||||
browser: undefined,
|
||||
};
|
||||
|
||||
textarea: HTMLTextAreaElement | null = null;
|
||||
|
||||
componentDidCatch(error: any, info: any): void {
|
||||
captureException(error, {
|
||||
tags: {
|
||||
// Allow page crashes to be easily searched in Sentry.
|
||||
ErrorBoundary: 'yes',
|
||||
},
|
||||
});
|
||||
|
||||
this.setState({
|
||||
hasError: true,
|
||||
error,
|
||||
componentStack: info && info.componentStack,
|
||||
});
|
||||
|
||||
import('bowser')
|
||||
.then(({ default: Bowser }) => {
|
||||
this.setState({
|
||||
browser: Bowser.getParser(window.navigator.userAgent),
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
setTextareaRef: React.RefCallback<HTMLTextAreaElement> = c => {
|
||||
this.textarea = c;
|
||||
};
|
||||
|
||||
handleCopy: React.MouseEventHandler = () => {
|
||||
if (!this.textarea) return;
|
||||
|
||||
this.textarea.select();
|
||||
this.textarea.setSelectionRange(0, 99999);
|
||||
|
||||
document.execCommand('copy');
|
||||
};
|
||||
|
||||
getErrorText = (): string => {
|
||||
const { error, componentStack } = this.state;
|
||||
return error + componentStack;
|
||||
};
|
||||
|
||||
clearCookies: React.MouseEventHandler = (e) => {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
KVStore.clear();
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
e.preventDefault();
|
||||
unregisterSW().then(goHome).catch(goHome);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { browser, hasError } = this.state;
|
||||
const { children, links } = this.props;
|
||||
|
||||
if (!hasError) {
|
||||
return children;
|
||||
}
|
||||
|
||||
const isProduction = BuildConfig.NODE_ENV === 'production';
|
||||
|
||||
const errorText = this.getErrorText();
|
||||
|
||||
return (
|
||||
<div className='flex h-screen flex-col bg-white pb-12 pt-16 dark:bg-primary-900'>
|
||||
<main className='mx-auto flex w-full max-w-7xl grow flex-col justify-center px-4 sm:px-6 lg:px-8'>
|
||||
<div className='flex shrink-0 justify-center'>
|
||||
<a href='/' className='inline-flex'>
|
||||
<SiteLogo alt='Logo' className='h-12 w-auto cursor-pointer' />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className='py-8'>
|
||||
<div className='mx-auto max-w-xl space-y-2 text-center'>
|
||||
<h1 className='text-3xl font-extrabold tracking-tight text-gray-900 dark:text-gray-500 sm:text-4xl'>
|
||||
<FormattedMessage id='alert.unexpected.message' defaultMessage='Something went wrong.' />
|
||||
</h1>
|
||||
<p className='text-lg text-gray-700 dark:text-gray-600'>
|
||||
<FormattedMessage
|
||||
id='alert.unexpected.body'
|
||||
defaultMessage="We're sorry for the interruption. If the problem persists, please reach out to our support team. You may also try to {clearCookies} (this will log you out)."
|
||||
values={{
|
||||
clearCookies: (
|
||||
<a href='/' onClick={this.clearCookies} className='text-primary-600 hover:underline dark:text-accent-blue'>
|
||||
<FormattedMessage
|
||||
id='alert.unexpected.clear_cookies'
|
||||
defaultMessage='clear cookies and browser data'
|
||||
/>
|
||||
</a>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
|
||||
<Text theme='muted'>
|
||||
<Text weight='medium' tag='span' theme='muted'>{sourceCode.displayName}:</Text>
|
||||
|
||||
{' '}{sourceCode.version}
|
||||
</Text>
|
||||
|
||||
<div className='mt-10'>
|
||||
<a href='/' className='text-base font-medium text-primary-600 hover:underline dark:text-accent-blue'>
|
||||
<FormattedMessage id='alert.unexpected.return_home' defaultMessage='Return Home' />
|
||||
{' '}
|
||||
<span className='inline-block rtl:rotate-180' aria-hidden='true'>→</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!isProduction && (
|
||||
<div className='mx-auto max-w-lg space-y-4 py-16'>
|
||||
{errorText && (
|
||||
<textarea
|
||||
ref={this.setTextareaRef}
|
||||
className='block h-48 w-full rounded-md border-gray-300 bg-gray-100 p-4 font-mono text-gray-900 shadow-sm focus:border-primary-500 focus:ring-2 focus:ring-primary-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 sm:text-sm'
|
||||
value={errorText}
|
||||
onClick={this.handleCopy}
|
||||
dir='ltr'
|
||||
readOnly
|
||||
/>
|
||||
)}
|
||||
|
||||
{browser && (
|
||||
<Stack>
|
||||
<Text weight='semibold'><FormattedMessage id='alert.unexpected.browser' defaultMessage='Browser' /></Text>
|
||||
<Text theme='muted'>{browser.getBrowserName()} {browser.getBrowserVersion()}</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer className='mx-auto w-full max-w-7xl shrink-0 px-4 sm:px-6 lg:px-8'>
|
||||
<HStack justifyContent='center' space={4} element='nav'>
|
||||
{links.get('status') && (
|
||||
<>
|
||||
<a href={links.get('status')} className='text-sm font-medium text-gray-700 hover:underline dark:text-gray-600'>
|
||||
<FormattedMessage id='alert.unexpected.links.status' defaultMessage='Status' />
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
|
||||
{links.get('help') && (
|
||||
<>
|
||||
<span className='inline-block border-l border-gray-300' aria-hidden='true' />
|
||||
<a href={links.get('help')} className='text-sm font-medium text-gray-700 hover:underline dark:text-gray-600'>
|
||||
<FormattedMessage id='alert.unexpected.links.help' defaultMessage='Help Center' />
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
|
||||
{links.get('support') && (
|
||||
<>
|
||||
<span className='inline-block border-l border-gray-300' aria-hidden='true' />
|
||||
<a href={links.get('support')} className='text-sm font-medium text-gray-700 hover:underline dark:text-gray-600'>
|
||||
<FormattedMessage id='alert.unexpected.links.support' defaultMessage='Support' />
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</HStack>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function goHome() {
|
||||
location.href = '/';
|
||||
}
|
||||
|
||||
function mapStateToProps(state: RootState) {
|
||||
const { links, logo } = getSoapboxConfig(state);
|
||||
|
||||
return {
|
||||
siteTitle: state.instance.title,
|
||||
logo,
|
||||
links,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(ErrorBoundary);
|
|
@ -10,7 +10,7 @@ import Icon from './icon';
|
|||
import { Button, HStack, Stack, Text } from './ui';
|
||||
import VerificationBadge from './verification-badge';
|
||||
|
||||
import type { Account as AccountEntity, Status as StatusEntity } from 'soapbox/types/entities';
|
||||
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
||||
const messages = defineMessages({
|
||||
eventBanner: { id: 'event.banner', defaultMessage: 'Event banner' },
|
||||
|
@ -30,7 +30,7 @@ const EventPreview: React.FC<IEventPreview> = ({ status, className, hideAction,
|
|||
|
||||
const me = useAppSelector((state) => state.me);
|
||||
|
||||
const account = status.account as AccountEntity;
|
||||
const account = status.account;
|
||||
const event = status.event!;
|
||||
|
||||
const banner = event.banner;
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
// @ts-ignore No types available
|
||||
import { WasmBoy } from '@soapbox.pub/wasmboy';
|
||||
import clsx from 'clsx';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { exitFullscreen, isFullscreen, requestFullscreen } from 'soapbox/features/ui/util/fullscreen';
|
||||
|
||||
import { HStack, IconButton } from './ui';
|
||||
|
||||
let gainNode: GainNode | undefined;
|
||||
|
||||
interface IGameboy extends Pick<React.HTMLAttributes<HTMLDivElement>, 'onFocus' | 'onBlur'> {
|
||||
/** Classname of the outer `<div>`. */
|
||||
className?: string;
|
||||
/** URL to the ROM. */
|
||||
src: string;
|
||||
/** Aspect ratio of the canvas. */
|
||||
aspect?: 'normal' | 'stretched';
|
||||
}
|
||||
|
||||
/** Component to display a playable Gameboy emulator. */
|
||||
const Gameboy: React.FC<IGameboy> = ({ className, src, aspect = 'normal', onFocus, onBlur, ...rest }) => {
|
||||
const node = useRef<HTMLDivElement>(null);
|
||||
const canvas = useRef<HTMLCanvasElement>(null);
|
||||
|
||||
const [paused, setPaused] = useState(false);
|
||||
const [muted, setMuted] = useState(true);
|
||||
const [fullscreen, setFullscreen] = useState(false);
|
||||
const [showControls, setShowControls] = useState(true);
|
||||
|
||||
async function init() {
|
||||
await WasmBoy.config(WasmBoyOptions, canvas.current!);
|
||||
await WasmBoy.loadROM(src);
|
||||
await play();
|
||||
|
||||
if (document.activeElement === canvas.current) {
|
||||
await WasmBoy.enableDefaultJoypad();
|
||||
} else {
|
||||
await WasmBoy.disableDefaultJoypad();
|
||||
}
|
||||
}
|
||||
|
||||
const handleFocus: React.FocusEventHandler<HTMLDivElement> = useCallback(() => {
|
||||
WasmBoy.enableDefaultJoypad();
|
||||
}, []);
|
||||
|
||||
const handleBlur: React.FocusEventHandler<HTMLDivElement> = useCallback(() => {
|
||||
WasmBoy.disableDefaultJoypad();
|
||||
}, []);
|
||||
|
||||
const handleFullscreenChange = useCallback(() => {
|
||||
setFullscreen(isFullscreen());
|
||||
}, []);
|
||||
|
||||
const handleCanvasClick = useCallback(() => {
|
||||
setShowControls(!showControls);
|
||||
}, [showControls]);
|
||||
|
||||
const pause = async () => {
|
||||
await WasmBoy.pause();
|
||||
setPaused(true);
|
||||
};
|
||||
|
||||
const play = async () => {
|
||||
await WasmBoy.play();
|
||||
setPaused(false);
|
||||
};
|
||||
|
||||
const togglePaused = () => paused ? play() : pause();
|
||||
const toggleMuted = () => setMuted(!muted);
|
||||
|
||||
const toggleFullscreen = () => {
|
||||
if (isFullscreen()) {
|
||||
exitFullscreen();
|
||||
} else if (node.current) {
|
||||
requestFullscreen(node.current);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDownload = () => {
|
||||
window.open(src);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
init();
|
||||
|
||||
return () => {
|
||||
WasmBoy.pause();
|
||||
WasmBoy.disableDefaultJoypad();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('fullscreenchange', handleFullscreenChange, true);
|
||||
return () => {
|
||||
document.removeEventListener('fullscreenchange', handleFullscreenChange, true);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (fullscreen) {
|
||||
node.current?.focus();
|
||||
}
|
||||
}, [fullscreen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (gainNode) {
|
||||
gainNode.gain.value = muted ? 0 : 1;
|
||||
}
|
||||
}, [gainNode, muted]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={node}
|
||||
tabIndex={0}
|
||||
className={clsx(className, 'relative outline-none')}
|
||||
onFocus={onFocus ?? handleFocus}
|
||||
onBlur={onBlur ?? handleBlur}
|
||||
>
|
||||
<canvas
|
||||
ref={canvas}
|
||||
onClick={handleCanvasClick}
|
||||
className={clsx('h-full w-full bg-black ', {
|
||||
'object-contain': aspect === 'normal',
|
||||
'object-cover': aspect === 'stretched',
|
||||
})}
|
||||
{...rest}
|
||||
/>
|
||||
|
||||
<HStack
|
||||
justifyContent='between'
|
||||
className={clsx('pointer-events-none absolute inset-x-0 bottom-0 w-full bg-gradient-to-t from-black/50 to-transparent p-2 opacity-0 transition-opacity', {
|
||||
'pointer-events-auto opacity-100': showControls,
|
||||
})}
|
||||
>
|
||||
<HStack space={2}>
|
||||
<IconButton
|
||||
theme='transparent'
|
||||
className='text-white'
|
||||
onClick={togglePaused}
|
||||
src={paused ? require('@tabler/icons/player-play.svg') : require('@tabler/icons/player-pause.svg')}
|
||||
/>
|
||||
<IconButton
|
||||
theme='transparent'
|
||||
className='text-white'
|
||||
onClick={toggleMuted}
|
||||
src={muted ? require('@tabler/icons/volume-3.svg') : require('@tabler/icons/volume.svg')}
|
||||
/>
|
||||
</HStack>
|
||||
|
||||
<HStack space={2}>
|
||||
<IconButton
|
||||
theme='transparent'
|
||||
className='text-white'
|
||||
src={require('@tabler/icons/download.svg')}
|
||||
onClick={handleDownload}
|
||||
/>
|
||||
<IconButton
|
||||
theme='transparent'
|
||||
className='text-white'
|
||||
onClick={toggleFullscreen}
|
||||
src={fullscreen ? require('@tabler/icons/arrows-minimize.svg') : require('@tabler/icons/arrows-maximize.svg')}
|
||||
/>
|
||||
</HStack>
|
||||
</HStack>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const WasmBoyOptions = {
|
||||
headless: false,
|
||||
useGbcWhenOptional: true,
|
||||
isAudioEnabled: true,
|
||||
frameSkip: 1,
|
||||
audioBatchProcessing: true,
|
||||
timersBatchProcessing: false,
|
||||
audioAccumulateSamples: true,
|
||||
graphicsBatchProcessing: false,
|
||||
graphicsDisableScanlineRendering: false,
|
||||
tileRendering: true,
|
||||
tileCaching: true,
|
||||
gameboyFPSCap: 60,
|
||||
updateGraphicsCallback: false,
|
||||
updateAudioCallback: (audioContext: AudioContext, audioBufferSourceNode: AudioBufferSourceNode) => {
|
||||
gainNode = gainNode ?? audioContext.createGain();
|
||||
audioBufferSourceNode.connect(gainNode);
|
||||
return gainNode;
|
||||
},
|
||||
saveStateCallback: false,
|
||||
};
|
||||
|
||||
export default Gameboy;
|
|
@ -3,7 +3,7 @@ import React, { useState } from 'react';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Banner, Button, HStack, Stack, Text } from 'soapbox/components/ui';
|
||||
import { useAppSelector, useInstance, useSoapboxConfig } from 'soapbox/hooks';
|
||||
import { useInstance, useSoapboxConfig } from 'soapbox/hooks';
|
||||
|
||||
const acceptedGdpr = !!localStorage.getItem('soapbox:gdpr');
|
||||
|
||||
|
@ -14,8 +14,7 @@ const GdprBanner: React.FC = () => {
|
|||
const [slideout, setSlideout] = useState(false);
|
||||
|
||||
const instance = useInstance();
|
||||
const soapbox = useSoapboxConfig();
|
||||
const isLoggedIn = useAppSelector(state => !!state.me);
|
||||
const { gdprUrl } = useSoapboxConfig();
|
||||
|
||||
const handleAccept = () => {
|
||||
localStorage.setItem('soapbox:gdpr', 'true');
|
||||
|
@ -23,15 +22,13 @@ const GdprBanner: React.FC = () => {
|
|||
setTimeout(() => setShown(true), 200);
|
||||
};
|
||||
|
||||
const showBanner = soapbox.gdpr && !isLoggedIn && !shown;
|
||||
|
||||
if (!showBanner) {
|
||||
if (shown) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Banner theme='opaque' className={clsx('transition-transform', { 'translate-y-full': slideout })}>
|
||||
<div className='flex flex-col space-y-4 rtl:space-x-reverse lg:flex-row lg:items-center lg:justify-between lg:space-x-4 lg:space-y-0'>
|
||||
<div className='flex flex-col space-y-4 lg:flex-row lg:items-center lg:justify-between lg:space-x-4 lg:space-y-0 rtl:space-x-reverse'>
|
||||
<Stack space={2}>
|
||||
<Text size='xl' weight='bold'>
|
||||
<FormattedMessage id='gdpr.title' defaultMessage='{siteTitle} uses cookies' values={{ siteTitle: instance.title }} />
|
||||
|
@ -47,8 +44,8 @@ const GdprBanner: React.FC = () => {
|
|||
</Stack>
|
||||
|
||||
<HStack space={2} alignItems='center' className='flex-none'>
|
||||
{soapbox.gdprUrl && (
|
||||
<a href={soapbox.gdprUrl} tabIndex={-1} className='inline-flex'>
|
||||
{gdprUrl && (
|
||||
<a href={gdprUrl} tabIndex={-1} className='inline-flex'>
|
||||
<Button theme='secondary'>
|
||||
<FormattedMessage id='gdpr.learn_more' defaultMessage='Learn more' />
|
||||
</Button>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import clsx from 'clsx';
|
||||
import React, { useState, useRef, useLayoutEffect } from 'react';
|
||||
import React, { useState, useRef, useLayoutEffect, Suspense } from 'react';
|
||||
|
||||
import Blurhash from 'soapbox/components/blurhash';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
|
@ -15,6 +15,8 @@ import { isPanoramic, isPortrait, isNonConformingRatio, minimumAspectRatio, maxi
|
|||
import type { Property } from 'csstype';
|
||||
import type { List as ImmutableList } from 'immutable';
|
||||
|
||||
const Gameboy = React.lazy(() => import('./gameboy'));
|
||||
|
||||
const ATTACHMENT_LIMIT = 4;
|
||||
const MAX_FILENAME_LENGTH = 45;
|
||||
|
||||
|
@ -141,8 +143,24 @@ const Item: React.FC<IItem> = ({
|
|||
}
|
||||
|
||||
let thumbnail: React.ReactNode = '';
|
||||
const ext = attachment.url.split('.').pop()?.toLowerCase();
|
||||
|
||||
if (attachment.type === 'unknown') {
|
||||
if (attachment.type === 'unknown' && ['gb', 'gbc'].includes(ext!)) {
|
||||
return (
|
||||
<div
|
||||
className={clsx('media-gallery__item', {
|
||||
standalone,
|
||||
'rounded-md': total > 1,
|
||||
})}
|
||||
key={attachment.id}
|
||||
style={{ position, float, left, top, right, bottom, height, width: `${width}%` }}
|
||||
>
|
||||
<Suspense fallback={<div className='media-gallery__item-thumbnail' />}>
|
||||
<Gameboy className='media-gallery__item-thumbnail cursor-default' src={attachment.url} />
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
} else if (attachment.type === 'unknown') {
|
||||
const filename = truncateFilename(attachment.url, MAX_FILENAME_LENGTH);
|
||||
const attachmentIcon = (
|
||||
<Icon
|
||||
|
@ -215,7 +233,6 @@ const Item: React.FC<IItem> = ({
|
|||
</div>
|
||||
);
|
||||
} else if (attachment.type === 'audio') {
|
||||
const ext = attachment.url.split('.').pop()?.toUpperCase();
|
||||
thumbnail = (
|
||||
<a
|
||||
className={clsx('media-gallery__item-thumbnail')}
|
||||
|
@ -225,11 +242,10 @@ const Item: React.FC<IItem> = ({
|
|||
title={attachment.description}
|
||||
>
|
||||
<span className='media-gallery__item__icons'><Icon src={require('@tabler/icons/volume.svg')} /></span>
|
||||
<span className='media-gallery__file-extension__label'>{ext}</span>
|
||||
<span className='media-gallery__file-extension__label uppercase'>{ext}</span>
|
||||
</a>
|
||||
);
|
||||
} else if (attachment.type === 'video') {
|
||||
const ext = attachment.url.split('.').pop()?.toUpperCase();
|
||||
thumbnail = (
|
||||
<a
|
||||
className={clsx('media-gallery__item-thumbnail')}
|
||||
|
@ -246,7 +262,7 @@ const Item: React.FC<IItem> = ({
|
|||
>
|
||||
<source src={attachment.url} />
|
||||
</video>
|
||||
<span className='media-gallery__file-extension__label'>{ext}</span>
|
||||
<span className='media-gallery__file-extension__label uppercase'>{ext}</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ const PollOption: React.FC<IPollOption> = (props): JSX.Element | null => {
|
|||
return (
|
||||
<div key={option.title}>
|
||||
{showResults ? (
|
||||
<div title={voted ? message : undefined}>
|
||||
<div title={message}>
|
||||
<HStack
|
||||
justifyContent='between'
|
||||
alignItems='center'
|
||||
|
|
|
@ -14,7 +14,6 @@ import Badge from 'soapbox/components/badge';
|
|||
import ActionButton from 'soapbox/features/ui/components/action-button';
|
||||
import { UserPanel } from 'soapbox/features/ui/util/async-components';
|
||||
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
|
||||
import { isLocal } from 'soapbox/utils/accounts';
|
||||
|
||||
import { showProfileHoverCard } from './hover-ref-wrapper';
|
||||
import { dateFormatOptions } from './relative-timestamp';
|
||||
|
@ -117,7 +116,7 @@ export const ProfileHoverCard: React.FC<IProfileHoverCard> = ({ visible = true }
|
|||
badges={badges}
|
||||
/>
|
||||
|
||||
{isLocal(account) ? (
|
||||
{account.local ? (
|
||||
<HStack alignItems='center' space={0.5}>
|
||||
<Icon
|
||||
src={require('@tabler/icons/calendar.svg')}
|
||||
|
|
|
@ -15,7 +15,7 @@ import StatusContent from './status-content';
|
|||
import StatusReplyMentions from './status-reply-mentions';
|
||||
import SensitiveContentOverlay from './statuses/sensitive-content-overlay';
|
||||
|
||||
import type { Account as AccountEntity, Status as StatusEntity } from 'soapbox/types/entities';
|
||||
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
||||
const messages = defineMessages({
|
||||
cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
|
||||
|
@ -51,7 +51,7 @@ const QuotedStatus: React.FC<IQuotedStatus> = ({ status, onCancel, compose }) =>
|
|||
|
||||
const handleExpandClick: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||
if (!status) return;
|
||||
const account = status.account as AccountEntity;
|
||||
const account = status.account;
|
||||
|
||||
if (!compose && e.button === 0) {
|
||||
const statusUrl = `/@${account.acct}/posts/${status.id}`;
|
||||
|
@ -79,7 +79,7 @@ const QuotedStatus: React.FC<IQuotedStatus> = ({ status, onCancel, compose }) =>
|
|||
return null;
|
||||
}
|
||||
|
||||
const account = status.account as AccountEntity;
|
||||
const account = status.account;
|
||||
|
||||
let actions = {};
|
||||
if (onCancel) {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Textarea, Form, Button, FormGroup, FormActions, Text } from 'soapbox/components/ui';
|
||||
import { useOwnAccount } from 'soapbox/hooks';
|
||||
import { captureSentryFeedback } from 'soapbox/sentry';
|
||||
|
||||
interface ISentryFeedbackForm {
|
||||
eventId: string;
|
||||
}
|
||||
|
||||
/** Accept feedback for the given Sentry event. */
|
||||
const SentryFeedbackForm: React.FC<ISentryFeedbackForm> = ({ eventId }) => {
|
||||
const { account } = useOwnAccount();
|
||||
|
||||
const [feedback, setFeedback] = useState<string>();
|
||||
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
||||
const [isSubmitted, setIsSubmitted] = useState<boolean>(false);
|
||||
|
||||
const handleFeedbackChange: React.ChangeEventHandler<HTMLTextAreaElement> = (e) => {
|
||||
setFeedback(e.target.value);
|
||||
};
|
||||
|
||||
const handleSubmitFeedback: React.FormEventHandler = async (_e) => {
|
||||
if (!feedback || !eventId) return;
|
||||
setIsSubmitting(true);
|
||||
|
||||
await captureSentryFeedback({
|
||||
name: account?.acct,
|
||||
event_id: eventId,
|
||||
comments: feedback,
|
||||
}).catch(console.error);
|
||||
|
||||
setIsSubmitted(true);
|
||||
};
|
||||
|
||||
if (isSubmitted) {
|
||||
return (
|
||||
<Text align='center'>
|
||||
<FormattedMessage id='alert.unexpected.thanks' defaultMessage='Thanks for your feedback!' />
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Form onSubmit={handleSubmitFeedback}>
|
||||
<FormGroup>
|
||||
<Textarea
|
||||
value={feedback}
|
||||
onChange={handleFeedbackChange}
|
||||
placeholder='Anything you can tell us about what happened?'
|
||||
disabled={isSubmitting}
|
||||
autoGrow
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormActions>
|
||||
<Button type='submit' className='mx-auto' disabled={!feedback || isSubmitting}>
|
||||
<FormattedMessage id='alert.unexpected.submit_feedback' defaultMessage='Submit Feedback' />
|
||||
</Button>
|
||||
</FormActions>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default SentryFeedbackForm;
|
|
@ -0,0 +1,199 @@
|
|||
import React, { type ErrorInfo, useRef, useState } from 'react';
|
||||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { NODE_ENV } from 'soapbox/build-config';
|
||||
import { HStack, Text, Stack, Textarea } from 'soapbox/components/ui';
|
||||
import { useSoapboxConfig } from 'soapbox/hooks';
|
||||
import { captureSentryException } from 'soapbox/sentry';
|
||||
import KVStore from 'soapbox/storage/kv-store';
|
||||
import sourceCode from 'soapbox/utils/code';
|
||||
import { unregisterSW } from 'soapbox/utils/sw';
|
||||
|
||||
import SentryFeedbackForm from './sentry-feedback-form';
|
||||
import SiteLogo from './site-logo';
|
||||
|
||||
interface ISiteErrorBoundary {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
/** Application-level error boundary. Fills the whole screen. */
|
||||
const SiteErrorBoundary: React.FC<ISiteErrorBoundary> = ({ children }) => {
|
||||
const { links, sentryDsn } = useSoapboxConfig();
|
||||
const textarea = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const [error, setError] = useState<unknown>();
|
||||
const [componentStack, setComponentStack] = useState<string>();
|
||||
const [browser, setBrowser] = useState<Bowser.Parser.Parser>();
|
||||
const [sentryEventId, setSentryEventId] = useState<string>();
|
||||
|
||||
const sentryEnabled = Boolean(sentryDsn);
|
||||
const isProduction = NODE_ENV === 'production';
|
||||
const errorText = String(error) + componentStack;
|
||||
|
||||
const clearCookies: React.MouseEventHandler = (e) => {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
KVStore.clear();
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
e.preventDefault();
|
||||
unregisterSW().then(goHome).catch(goHome);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCopy: React.MouseEventHandler = () => {
|
||||
if (!textarea.current) return;
|
||||
|
||||
textarea.current.select();
|
||||
textarea.current.setSelectionRange(0, 99999);
|
||||
|
||||
document.execCommand('copy');
|
||||
};
|
||||
|
||||
function handleError(error: Error, info: ErrorInfo) {
|
||||
setError(error);
|
||||
setComponentStack(info.componentStack);
|
||||
|
||||
captureSentryException(error, {
|
||||
tags: {
|
||||
// Allow page crashes to be easily searched in Sentry.
|
||||
ErrorBoundary: 'yes',
|
||||
},
|
||||
})
|
||||
.then((eventId) => setSentryEventId(eventId))
|
||||
.catch(console.error);
|
||||
|
||||
import('bowser')
|
||||
.then(({ default: Bowser }) => setBrowser(Bowser.getParser(window.navigator.userAgent)))
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
function goHome() {
|
||||
location.href = '/';
|
||||
}
|
||||
|
||||
const fallback = (
|
||||
<div className='flex h-screen flex-col bg-white pb-12 pt-16 dark:bg-primary-900'>
|
||||
<main className='mx-auto flex w-full max-w-7xl grow flex-col justify-center px-4 sm:px-6 lg:px-8'>
|
||||
<div className='flex shrink-0 justify-center'>
|
||||
<a href='/' className='inline-flex'>
|
||||
<SiteLogo alt='Logo' className='h-12 w-auto cursor-pointer' />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className='py-8'>
|
||||
<div className='mx-auto max-w-xl space-y-2 text-center'>
|
||||
<h1 className='text-3xl font-extrabold tracking-tight text-gray-900 sm:text-4xl dark:text-gray-500'>
|
||||
<FormattedMessage id='alert.unexpected.message' defaultMessage='Something went wrong.' />
|
||||
</h1>
|
||||
<p className='text-lg text-gray-700 dark:text-gray-600'>
|
||||
<FormattedMessage
|
||||
id='alert.unexpected.body'
|
||||
defaultMessage="We're sorry for the interruption. If the problem persists, please reach out to our support team. You may also try to {clearCookies} (this will log you out)."
|
||||
values={{
|
||||
clearCookies: (
|
||||
<a href='/' onClick={clearCookies} className='text-primary-600 hover:underline dark:text-accent-blue'>
|
||||
<FormattedMessage
|
||||
id='alert.unexpected.clear_cookies'
|
||||
defaultMessage='clear cookies and browser data'
|
||||
/>
|
||||
</a>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
|
||||
<Text theme='muted'>
|
||||
<Text weight='medium' tag='span' theme='muted'>{sourceCode.displayName}:</Text>
|
||||
|
||||
{' '}{sourceCode.version}
|
||||
</Text>
|
||||
|
||||
<div className='mt-10'>
|
||||
<a href='/' className='text-base font-medium text-primary-600 hover:underline dark:text-accent-blue'>
|
||||
<FormattedMessage id='alert.unexpected.return_home' defaultMessage='Return Home' />
|
||||
{' '}
|
||||
<span className='inline-block rtl:rotate-180' aria-hidden='true'>→</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mx-auto max-w-lg space-y-4 py-16'>
|
||||
{(isProduction) ? (
|
||||
(sentryEnabled && sentryEventId) && (
|
||||
<SentryFeedbackForm eventId={sentryEventId} />
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
{errorText && (
|
||||
<Textarea
|
||||
ref={textarea}
|
||||
value={errorText}
|
||||
onClick={handleCopy}
|
||||
isCodeEditor
|
||||
rows={12}
|
||||
readOnly
|
||||
/>
|
||||
)}
|
||||
|
||||
{browser && (
|
||||
<Stack>
|
||||
<Text weight='semibold'><FormattedMessage id='alert.unexpected.browser' defaultMessage='Browser' /></Text>
|
||||
<Text theme='muted'>{browser.getBrowserName()} {browser.getBrowserVersion()}</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer className='mx-auto w-full max-w-7xl shrink-0 px-4 sm:px-6 lg:px-8'>
|
||||
<HStack justifyContent='center' space={4} element='nav'>
|
||||
{links.get('status') && (
|
||||
<SiteErrorBoundaryLink href={links.get('status')!}>
|
||||
<FormattedMessage id='alert.unexpected.links.status' defaultMessage='Status' />
|
||||
</SiteErrorBoundaryLink>
|
||||
)}
|
||||
|
||||
{links.get('help') && (
|
||||
<SiteErrorBoundaryLink href={links.get('help')!}>
|
||||
<FormattedMessage id='alert.unexpected.links.help' defaultMessage='Help Center' />
|
||||
</SiteErrorBoundaryLink>
|
||||
)}
|
||||
|
||||
{links.get('support') && (
|
||||
<SiteErrorBoundaryLink href={links.get('support')!}>
|
||||
<FormattedMessage id='alert.unexpected.links.support' defaultMessage='Support' />
|
||||
</SiteErrorBoundaryLink>
|
||||
)}
|
||||
</HStack>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<ErrorBoundary fallback={fallback} onError={handleError}>
|
||||
{children}
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
interface ISiteErrorBoundaryLink {
|
||||
href: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
function SiteErrorBoundaryLink({ href, children }: ISiteErrorBoundaryLink) {
|
||||
return (
|
||||
<>
|
||||
<span className='inline-block border-l border-gray-300' aria-hidden='true' />
|
||||
<a href={href} className='text-sm font-medium text-gray-700 hover:underline dark:text-gray-600'>
|
||||
{children}
|
||||
</a>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default SiteErrorBoundary;
|
|
@ -1,4 +1,3 @@
|
|||
import { List as ImmutableList } from 'immutable';
|
||||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useHistory, useRouteMatch } from 'react-router-dom';
|
||||
|
@ -23,14 +22,13 @@ import { HStack } from 'soapbox/components/ui';
|
|||
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount, useSettings, useSoapboxConfig } from 'soapbox/hooks';
|
||||
import { GroupRoles } from 'soapbox/schemas/group-member';
|
||||
import toast from 'soapbox/toast';
|
||||
import { isLocal, isRemote } from 'soapbox/utils/accounts';
|
||||
import copy from 'soapbox/utils/copy';
|
||||
import { getReactForStatus, reduceEmoji } from 'soapbox/utils/emoji-reacts';
|
||||
|
||||
import GroupPopover from './groups/popover/group-popover';
|
||||
|
||||
import type { Menu } from 'soapbox/components/dropdown-menu';
|
||||
import type { Account, Group, Status } from 'soapbox/types/entities';
|
||||
import type { Group, Status } from 'soapbox/types/entities';
|
||||
|
||||
const messages = defineMessages({
|
||||
adminAccount: { id: 'status.admin_account', defaultMessage: 'Moderate @{name}' },
|
||||
|
@ -132,7 +130,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
const unmuteGroup = useUnmuteGroup(group as Group);
|
||||
const isMutingGroup = !!group?.relationship?.muting;
|
||||
const deleteGroupStatus = useDeleteGroupStatus(group as Group, status.id);
|
||||
const blockGroupMember = useBlockGroupMember(group as Group, status?.account as any);
|
||||
const blockGroupMember = useBlockGroupMember(group as Group, status.account);
|
||||
|
||||
const me = useAppSelector(state => state.me);
|
||||
const { groupRelationship } = useGroupRelationship(status.group?.id);
|
||||
|
@ -267,20 +265,20 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
};
|
||||
|
||||
const handleMentionClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
dispatch(mentionCompose(status.account as Account));
|
||||
dispatch(mentionCompose(status.account));
|
||||
};
|
||||
|
||||
const handleDirectClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
dispatch(directCompose(status.account as Account));
|
||||
dispatch(directCompose(status.account));
|
||||
};
|
||||
|
||||
const handleChatClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
const account = status.account as Account;
|
||||
const account = status.account;
|
||||
dispatch(launchChat(account.id, history));
|
||||
};
|
||||
|
||||
const handleMuteClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
dispatch(initMuteModal(status.account as Account));
|
||||
dispatch(initMuteModal(status.account));
|
||||
};
|
||||
|
||||
const handleMuteGroupClick: React.EventHandler<React.MouseEvent> = () =>
|
||||
|
@ -305,7 +303,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
};
|
||||
|
||||
const handleBlockClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
const account = status.account as Account;
|
||||
const account = status.account;
|
||||
|
||||
dispatch(openModal('CONFIRM', {
|
||||
icon: require('@tabler/icons/ban.svg'),
|
||||
|
@ -333,7 +331,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
};
|
||||
|
||||
const handleReport: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
dispatch(initReport(ReportableEntities.STATUS, status.account as Account, { status }));
|
||||
dispatch(initReport(ReportableEntities.STATUS, status.account, { status }));
|
||||
};
|
||||
|
||||
const handleConversationMuteClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
|
@ -347,7 +345,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
};
|
||||
|
||||
const onModerate: React.MouseEventHandler = (e) => {
|
||||
const account = status.account as Account;
|
||||
const account = status.account;
|
||||
dispatch(openModal('ACCOUNT_MODERATION', { accountId: account.id }));
|
||||
};
|
||||
|
||||
|
@ -360,7 +358,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
};
|
||||
|
||||
const handleDeleteFromGroup: React.EventHandler<React.MouseEvent> = () => {
|
||||
const account = status.account as Account;
|
||||
const account = status.account;
|
||||
|
||||
dispatch(openModal('CONFIRM', {
|
||||
heading: intl.formatMessage(messages.deleteHeading),
|
||||
|
@ -379,10 +377,10 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
const handleBlockFromGroup = () => {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
heading: intl.formatMessage(messages.groupBlockFromGroupHeading),
|
||||
message: intl.formatMessage(messages.groupBlockFromGroupMessage, { name: (status.account as any).username }),
|
||||
message: intl.formatMessage(messages.groupBlockFromGroupMessage, { name: status.account.username }),
|
||||
confirm: intl.formatMessage(messages.groupBlockConfirm),
|
||||
onConfirm: () => {
|
||||
blockGroupMember({ account_ids: [(status.account as any).id] }, {
|
||||
blockGroupMember({ account_ids: [status.account.id] }, {
|
||||
onSuccess() {
|
||||
toast.success(intl.formatMessage(messages.blocked, { name: account?.acct }));
|
||||
},
|
||||
|
@ -415,7 +413,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
icon: require('@tabler/icons/clipboard-copy.svg'),
|
||||
});
|
||||
|
||||
if (features.embeds && isLocal(account)) {
|
||||
if (features.embeds && account.local) {
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.embed),
|
||||
action: handleEmbed,
|
||||
|
@ -449,7 +447,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
});
|
||||
}
|
||||
|
||||
if (features.federating && isRemote(account)) {
|
||||
if (features.federating && !account.local) {
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.external, { domain }),
|
||||
action: handleExternalClick,
|
||||
|
@ -554,7 +552,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
|
||||
if (isGroupStatus && !!status.group) {
|
||||
const group = status.group as Group;
|
||||
const account = status.account as Account;
|
||||
const account = status.account;
|
||||
const isGroupOwner = groupRelationship?.role === GroupRoles.OWNER;
|
||||
const isGroupAdmin = groupRelationship?.role === GroupRoles.ADMIN;
|
||||
const isStatusFromOwner = group.owner.id === account.id;
|
||||
|
@ -627,15 +625,15 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
const reblogCount = status.reblogs_count;
|
||||
const favouriteCount = status.favourites_count;
|
||||
|
||||
const emojiReactCount = reduceEmoji(
|
||||
(status.pleroma.get('emoji_reactions') || ImmutableList()) as ImmutableList<any>,
|
||||
const emojiReactCount = status.reactions ? reduceEmoji(
|
||||
status.reactions,
|
||||
favouriteCount,
|
||||
status.favourited,
|
||||
allowedEmoji,
|
||||
).reduce((acc, cur) => acc + cur.get('count'), 0);
|
||||
).reduce((acc, cur) => acc + (cur.count || 0), 0) : undefined;
|
||||
|
||||
const meEmojiReact = getReactForStatus(status, allowedEmoji);
|
||||
const meEmojiName = meEmojiReact?.get('name') as keyof typeof reactMessages | undefined;
|
||||
const meEmojiName = meEmojiReact?.name as keyof typeof reactMessages | undefined;
|
||||
|
||||
const reactMessages = {
|
||||
'👍': messages.reactionLike,
|
||||
|
|
|
@ -4,7 +4,7 @@ import React from 'react';
|
|||
import { Text, Icon, Emoji } from 'soapbox/components/ui';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||
|
||||
import type { Map as ImmutableMap } from 'immutable';
|
||||
import type { EmojiReaction } from 'soapbox/schemas';
|
||||
|
||||
const COLORS = {
|
||||
accent: 'accent',
|
||||
|
@ -33,7 +33,7 @@ interface IStatusActionButton extends React.ButtonHTMLAttributes<HTMLButtonEleme
|
|||
active?: boolean;
|
||||
color?: Color;
|
||||
filled?: boolean;
|
||||
emoji?: ImmutableMap<string, any>;
|
||||
emoji?: EmojiReaction;
|
||||
text?: React.ReactNode;
|
||||
theme?: 'default' | 'inverse';
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ const StatusActionButton = React.forwardRef<HTMLButtonElement, IStatusActionButt
|
|||
if (emoji) {
|
||||
return (
|
||||
<span className='flex h-6 w-6 items-center justify-center'>
|
||||
<Emoji className='h-full w-full p-0.5' emoji={emoji.get('name')} src={emoji.get('url')} />
|
||||
<Emoji className='h-full w-full p-0.5' emoji={emoji.name} src={emoji.url} />
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -71,7 +71,7 @@ const StatusReactionWrapper: React.FC<IStatusReactionWrapper> = ({ statusId, chi
|
|||
};
|
||||
|
||||
const handleClick: React.EventHandler<React.MouseEvent> = e => {
|
||||
const meEmojiReact = getReactForStatus(status, soapboxConfig.allowedEmoji)?.get('name') || '👍';
|
||||
const meEmojiReact = getReactForStatus(status, soapboxConfig.allowedEmoji)?.name || '👍';
|
||||
|
||||
if (isUserTouching()) {
|
||||
if (ownAccount) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import HoverStatusWrapper from 'soapbox/components/hover-status-wrapper';
|
|||
import { useAppDispatch } from 'soapbox/hooks';
|
||||
import { isPubkey } from 'soapbox/utils/nostr';
|
||||
|
||||
import type { Account, Status } from 'soapbox/types/entities';
|
||||
import type { Status } from 'soapbox/types/entities';
|
||||
|
||||
interface IStatusReplyMentions {
|
||||
status: Status;
|
||||
|
@ -21,7 +21,7 @@ const StatusReplyMentions: React.FC<IStatusReplyMentions> = ({ status, hoverable
|
|||
const handleOpenMentionsModal: React.MouseEventHandler<HTMLSpanElement> = (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
const account = status.account as Account;
|
||||
const account = status.account;
|
||||
|
||||
dispatch(openModal('MENTIONS', {
|
||||
username: account.acct,
|
||||
|
|
|
@ -24,10 +24,7 @@ import StatusInfo from './statuses/status-info';
|
|||
import Tombstone from './tombstone';
|
||||
import { Card, Icon, Stack, Text } from './ui';
|
||||
|
||||
import type {
|
||||
Account as AccountEntity,
|
||||
Status as StatusEntity,
|
||||
} from 'soapbox/types/entities';
|
||||
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
||||
// Defined in components/scrollable-list
|
||||
export type ScrollPosition = { height: number; top: number };
|
||||
|
@ -168,7 +165,7 @@ const Status: React.FC<IStatus> = (props) => {
|
|||
|
||||
const handleHotkeyMention = (e?: KeyboardEvent): void => {
|
||||
e?.preventDefault();
|
||||
dispatch(mentionCompose(actualStatus.account as AccountEntity));
|
||||
dispatch(mentionCompose(actualStatus.account));
|
||||
};
|
||||
|
||||
const handleHotkeyOpen = (): void => {
|
||||
|
|
|
@ -3,11 +3,10 @@ import { FormattedMessage, useIntl } from 'react-intl';
|
|||
|
||||
import { translateStatus, undoStatusTranslation } from 'soapbox/actions/statuses';
|
||||
import { useAppDispatch, useAppSelector, useFeatures, useInstance } from 'soapbox/hooks';
|
||||
import { isLocal } from 'soapbox/utils/accounts';
|
||||
|
||||
import { Stack, Button, Text } from './ui';
|
||||
|
||||
import type { Account, Status } from 'soapbox/types/entities';
|
||||
import type { Status } from 'soapbox/types/entities';
|
||||
|
||||
interface ITranslateButton {
|
||||
status: Status;
|
||||
|
@ -28,7 +27,7 @@ const TranslateButton: React.FC<ITranslateButton> = ({ status }) => {
|
|||
target_languages: targetLanguages,
|
||||
} = instance.pleroma.metadata.translation;
|
||||
|
||||
const renderTranslate = (me || allowUnauthenticated) && (allowRemote || isLocal(status.account as Account)) && ['public', 'unlisted'].includes(status.visibility) && status.contentHtml.length > 0 && status.language !== null && intl.locale !== status.language;
|
||||
const renderTranslate = (me || allowUnauthenticated) && (allowRemote || status.account.local) && ['public', 'unlisted'].includes(status.visibility) && status.contentHtml.length > 0 && status.language !== null && intl.locale !== status.language;
|
||||
|
||||
const supportsLanguages = (!sourceLanguages || sourceLanguages.includes(status.language!)) && (!targetLanguages || targetLanguages.includes(intl.locale));
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ const Select = React.forwardRef<HTMLSelectElement, ISelect>((props, ref) => {
|
|||
<select
|
||||
ref={ref}
|
||||
className={clsx(
|
||||
'w-full truncate rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-primary-500 focus:outline-none focus:ring-primary-500 disabled:opacity-50 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:focus:border-primary-500 dark:focus:ring-primary-500 sm:text-sm',
|
||||
'w-full truncate rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-primary-500 focus:outline-none focus:ring-primary-500 disabled:opacity-50 sm:text-sm dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:focus:border-primary-500 dark:focus:ring-primary-500',
|
||||
className,
|
||||
)}
|
||||
{...filteredProps}
|
||||
|
|
|
@ -45,7 +45,7 @@ const TagInput: React.FC<ITagInput> = ({ tags, onChange, placeholder }) => {
|
|||
return (
|
||||
<div className='relative mt-1 grow shadow-sm'>
|
||||
<HStack
|
||||
className='block w-full rounded-md border-gray-400 bg-white p-2 pb-0 text-gray-900 placeholder:text-gray-600 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus:border-primary-500 dark:focus:ring-primary-500 sm:text-sm'
|
||||
className='block w-full rounded-md border-gray-400 bg-white p-2 pb-0 text-gray-900 placeholder:text-gray-600 focus:border-primary-500 focus:ring-primary-500 sm:text-sm dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus:border-primary-500 dark:focus:ring-primary-500'
|
||||
space={2}
|
||||
wrap
|
||||
>
|
||||
|
|
|
@ -8,7 +8,7 @@ import { getTextDirection } from 'soapbox/utils/rtl';
|
|||
import Stack from '../stack/stack';
|
||||
import Text from '../text/text';
|
||||
|
||||
interface ITextarea extends Pick<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'id' | 'maxLength' | 'onChange' | 'onKeyDown' | 'onPaste' | 'required' | 'disabled' | 'rows' | 'readOnly'> {
|
||||
interface ITextarea extends Pick<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'id' | 'maxLength' | 'onChange' | 'onClick' | 'onKeyDown' | 'onPaste' | 'required' | 'disabled' | 'rows' | 'readOnly'> {
|
||||
/** Put the cursor into the input on mount. */
|
||||
autoFocus?: boolean;
|
||||
/** Allows the textarea height to grow while typing */
|
||||
|
@ -48,13 +48,14 @@ const Textarea = React.forwardRef(({
|
|||
autoGrow = false,
|
||||
maxRows = 10,
|
||||
minRows = 1,
|
||||
rows: initialRows = 4,
|
||||
theme = 'default',
|
||||
maxLength,
|
||||
value,
|
||||
...props
|
||||
}: ITextarea, ref: React.ForwardedRef<HTMLTextAreaElement>) => {
|
||||
const length = value?.length || 0;
|
||||
const [rows, setRows] = useState<number>(autoGrow ? 1 : 4);
|
||||
const [rows, setRows] = useState<number>(autoGrow ? minRows : initialRows);
|
||||
const locale = useLocale();
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
|
@ -90,7 +91,7 @@ const Textarea = React.forwardRef(({
|
|||
ref={ref}
|
||||
rows={rows}
|
||||
onChange={handleChange}
|
||||
className={clsx('block w-full rounded-md text-gray-900 placeholder:text-gray-600 dark:text-gray-100 dark:placeholder:text-gray-600 sm:text-sm', {
|
||||
className={clsx('block w-full rounded-md text-gray-900 placeholder:text-gray-600 sm:text-sm dark:text-gray-100 dark:placeholder:text-gray-600', {
|
||||
'bg-white dark:bg-transparent shadow-sm border-gray-400 dark:border-gray-800 dark:ring-1 dark:ring-gray-800 focus:ring-primary-500 focus:border-primary-500 dark:focus:ring-primary-500 dark:focus:border-primary-500':
|
||||
theme === 'default',
|
||||
'bg-transparent border-0 focus:border-0 focus:ring-0': theme === 'transparent',
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { List as ImmutableList } from 'immutable';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
@ -13,7 +14,6 @@ import { getAccountGallery } from 'soapbox/selectors';
|
|||
|
||||
import MediaItem from './components/media-item';
|
||||
|
||||
import type { List as ImmutableList } from 'immutable';
|
||||
import type { Attachment, Status } from 'soapbox/types/entities';
|
||||
|
||||
interface ILoadMoreMedia {
|
||||
|
@ -41,7 +41,7 @@ const AccountGallery = () => {
|
|||
isUnavailable,
|
||||
} = useAccountLookup(username, { withRelationship: true });
|
||||
|
||||
const attachments: ImmutableList<Attachment> = useAppSelector((state) => getAccountGallery(state, account!.id));
|
||||
const attachments: ImmutableList<Attachment> = useAppSelector((state) => account ? getAccountGallery(state, account.id) : ImmutableList());
|
||||
const isLoading = useAppSelector((state) => state.timelines.get(`account:${account?.id}:media`)?.isLoading);
|
||||
const hasMore = useAppSelector((state) => state.timelines.get(`account:${account?.id}:media`)?.hasMore);
|
||||
const next = useAppSelector(state => state.timelines.get(`account:${account?.id}:media`)?.next);
|
||||
|
|
|
@ -28,7 +28,7 @@ import { ChatKeys, useChats } from 'soapbox/queries/chats';
|
|||
import { queryClient } from 'soapbox/queries/client';
|
||||
import { Account } from 'soapbox/schemas';
|
||||
import toast from 'soapbox/toast';
|
||||
import { isDefaultHeader, isLocal, isRemote } from 'soapbox/utils/accounts';
|
||||
import { isDefaultHeader } from 'soapbox/utils/accounts';
|
||||
import copy from 'soapbox/utils/copy';
|
||||
import { MASTODON, parseVersion } from 'soapbox/utils/features';
|
||||
|
||||
|
@ -110,7 +110,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
return (
|
||||
<div className='-mx-4 -mt-4 sm:-mx-6 sm:-mt-6'>
|
||||
<div>
|
||||
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' />
|
||||
<div className='relative h-32 w-full bg-gray-200 md:rounded-t-xl lg:h-48 dark:bg-gray-900/50' />
|
||||
</div>
|
||||
|
||||
<div className='px-4 sm:px-6'>
|
||||
|
@ -287,7 +287,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
return [];
|
||||
}
|
||||
|
||||
if (features.rssFeeds && isLocal(account)) {
|
||||
if (features.rssFeeds && account.local) {
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.subscribeFeed),
|
||||
action: handleRssFeedClick,
|
||||
|
@ -303,7 +303,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
});
|
||||
}
|
||||
|
||||
if (features.federating && isRemote(account)) {
|
||||
if (features.federating && !account.local) {
|
||||
const domain = account.fqn.split('@')[1];
|
||||
|
||||
menu.push({
|
||||
|
@ -453,7 +453,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
});
|
||||
}
|
||||
|
||||
if (isRemote(account)) {
|
||||
if (!account.local) {
|
||||
const domain = account.fqn.split('@')[1];
|
||||
|
||||
menu.push(null);
|
||||
|
@ -620,7 +620,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
)}
|
||||
|
||||
<div>
|
||||
<div className='relative isolate flex h-32 w-full flex-col justify-center overflow-hidden bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48'>
|
||||
<div className='relative isolate flex h-32 w-full flex-col justify-center overflow-hidden bg-gray-200 md:rounded-t-xl lg:h-48 dark:bg-gray-900/50'>
|
||||
{renderHeader()}
|
||||
|
||||
<div className='absolute left-2 top-2'>
|
||||
|
|
|
@ -44,7 +44,7 @@ const Search: React.FC = () => {
|
|||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.search)}</span>
|
||||
|
||||
<input
|
||||
className='block w-full rounded-full focus:border-primary-500 focus:ring-primary-500 dark:bg-gray-800 dark:text-white dark:placeholder:text-gray-500 sm:text-sm'
|
||||
className='block w-full rounded-full focus:border-primary-500 focus:ring-primary-500 sm:text-sm dark:bg-gray-800 dark:text-white dark:placeholder:text-gray-500'
|
||||
type='text'
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
|
|
|
@ -16,7 +16,7 @@ const ConsumersList: React.FC<IConsumersList> = () => {
|
|||
|
||||
if (providers.length > 0) {
|
||||
return (
|
||||
<Card className='bg-gray-50 p-4 dark:bg-primary-800 sm:rounded-xl'>
|
||||
<Card className='bg-gray-50 p-4 sm:rounded-xl dark:bg-primary-800'>
|
||||
<Text size='xs' theme='muted'>
|
||||
<FormattedMessage id='oauth_consumers.title' defaultMessage='Other ways to sign in' />
|
||||
</Text>
|
||||
|
|
|
@ -60,7 +60,7 @@ const ChatPage: React.FC<IChatPage> = ({ chatId }) => {
|
|||
<div
|
||||
ref={containerRef}
|
||||
style={{ height }}
|
||||
className='h-screen overflow-hidden bg-white text-gray-900 shadow-lg dark:bg-primary-900 dark:text-gray-100 dark:shadow-none sm:rounded-t-xl'
|
||||
className='h-screen overflow-hidden bg-white text-gray-900 shadow-lg sm:rounded-t-xl dark:bg-primary-900 dark:text-gray-100 dark:shadow-none'
|
||||
>
|
||||
{isOnboarded ? (
|
||||
<div
|
||||
|
@ -68,7 +68,7 @@ const ChatPage: React.FC<IChatPage> = ({ chatId }) => {
|
|||
data-testid='chat-page'
|
||||
>
|
||||
<Stack
|
||||
className={clsx('dark:inset col-span-9 overflow-hidden bg-gradient-to-r from-white to-gray-100 dark:bg-gray-900 dark:bg-none sm:col-span-3', {
|
||||
className={clsx('dark:inset col-span-9 overflow-hidden bg-gradient-to-r from-white to-gray-100 sm:col-span-3 dark:bg-gray-900 dark:bg-none', {
|
||||
'hidden sm:block': isSidebarHidden,
|
||||
})}
|
||||
>
|
||||
|
|
|
@ -121,7 +121,7 @@ const ChatPageMain = () => {
|
|||
<HStack alignItems='center'>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/arrow-left.svg')}
|
||||
className='mr-2 h-7 w-7 rtl:rotate-180 sm:mr-0 sm:hidden'
|
||||
className='mr-2 h-7 w-7 sm:mr-0 sm:hidden rtl:rotate-180'
|
||||
onClick={() => history.push('/chats')}
|
||||
/>
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ const ChatPageNew: React.FC<IChatPageNew> = () => {
|
|||
<HStack alignItems='center'>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/arrow-left.svg')}
|
||||
className='mr-2 h-7 w-7 rtl:rotate-180 sm:mr-0 sm:hidden'
|
||||
className='mr-2 h-7 w-7 sm:mr-0 sm:hidden rtl:rotate-180'
|
||||
onClick={() => history.push('/chats')}
|
||||
/>
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ const ChatPageSettings = () => {
|
|||
<HStack alignItems='center'>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/arrow-left.svg')}
|
||||
className='mr-2 h-7 w-7 rtl:rotate-180 sm:mr-0 sm:hidden'
|
||||
className='mr-2 h-7 w-7 sm:mr-0 sm:hidden rtl:rotate-180'
|
||||
onClick={() => history.push('/chats')}
|
||||
/>
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ const ChatTextarea: React.FC<IChatTextarea> = React.forwardRef(({
|
|||
bg-white text-gray-900
|
||||
shadow-sm placeholder:text-gray-600
|
||||
focus-within:border-primary-500
|
||||
focus-within:ring-1 focus-within:ring-primary-500 dark:border-gray-800 dark:bg-gray-800
|
||||
dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500
|
||||
dark:focus-within:ring-primary-500 sm:text-sm
|
||||
focus-within:ring-1 focus-within:ring-primary-500 sm:text-sm dark:border-gray-800
|
||||
dark:bg-gray-800 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600
|
||||
dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500
|
||||
`}
|
||||
>
|
||||
{(!!attachments?.length || isUploading) && (
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import clsx from 'clsx';
|
||||
import { CLEAR_EDITOR_COMMAND, TextNode, type LexicalEditor } from 'lexical';
|
||||
import { CLEAR_EDITOR_COMMAND, TextNode, type LexicalEditor, $getRoot } from 'lexical';
|
||||
import React, { Suspense, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
|
@ -18,7 +18,6 @@ import { Button, HStack, Stack } from 'soapbox/components/ui';
|
|||
import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container';
|
||||
import { ComposeEditor } 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';
|
||||
|
@ -96,23 +95,25 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
const anyMedia = compose.media_attachments.size > 0;
|
||||
|
||||
const [composeFocused, setComposeFocused] = useState(false);
|
||||
const [text, setText] = useState(compose.text);
|
||||
|
||||
const firstRender = useRef(true);
|
||||
const formRef = useRef<HTMLDivElement>(null);
|
||||
const spoilerTextRef = useRef<AutosuggestInput>(null);
|
||||
const editorRef = useRef<LexicalEditor>(null);
|
||||
|
||||
const { isDraggedOver } = useDraggedFiles(formRef);
|
||||
|
||||
const text = editorRef.current?.getEditorState().read(() => $getRoot().getTextContent()) ?? '';
|
||||
const fulltext = [spoilerText, countableText(text)].join('');
|
||||
|
||||
const isEmpty = !(fulltext.trim() || anyMedia);
|
||||
const condensed = shouldCondense && !isDraggedOver && !composeFocused && isEmpty && !isUploading;
|
||||
const shouldAutoFocus = autoFocus && !showSearch;
|
||||
const canSubmit = !!editorRef.current && !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars;
|
||||
|
||||
const getClickableArea = () => {
|
||||
return clickableAreaRef ? clickableAreaRef.current : formRef.current;
|
||||
};
|
||||
|
||||
const isEmpty = () => {
|
||||
return !(text || spoilerText || anyMedia);
|
||||
};
|
||||
|
||||
const isClickOutside = (e: MouseEvent | React.MouseEvent) => {
|
||||
return ![
|
||||
// List of elements that shouldn't collapse the composer when clicked
|
||||
|
@ -125,10 +126,10 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
};
|
||||
|
||||
const handleClick = useCallback((e: MouseEvent | React.MouseEvent) => {
|
||||
if (isEmpty() && isClickOutside(e)) {
|
||||
if (isEmpty && isClickOutside(e)) {
|
||||
handleClickOutside();
|
||||
}
|
||||
}, []);
|
||||
}, [isEmpty]);
|
||||
|
||||
const handleClickOutside = () => {
|
||||
setComposeFocused(false);
|
||||
|
@ -139,20 +140,12 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
};
|
||||
|
||||
const handleSubmit = (e?: React.FormEvent<Element>) => {
|
||||
if (!canSubmit) return;
|
||||
e?.preventDefault();
|
||||
|
||||
dispatch(changeCompose(id, text));
|
||||
|
||||
// Submit disabled:
|
||||
const fulltext = [spoilerText, countableText(text)].join('');
|
||||
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (isSubmitting || isUploading || isChangingUpload || length(fulltext) > maxTootChars || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(submitCompose(id, { history }));
|
||||
|
||||
editorRef.current?.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined);
|
||||
};
|
||||
|
||||
|
@ -215,12 +208,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
</HStack>
|
||||
), [features, id]);
|
||||
|
||||
const condensed = shouldCondense && !isDraggedOver && !composeFocused && isEmpty() && !isUploading;
|
||||
const disabled = isSubmitting;
|
||||
const countedText = [spoilerText, countableText(text)].join('');
|
||||
const disabledButton = disabled || isUploading || isChangingUpload || length(countedText) > maxTootChars || (countedText.length !== 0 && countedText.trim().length === 0 && !anyMedia);
|
||||
const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth);
|
||||
|
||||
const composeModifiers = !condensed && (
|
||||
<Stack space={4} className='compose-form__modifiers'>
|
||||
<UploadForm composeId={id} onSubmit={handleSubmit} />
|
||||
|
@ -297,7 +284,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
autoFocus={shouldAutoFocus}
|
||||
hasPoll={hasPoll}
|
||||
handleSubmit={handleSubmit}
|
||||
onChange={setText}
|
||||
onFocus={handleComposeFocus}
|
||||
onPaste={onPaste}
|
||||
/>
|
||||
|
@ -324,7 +310,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
</HStack>
|
||||
)}
|
||||
|
||||
<Button type='submit' theme='primary' icon={publishIcon} text={publishText} disabled={disabledButton} />
|
||||
<Button type='submit' theme='primary' icon={publishIcon} text={publishText} disabled={!canSubmit} />
|
||||
</HStack>
|
||||
</div>
|
||||
</Stack>
|
||||
|
|
|
@ -11,10 +11,6 @@ export const FOCUS_EDITOR_COMMAND: LexicalCommand<void> = createCommand();
|
|||
const FocusPlugin: React.FC<IFocusPlugin> = ({ autoFocus }) => {
|
||||
const [editor] = useLexicalComposerContext();
|
||||
|
||||
const focus = () => {
|
||||
editor.dispatchCommand(FOCUS_EDITOR_COMMAND, undefined);
|
||||
};
|
||||
|
||||
useEffect(() => editor.registerCommand(FOCUS_EDITOR_COMMAND, () => {
|
||||
editor.focus(
|
||||
() => {
|
||||
|
@ -29,8 +25,10 @@ const FocusPlugin: React.FC<IFocusPlugin> = ({ autoFocus }) => {
|
|||
}, COMMAND_PRIORITY_NORMAL));
|
||||
|
||||
useEffect(() => {
|
||||
if (autoFocus) focus();
|
||||
}, []);
|
||||
if (autoFocus) {
|
||||
editor.dispatchCommand(FOCUS_EDITOR_COMMAND, undefined);
|
||||
}
|
||||
}, [autoFocus, editor]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
|
|
@ -36,7 +36,7 @@ const HeaderPicker = React.forwardRef<HTMLInputElement, IMediaInput>(({ src, onC
|
|||
<label
|
||||
ref={picker}
|
||||
className={clsx(
|
||||
'dark:sm:shadow-inset relative h-24 w-full cursor-pointer overflow-hidden rounded-lg bg-primary-100 text-primary-500 dark:bg-gray-800 dark:text-accent-blue sm:h-36 sm:shadow',
|
||||
'dark:sm:shadow-inset relative h-24 w-full cursor-pointer overflow-hidden rounded-lg bg-primary-100 text-primary-500 sm:h-36 sm:shadow dark:bg-gray-800 dark:text-accent-blue',
|
||||
{
|
||||
'border-2 border-primary-600 border-dashed !z-[99]': isDragging,
|
||||
'ring-2 ring-offset-2 ring-primary-600': isDraggedOver,
|
||||
|
|
|
@ -19,7 +19,6 @@ import { Button, HStack, IconButton, Menu, MenuButton, MenuDivider, MenuItem, Me
|
|||
import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
|
||||
import VerificationBadge from 'soapbox/components/verification-badge';
|
||||
import { useAppDispatch, useFeatures, useOwnAccount, useSettings } from 'soapbox/hooks';
|
||||
import { isRemote } from 'soapbox/utils/accounts';
|
||||
import copy from 'soapbox/utils/copy';
|
||||
import { download } from 'soapbox/utils/download';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||
|
@ -29,7 +28,7 @@ import EventActionButton from '../components/event-action-button';
|
|||
import EventDate from '../components/event-date';
|
||||
|
||||
import type { Menu as MenuType } from 'soapbox/components/dropdown-menu';
|
||||
import type { Account as AccountEntity, Status as StatusEntity } from 'soapbox/types/entities';
|
||||
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
||||
const messages = defineMessages({
|
||||
bannerHeader: { id: 'event.banner', defaultMessage: 'Event banner' },
|
||||
|
@ -81,7 +80,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
|||
return (
|
||||
<>
|
||||
<div className='-mx-4 -mt-4'>
|
||||
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' />
|
||||
<div className='relative h-32 w-full bg-gray-200 md:rounded-t-xl lg:h-48 dark:bg-gray-900/50' />
|
||||
</div>
|
||||
|
||||
<PlaceholderEventHeader />
|
||||
|
@ -89,7 +88,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
|||
);
|
||||
}
|
||||
|
||||
const account = status.account as AccountEntity;
|
||||
const account = status.account;
|
||||
const event = status.event;
|
||||
const banner = event.banner;
|
||||
|
||||
|
@ -217,7 +216,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
|||
},
|
||||
];
|
||||
|
||||
if (features.federating && isRemote(account)) {
|
||||
if (features.federating && !account.local) {
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.external, { domain }),
|
||||
action: handleExternalClick,
|
||||
|
@ -365,7 +364,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
|||
return (
|
||||
<>
|
||||
<div className='-mx-4 -mt-4'>
|
||||
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48'>
|
||||
<div className='relative h-32 w-full bg-gray-200 md:rounded-t-xl lg:h-48 dark:bg-gray-900/50'>
|
||||
{banner && (
|
||||
<a href={banner.url} onClick={handleHeaderClick} target='_blank'>
|
||||
<StillImage
|
||||
|
|
|
@ -24,7 +24,7 @@ const SuggestionItem: React.FC<ISuggestionItem> = ({ accountId }) => {
|
|||
if (!account) return null;
|
||||
|
||||
return (
|
||||
<Stack space={3} className='w-52 shrink-0 rounded-md border border-solid border-gray-300 p-4 dark:border-gray-800 md:w-full md:shrink md:border-transparent md:p-0 dark:md:border-transparent'>
|
||||
<Stack space={3} className='w-52 shrink-0 rounded-md border border-solid border-gray-300 p-4 md:w-full md:shrink md:border-transparent md:p-0 dark:border-gray-800 dark:md:border-transparent'>
|
||||
<Link
|
||||
to={`/@${account.acct}`}
|
||||
title={account.acct}
|
||||
|
|
|
@ -36,7 +36,7 @@ const GroupHeader: React.FC<IGroupHeader> = ({ group }) => {
|
|||
return (
|
||||
<div className='-mx-4 -mt-4 sm:-mx-6 sm:-mt-6' data-testid='group-header-missing'>
|
||||
<div>
|
||||
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' />
|
||||
<div className='relative h-32 w-full bg-gray-200 md:rounded-t-xl lg:h-48 dark:bg-gray-900/50' />
|
||||
</div>
|
||||
|
||||
<div className='px-4 sm:px-6'>
|
||||
|
@ -92,7 +92,7 @@ const GroupHeader: React.FC<IGroupHeader> = ({ group }) => {
|
|||
<StillImage
|
||||
src={group.header}
|
||||
alt={intl.formatMessage(messages.header)}
|
||||
className='relative h-32 w-full bg-gray-200 object-center dark:bg-gray-900/50 md:rounded-t-xl lg:h-52'
|
||||
className='relative h-32 w-full bg-gray-200 object-center md:rounded-t-xl lg:h-52 dark:bg-gray-900/50'
|
||||
onError={() => setIsHeaderMissing(true)}
|
||||
/>
|
||||
);
|
||||
|
@ -109,7 +109,7 @@ const GroupHeader: React.FC<IGroupHeader> = ({ group }) => {
|
|||
return (
|
||||
<div
|
||||
data-testid='group-header-image'
|
||||
className='flex h-32 w-full items-center justify-center bg-gray-200 dark:bg-gray-800/30 md:rounded-t-xl lg:h-52'
|
||||
className='flex h-32 w-full items-center justify-center bg-gray-200 md:rounded-t-xl lg:h-52 dark:bg-gray-800/30'
|
||||
>
|
||||
{isHeaderMissing ? (
|
||||
<Icon src={require('@tabler/icons/photo-off.svg')} className='h-6 w-6 text-gray-500 dark:text-gray-700' />
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useHashtagStream } from 'soapbox/api/hooks';
|
|||
import List, { ListItem } from 'soapbox/components/list';
|
||||
import { Column, Toggle } from 'soapbox/components/ui';
|
||||
import Timeline from 'soapbox/features/ui/components/timeline';
|
||||
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
|
||||
import { useAppDispatch, useAppSelector, useFeatures, useLoggedIn } from 'soapbox/hooks';
|
||||
|
||||
interface IHashtagTimeline {
|
||||
params?: {
|
||||
|
@ -22,7 +22,7 @@ export const HashtagTimeline: React.FC<IHashtagTimeline> = ({ params }) => {
|
|||
const dispatch = useAppDispatch();
|
||||
const tag = useAppSelector((state) => state.tags.get(id));
|
||||
const next = useAppSelector(state => state.timelines.get(`hashtag:${id}`)?.next);
|
||||
|
||||
const { isLoggedIn } = useLoggedIn();
|
||||
|
||||
const handleLoadMore = (maxId: string) => {
|
||||
dispatch(expandHashtagTimeline(id, { url: next, maxId }));
|
||||
|
@ -50,7 +50,7 @@ export const HashtagTimeline: React.FC<IHashtagTimeline> = ({ params }) => {
|
|||
|
||||
return (
|
||||
<Column label={`#${id}`} transparent>
|
||||
{features.followHashtags && (
|
||||
{features.followHashtags && isLoggedIn && (
|
||||
<List>
|
||||
<ListItem
|
||||
label={<FormattedMessage id='hashtag.follow' defaultMessage='Follow hashtag' />}
|
||||
|
|
|
@ -5,7 +5,7 @@ import React from 'react';
|
|||
* For testing logging/monitoring & previewing ErrorBoundary design.
|
||||
*/
|
||||
const IntentionalError: React.FC = () => {
|
||||
throw 'This error is intentional.';
|
||||
throw new Error('This error is intentional.');
|
||||
};
|
||||
|
||||
export default IntentionalError;
|
||||
|
|
|
@ -7,6 +7,8 @@ import {
|
|||
nip04 as _nip04,
|
||||
} from 'nostr-tools';
|
||||
|
||||
import { powWorker } from 'soapbox/workers';
|
||||
|
||||
/** localStorage key for the Nostr private key (if not using NIP-07). */
|
||||
const LOCAL_KEY = 'soapbox:nostr:privateKey';
|
||||
|
||||
|
@ -28,9 +30,18 @@ async function getPublicKey(): Promise<string> {
|
|||
return window.nostr ? window.nostr.getPublicKey() : _getPublicKey(getPrivateKey());
|
||||
}
|
||||
|
||||
interface SignEventOpts {
|
||||
pow?: number;
|
||||
}
|
||||
|
||||
/** Sign an event with NIP-07, or the locally generated key. */
|
||||
async function signEvent<K extends number>(event: EventTemplate<K>): Promise<Event<K>> {
|
||||
async function signEvent<K extends number>(template: EventTemplate<K>, opts: SignEventOpts = {}): Promise<Event<K>> {
|
||||
if (opts.pow) {
|
||||
const event = await powWorker.mine({ ...template, pubkey: await getPublicKey() }, opts.pow) as Omit<Event<K>, 'sig'>;
|
||||
return window.nostr ? window.nostr.signEvent(event) as Promise<Event<K>> : finishEvent(event, getPrivateKey()) ;
|
||||
} else {
|
||||
return window.nostr ? window.nostr.signEvent(template) as Promise<Event<K>> : finishEvent(template, getPrivateKey()) ;
|
||||
}
|
||||
}
|
||||
|
||||
/** Crypto function with NIP-07, or the local key. */
|
||||
|
|
|
@ -26,7 +26,7 @@ const FediverseStep = ({ onNext }: { onNext: () => void }) => {
|
|||
</Text>
|
||||
|
||||
<Stack space={4}>
|
||||
<div className='border-b border-solid border-gray-200 pb-2 dark:border-gray-800 sm:pb-5'>
|
||||
<div className='border-b border-solid border-gray-200 pb-2 sm:pb-5 dark:border-gray-800'>
|
||||
<Stack space={4}>
|
||||
<Text theme='muted'>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -8,7 +8,7 @@ import PlaceholderStatusContent from './placeholder-status-content';
|
|||
|
||||
/** Fake notification to display while data is loading. */
|
||||
const PlaceholderNotification = () => (
|
||||
<div className='bg-white px-4 py-6 dark:bg-primary-900 sm:p-6'>
|
||||
<div className='bg-white px-4 py-6 sm:p-6 dark:bg-primary-900'>
|
||||
<div className='w-full animate-pulse'>
|
||||
<div className='mb-2'>
|
||||
<PlaceholderStatusContent minLength={20} maxLength={20} />
|
||||
|
|
|
@ -13,7 +13,7 @@ import { buildStatus } from '../builder';
|
|||
|
||||
import ScheduledStatusActionBar from './scheduled-status-action-bar';
|
||||
|
||||
import type { Account as AccountEntity, Status as StatusEntity } from 'soapbox/types/entities';
|
||||
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
||||
interface IScheduledStatus {
|
||||
statusId: string;
|
||||
|
@ -28,7 +28,7 @@ const ScheduledStatus: React.FC<IScheduledStatus> = ({ statusId, ...other }) =>
|
|||
|
||||
if (!status) return null;
|
||||
|
||||
const account = status.account as AccountEntity;
|
||||
const account = status.account;
|
||||
|
||||
return (
|
||||
<div className={clsx('status__wrapper', `status__wrapper-${status.visibility}`, { 'status__wrapper-reply': !!status.in_reply_to_id })} tabIndex={0}>
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import clsx from 'clsx';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
|
@ -59,7 +57,7 @@ const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({ status }): JSX.
|
|||
|
||||
const getNormalizedReacts = () => {
|
||||
return reduceEmoji(
|
||||
ImmutableList(status.pleroma.get('emoji_reactions') as any),
|
||||
status.reactions,
|
||||
status.favourites_count,
|
||||
status.favourited,
|
||||
allowedEmoji,
|
||||
|
@ -164,20 +162,22 @@ const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({ status }): JSX.
|
|||
const getEmojiReacts = () => {
|
||||
const emojiReacts = getNormalizedReacts();
|
||||
const count = emojiReacts.reduce((acc, cur) => (
|
||||
acc + cur.get('count')
|
||||
acc + (cur.count || 0)
|
||||
), 0);
|
||||
|
||||
const handleClick = features.emojiReacts ? handleOpenReactionsModal : handleOpenFavouritesModal;
|
||||
|
||||
if (count) {
|
||||
return (
|
||||
<InteractionCounter count={count} onClick={features.exposableReactions ? handleOpenReactionsModal : undefined}>
|
||||
<InteractionCounter count={count} onClick={features.exposableReactions ? handleClick : undefined}>
|
||||
<HStack space={0.5} alignItems='center'>
|
||||
{emojiReacts.take(3).map((e, i) => {
|
||||
return (
|
||||
<Emoji
|
||||
key={i}
|
||||
className='h-4.5 w-4.5 flex-none'
|
||||
emoji={e.get('name')}
|
||||
src={e.get('url')}
|
||||
emoji={e.name}
|
||||
src={e.url}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -193,7 +193,7 @@ const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({ status }): JSX.
|
|||
<HStack space={3}>
|
||||
{getReposts()}
|
||||
{getQuotes()}
|
||||
{features.emojiReacts ? getEmojiReacts() : getFavourites()}
|
||||
{(features.emojiReacts || features.emojiReactsMastodon) ? getEmojiReacts() : getFavourites()}
|
||||
{getDislikes()}
|
||||
</HStack>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { Column, Stack, Text, IconButton } from 'soapbox/components/ui';
|
||||
import { isNetworkError } from 'soapbox/utils/errors';
|
||||
|
||||
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 IErrorColumn {
|
||||
error: Error;
|
||||
onRetry?: () => void;
|
||||
}
|
||||
|
||||
const ErrorColumn: React.FC<IErrorColumn> = ({ error, onRetry = () => location.reload() }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const handleRetry = () => {
|
||||
onRetry?.();
|
||||
};
|
||||
|
||||
if (!isNetworkError(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
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 ErrorColumn;
|
|
@ -12,7 +12,6 @@ import OutlineBox from 'soapbox/components/outline-box';
|
|||
import { Button, Text, HStack, Modal, Stack, Toggle } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
||||
import toast from 'soapbox/toast';
|
||||
import { isLocal } from 'soapbox/utils/accounts';
|
||||
import { getBadges } from 'soapbox/utils/badges';
|
||||
|
||||
import BadgeInput from './badge-input';
|
||||
|
@ -115,7 +114,7 @@ const AccountModerationModal: React.FC<IAccountModerationModal> = ({ onClose, ac
|
|||
</OutlineBox>
|
||||
|
||||
<List>
|
||||
{(ownAccount.admin && isLocal(account)) && (
|
||||
{(ownAccount.admin && account.local) && (
|
||||
<ListItem label={<FormattedMessage id='account_moderation_modal.fields.account_role' defaultMessage='Staff level' />}>
|
||||
<div className='w-auto'>
|
||||
<StaffRolePicker account={account} />
|
||||
|
|
|
@ -209,7 +209,7 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
|
|||
<FormGroup
|
||||
labelText={<FormattedMessage id='compose_event.fields.banner_label' defaultMessage='Event banner' />}
|
||||
>
|
||||
<div className='dark:sm:shadow-inset relative flex h-24 items-center justify-center overflow-hidden rounded-lg bg-primary-100 text-primary-500 dark:bg-gray-800 dark:text-white sm:h-32 sm:shadow'>
|
||||
<div className='dark:sm:shadow-inset relative flex h-24 items-center justify-center overflow-hidden rounded-lg bg-primary-100 text-primary-500 sm:h-32 sm:shadow dark:bg-gray-800 dark:text-white'>
|
||||
{banner ? (
|
||||
<>
|
||||
<img className='h-full w-full object-cover' src={banner.url} alt='' />
|
||||
|
@ -234,7 +234,7 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
|
|||
labelText={<FormattedMessage id='compose_event.fields.description_label' defaultMessage='Event description' />}
|
||||
>
|
||||
<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'
|
||||
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 sm:text-sm 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'
|
||||
placeholderClassName='pt-2'
|
||||
composeId='compose-event-modal'
|
||||
placeholder={intl.formatMessage(messages.eventDescriptionPlaceholder)}
|
||||
|
|
|
@ -30,24 +30,25 @@ const EditFederationModal: React.FC<IEditFederationModal> = ({ host, onClose })
|
|||
const getRemoteInstance = useCallback(makeGetRemoteInstance(), []);
|
||||
const remoteInstance = useAppSelector(state => getRemoteInstance(state, host));
|
||||
|
||||
const [data, setData] = useState({} as any);
|
||||
const [data, setData] = useState<Record<string, any>>({});
|
||||
|
||||
useEffect(() => {
|
||||
setData(remoteInstance.get('federation'));
|
||||
setData(remoteInstance.get('federation') as Record<string, any>);
|
||||
}, [remoteInstance]);
|
||||
|
||||
const handleDataChange = (key: string): React.ChangeEventHandler<HTMLInputElement> => {
|
||||
return ({ target }) => {
|
||||
setData(data.set(key, target.checked));
|
||||
setData({ ...data, [key]: target.checked });
|
||||
};
|
||||
};
|
||||
|
||||
const handleMediaRemoval: React.ChangeEventHandler<HTMLInputElement> = ({ target: { checked } }) => {
|
||||
const newData = data.merge({
|
||||
const newData = {
|
||||
...data,
|
||||
avatar_removal: checked,
|
||||
banner_removal: checked,
|
||||
media_removal: checked,
|
||||
});
|
||||
};
|
||||
|
||||
setData(newData);
|
||||
};
|
||||
|
|
|
@ -42,7 +42,7 @@ const ConfirmationStep: React.FC<IConfirmationStep> = ({ group }) => {
|
|||
<Stack space={3}>
|
||||
<Stack>
|
||||
<label
|
||||
className='dark:sm:shadow-inset relative h-24 w-full cursor-pointer overflow-hidden rounded-lg bg-primary-100 text-primary-500 dark:bg-gray-800 dark:text-accent-blue sm:h-36 sm:shadow'
|
||||
className='dark:sm:shadow-inset relative h-24 w-full cursor-pointer overflow-hidden rounded-lg bg-primary-100 text-primary-500 sm:h-36 sm:shadow dark:bg-gray-800 dark:text-accent-blue'
|
||||
>
|
||||
{group.header && <img className='h-full w-full object-cover' src={group.header} alt='' />}
|
||||
</label>
|
||||
|
|
|
@ -17,8 +17,6 @@ import ConfirmationStep from './steps/confirmation-step';
|
|||
import OtherActionsStep from './steps/other-actions-step';
|
||||
import ReasonStep from './steps/reason-step';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
|
||||
const messages = defineMessages({
|
||||
blankslate: { id: 'report.reason.blankslate', defaultMessage: 'You have removed all statuses from being selected.' },
|
||||
done: { id: 'report.done', defaultMessage: 'Done' },
|
||||
|
@ -123,7 +121,7 @@ const ReportModal = ({ onClose }: IReportModal) => {
|
|||
const handleSubmit = () => {
|
||||
dispatch(submitReport())
|
||||
.then(() => setCurrentStep(Steps.THREE))
|
||||
.catch((error: AxiosError) => dispatch(submitReportFail(error)));
|
||||
.catch((error) => dispatch(submitReportFail(error)));
|
||||
|
||||
if (isBlocked && account) {
|
||||
dispatch(blockAccount(account.id));
|
||||
|
|
|
@ -7,7 +7,7 @@ import { fetchRules } from 'soapbox/actions/rules';
|
|||
import { Button, FormGroup, HStack, Stack, Text, Toggle } from 'soapbox/components/ui';
|
||||
import StatusCheckBox from 'soapbox/features/report/components/status-check-box';
|
||||
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
|
||||
import { isRemote, getDomain } from 'soapbox/utils/accounts';
|
||||
import { getDomain } from 'soapbox/utils/accounts';
|
||||
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
|
||||
|
@ -31,7 +31,7 @@ const OtherActionsStep = ({ account }: IOtherActionsStep) => {
|
|||
const statusIds = useAppSelector((state) => OrderedSet(state.timelines.get(`account:${account.id}:with_replies`)!.items).union(state.reports.new.status_ids) as OrderedSet<string>);
|
||||
const isBlocked = useAppSelector((state) => state.reports.new.block);
|
||||
const isForward = useAppSelector((state) => state.reports.new.forward);
|
||||
const canForward = isRemote(account) && features.federating;
|
||||
const canForward = !account.local && features.federating;
|
||||
const isSubmitting = useAppSelector((state) => state.reports.new.isSubmitting);
|
||||
|
||||
const [showAdditionalStatuses, setShowAdditionalStatuses] = useState<boolean>(false);
|
||||
|
|
|
@ -76,7 +76,7 @@ const Navbar = () => {
|
|||
<div className='mx-auto max-w-7xl px-2 sm:px-6 lg:px-8'>
|
||||
<div className='relative flex h-12 justify-between lg:h-16'>
|
||||
{account && (
|
||||
<div className='absolute inset-y-0 left-0 flex items-center rtl:left-auto rtl:right-0 lg:hidden'>
|
||||
<div className='absolute inset-y-0 left-0 flex items-center lg:hidden rtl:left-auto rtl:right-0'>
|
||||
<button onClick={onOpenSidebar}>
|
||||
<Avatar src={account.avatar} size={34} />
|
||||
</button>
|
||||
|
@ -125,7 +125,7 @@ const Navbar = () => {
|
|||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Form className='hidden items-center space-x-2 rtl:space-x-reverse xl:flex' onSubmit={handleSubmit}>
|
||||
<Form className='hidden items-center space-x-2 xl:flex rtl:space-x-reverse' onSubmit={handleSubmit}>
|
||||
<Input
|
||||
required
|
||||
value={username}
|
||||
|
|
|
@ -14,7 +14,7 @@ import { buildStatus } from '../util/pending-status-builder';
|
|||
|
||||
import PollPreview from './poll-preview';
|
||||
|
||||
import type { Account as AccountEntity, Status as StatusEntity } from 'soapbox/types/entities';
|
||||
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
||||
const shouldHaveCard = (pendingStatus: StatusEntity) => {
|
||||
return Boolean(pendingStatus.content.match(/https?:\/\/\S*/));
|
||||
|
@ -54,7 +54,7 @@ const PendingStatus: React.FC<IPendingStatus> = ({ idempotencyKey, className, mu
|
|||
if (!status) return null;
|
||||
if (!status.account) return null;
|
||||
|
||||
const account = status.account as AccountEntity;
|
||||
const account = status.account;
|
||||
|
||||
return (
|
||||
<div className={clsx('opacity-50', className)}>
|
||||
|
|
|
@ -7,7 +7,6 @@ import Markup from 'soapbox/components/markup';
|
|||
import { dateFormatOptions } from 'soapbox/components/relative-timestamp';
|
||||
import { Icon, HStack, Stack, Text } from 'soapbox/components/ui';
|
||||
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
|
||||
import { isLocal } from 'soapbox/utils/accounts';
|
||||
import { badgeToTag, getBadges as getAccountBadges } from 'soapbox/utils/badges';
|
||||
import { capitalize } from 'soapbox/utils/strings';
|
||||
|
||||
|
@ -176,7 +175,7 @@ const ProfileInfoPanel: React.FC<IProfileInfoPanel> = ({ account, username }) =>
|
|||
)}
|
||||
|
||||
<div className='flex flex-col items-start gap-2 md:flex-row md:flex-wrap md:items-center'>
|
||||
{isLocal(account) ? (
|
||||
{account.local ? (
|
||||
<HStack alignItems='center' space={0.5}>
|
||||
<Icon
|
||||
src={require('@tabler/icons/calendar.svg')}
|
||||
|
|
|
@ -329,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={lazy(() => Promise.reject())} 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} />
|
||||
|
||||
{hasCrypto && <WrappedRoute path='/donate/crypto' publicRoute page={DefaultPage} component={CryptoDonate} content={children} />}
|
||||
|
@ -494,7 +494,7 @@ const UI: React.FC<IUI> = ({ children }) => {
|
|||
</Layout>
|
||||
|
||||
{(me && !shouldHideFAB()) && (
|
||||
<div className='fixed bottom-24 right-4 z-40 transition-all rtl:left-4 rtl:right-auto lg:hidden'>
|
||||
<div className='fixed bottom-24 right-4 z-40 transition-all lg:hidden rtl:left-4 rtl:right-auto'>
|
||||
<FloatingActionButton />
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { Suspense } from 'react';
|
||||
import { Redirect, Route, useHistory, RouteProps, RouteComponentProps, match as MatchType } from 'react-router-dom';
|
||||
import React, { Suspense, useEffect, useRef } from 'react';
|
||||
import { ErrorBoundary, type FallbackProps } from 'react-error-boundary';
|
||||
import { Redirect, Route, useHistory, RouteProps, RouteComponentProps, match as MatchType, useLocation } from 'react-router-dom';
|
||||
|
||||
import { Layout } from 'soapbox/components/ui';
|
||||
import { useOwnAccount, useSettings } from 'soapbox/hooks';
|
||||
|
@ -7,6 +8,7 @@ import { useOwnAccount, useSettings } from 'soapbox/hooks';
|
|||
import ColumnForbidden from '../components/column-forbidden';
|
||||
import ColumnLoading from '../components/column-loading';
|
||||
import ColumnsArea from '../components/columns-area';
|
||||
import ErrorColumn from '../components/error-column';
|
||||
|
||||
type PageProps = {
|
||||
params?: MatchType['params'];
|
||||
|
@ -46,40 +48,31 @@ const WrappedRoute: React.FC<IWrappedRoute> = ({
|
|||
const renderComponent = ({ match }: RouteComponentProps) => {
|
||||
if (Page) {
|
||||
return (
|
||||
<Suspense fallback={renderLoading()}>
|
||||
<ErrorBoundary FallbackComponent={FallbackError}>
|
||||
<Suspense fallback={<FallbackLoading />}>
|
||||
<Page params={match.params} layout={layout} {...componentParams}>
|
||||
<Component params={match.params} {...componentParams}>
|
||||
{content}
|
||||
</Component>
|
||||
</Page>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense fallback={renderLoading()}>
|
||||
<ErrorBoundary FallbackComponent={FallbackError}>
|
||||
<Suspense fallback={<FallbackLoading />}>
|
||||
<ColumnsArea layout={layout}>
|
||||
<Component params={match.params} {...componentParams}>
|
||||
{content}
|
||||
</Component>
|
||||
</ColumnsArea>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
const renderWithLayout = (children: JSX.Element) => (
|
||||
<>
|
||||
<Layout.Main>
|
||||
{children}
|
||||
</Layout.Main>
|
||||
|
||||
<Layout.Aside />
|
||||
</>
|
||||
);
|
||||
|
||||
const renderLoading = () => renderWithLayout(<ColumnLoading />);
|
||||
const renderForbidden = () => renderWithLayout(<ColumnForbidden />);
|
||||
|
||||
const loginRedirect = () => {
|
||||
const actualUrl = encodeURIComponent(`${history.location.pathname}${history.location.search}`);
|
||||
localStorage.setItem('soapbox:redirect_uri', actualUrl);
|
||||
|
@ -97,13 +90,58 @@ const WrappedRoute: React.FC<IWrappedRoute> = ({
|
|||
if (!account) {
|
||||
return loginRedirect();
|
||||
} else {
|
||||
return renderForbidden();
|
||||
return <FallbackForbidden />;
|
||||
}
|
||||
}
|
||||
|
||||
return <Route {...rest} render={renderComponent} />;
|
||||
};
|
||||
|
||||
interface IFallbackLayout {
|
||||
children: JSX.Element;
|
||||
}
|
||||
|
||||
const FallbackLayout: React.FC<IFallbackLayout> = ({ children }) => (
|
||||
<>
|
||||
<Layout.Main>
|
||||
{children}
|
||||
</Layout.Main>
|
||||
|
||||
<Layout.Aside />
|
||||
</>
|
||||
);
|
||||
|
||||
const FallbackLoading: React.FC = () => (
|
||||
<FallbackLayout>
|
||||
<ColumnLoading />
|
||||
</FallbackLayout>
|
||||
);
|
||||
|
||||
const FallbackForbidden: React.FC = () => (
|
||||
<FallbackLayout>
|
||||
<ColumnForbidden />
|
||||
</FallbackLayout>
|
||||
);
|
||||
|
||||
const FallbackError: React.FC<FallbackProps> = ({ error, resetErrorBoundary }) => {
|
||||
const location = useLocation();
|
||||
const firstUpdate = useRef(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (firstUpdate.current) {
|
||||
firstUpdate.current = false;
|
||||
} else {
|
||||
resetErrorBoundary();
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
return (
|
||||
<FallbackLayout>
|
||||
<ErrorColumn error={error} onRetry={resetErrorBoundary} />
|
||||
</FallbackLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export {
|
||||
WrappedRoute,
|
||||
};
|
||||
|
|
|
@ -7,19 +7,19 @@ import { ScrollContext } from 'react-router-scroll-4';
|
|||
|
||||
import * as BuildConfig from 'soapbox/build-config';
|
||||
import LoadingScreen from 'soapbox/components/loading-screen';
|
||||
import SiteErrorBoundary from 'soapbox/components/site-error-boundary';
|
||||
import {
|
||||
ModalContainer,
|
||||
OnboardingWizard,
|
||||
} from 'soapbox/features/ui/util/async-components';
|
||||
import {
|
||||
useAppSelector,
|
||||
useLoggedIn,
|
||||
useOwnAccount,
|
||||
useSoapboxConfig,
|
||||
} from 'soapbox/hooks';
|
||||
import { useCachedLocationHandler } from 'soapbox/utils/redirect';
|
||||
|
||||
import ErrorBoundary from '../components/error-boundary';
|
||||
|
||||
const GdprBanner = React.lazy(() => import('soapbox/components/gdpr-banner'));
|
||||
const EmbeddedStatus = React.lazy(() => import('soapbox/features/embedded-status'));
|
||||
const UI = React.lazy(() => import('soapbox/features/ui'));
|
||||
|
@ -28,52 +28,29 @@ const UI = React.lazy(() => import('soapbox/features/ui'));
|
|||
const SoapboxMount = () => {
|
||||
useCachedLocationHandler();
|
||||
|
||||
const me = useAppSelector(state => state.me);
|
||||
const { isLoggedIn } = useLoggedIn();
|
||||
const { account } = useOwnAccount();
|
||||
const soapboxConfig = useSoapboxConfig();
|
||||
|
||||
const needsOnboarding = useAppSelector(state => state.onboarding.needsOnboarding);
|
||||
const showOnboarding = account && needsOnboarding;
|
||||
const { redirectRootNoLogin } = soapboxConfig;
|
||||
const { redirectRootNoLogin, gdpr } = soapboxConfig;
|
||||
|
||||
// @ts-ignore: I don't actually know what these should be, lol
|
||||
const shouldUpdateScroll = (prevRouterProps, { location }) => {
|
||||
return !(location.state?.soapboxModalKey && location.state?.soapboxModalKey !== prevRouterProps?.location?.state?.soapboxModalKey);
|
||||
};
|
||||
|
||||
/** Render the onboarding flow. */
|
||||
const renderOnboarding = () => (
|
||||
<Suspense fallback={<LoadingScreen />}>
|
||||
<OnboardingWizard />
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
/** Render the auth layout or UI. */
|
||||
const renderSwitch = () => (
|
||||
<Switch>
|
||||
{(!me && redirectRootNoLogin) && (
|
||||
<Redirect exact from='/' to={redirectRootNoLogin} />
|
||||
)}
|
||||
|
||||
<Route path='/' component={UI} />
|
||||
</Switch>
|
||||
);
|
||||
|
||||
/** Render the onboarding flow or UI. */
|
||||
const renderBody = () => {
|
||||
if (showOnboarding) {
|
||||
return renderOnboarding();
|
||||
} else {
|
||||
return renderSwitch();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<SiteErrorBoundary>
|
||||
<BrowserRouter basename={BuildConfig.FE_SUBDIRECTORY}>
|
||||
<CompatRouter>
|
||||
<ScrollContext shouldUpdateScroll={shouldUpdateScroll}>
|
||||
<Switch>
|
||||
{(!isLoggedIn && redirectRootNoLogin) && (
|
||||
<Redirect exact from='/' to={redirectRootNoLogin} />
|
||||
)}
|
||||
|
||||
<Route
|
||||
path='/embed/:statusId'
|
||||
render={(props) => (
|
||||
|
@ -82,18 +59,26 @@ const SoapboxMount = () => {
|
|||
</Suspense>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Redirect from='/@:username/:statusId/embed' to='/embed/:statusId' />
|
||||
|
||||
<Route>
|
||||
{renderBody()}
|
||||
<Suspense fallback={<LoadingScreen />}>
|
||||
{showOnboarding
|
||||
? <OnboardingWizard />
|
||||
: <UI />
|
||||
}
|
||||
</Suspense>
|
||||
|
||||
<Suspense>
|
||||
<ModalContainer />
|
||||
</Suspense>
|
||||
|
||||
{(gdpr && !isLoggedIn) && (
|
||||
<Suspense>
|
||||
<GdprBanner />
|
||||
</Suspense>
|
||||
)}
|
||||
|
||||
<div id='toaster'>
|
||||
<Toaster
|
||||
|
@ -107,7 +92,7 @@ const SoapboxMount = () => {
|
|||
</ScrollContext>
|
||||
</CompatRouter>
|
||||
</BrowserRouter>
|
||||
</ErrorBoundary>
|
||||
</SiteErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"account.birthday": "ولد في {date}",
|
||||
"account.birthday_today": "اليوم يوم ميلاد صاحب الحساب!",
|
||||
"account.block": "حظر @{name}",
|
||||
"account.block_domain": "إخفاء كل ما يتعلق بالنطاق {domain}",
|
||||
"account.block_domain": "إخفاء النطاق {domain}",
|
||||
"account.blocked": "محظور",
|
||||
"account.chat": "دردشة مع @{name}",
|
||||
"account.copy": "نسخ رابط الحساب",
|
||||
|
@ -164,6 +164,8 @@
|
|||
"alert.unexpected.links.support": "الدعم",
|
||||
"alert.unexpected.message": "حدث خطأ ما.",
|
||||
"alert.unexpected.return_home": "العودة للصفحة الرئيسة",
|
||||
"alert.unexpected.submit_feedback": "إرسال الملاحظات",
|
||||
"alert.unexpected.thanks": "شكرا لملاحظاتك!",
|
||||
"aliases.account.add": "إنشاء اسم مستعار",
|
||||
"aliases.account_label": "الحساب القديم:",
|
||||
"aliases.aliases_list_delete": "إلغاء ربط الاسم المستعار",
|
||||
|
@ -180,7 +182,7 @@
|
|||
"app_create.results.explanation_title": "أُنشئ التطبيق بنجاح",
|
||||
"app_create.results.token_label": "رمز OAuth",
|
||||
"app_create.scopes_label": "آفاق",
|
||||
"app_create.scopes_placeholder": "مثلاً: (قراءة كتابة متابعة)",
|
||||
"app_create.scopes_placeholder": "مثلاً: 'read write follow'",
|
||||
"app_create.submit": "إنشاء تطبيق",
|
||||
"app_create.website_label": "الموقع",
|
||||
"auth.awaiting_approval": "حسابك ينتظر الموافقة",
|
||||
|
@ -196,6 +198,9 @@
|
|||
"birthdays_modal.empty": "ليس لأصدقائك يوم ميلاد اليوم.",
|
||||
"boost_modal.combo": "يمكنك الضغط على {combo} لتخطي هذا في المرة القادمة",
|
||||
"boost_modal.title": "إعادة نشر؟",
|
||||
"bundle_column_error.body": "حدث خطأ ما أثناء تحميل هذه الصفحة.",
|
||||
"bundle_column_error.retry": "حاول مجددًا",
|
||||
"bundle_column_error.title": "خطأ في الشبكة",
|
||||
"card.back.label": "العودة",
|
||||
"chat.actions.send": "إرسال",
|
||||
"chat.failed_to_send": "فشل ارسال الرسالة.",
|
||||
|
@ -376,7 +381,7 @@
|
|||
"column_forbidden.body": "ليست لديك الصلاحيات للدخول إلى هذه الصفحة.",
|
||||
"column_forbidden.title": "محظور",
|
||||
"common.cancel": "إلغاء",
|
||||
"compare_history_modal.header": "تعديل السِّجل",
|
||||
"compare_history_modal.header": "سِجلّ التعديلات",
|
||||
"compose.character_counter.title": "مُستخدم {chars} حرف من أصل {maxChars} {maxChars, plural, one {حروف} other {حروف}}",
|
||||
"compose.edit_success": "تم تعديل المنشور",
|
||||
"compose.invalid_schedule": "يجب عليك جدولة منشور بمدة لا تقل عن 5 دقائق.",
|
||||
|
@ -389,7 +394,7 @@
|
|||
"compose_event.fields.description_label": "وصف الحدث",
|
||||
"compose_event.fields.description_placeholder": "الوصف",
|
||||
"compose_event.fields.end_time_label": "الحدث والتاريخ",
|
||||
"compose_event.fields.end_time_placeholder": "الحدث ينتهي في…",
|
||||
"compose_event.fields.end_time_placeholder": "ينتهي الحدث في…",
|
||||
"compose_event.fields.has_end_time": "الحدث له تاريخ إنتهاء",
|
||||
"compose_event.fields.location_label": "موقع الحدث",
|
||||
"compose_event.fields.name_label": "عنوان الحدث",
|
||||
|
@ -397,10 +402,10 @@
|
|||
"compose_event.fields.start_time_label": "تاريخ بداية الحدث",
|
||||
"compose_event.fields.start_time_placeholder": "الحدث يبدأ في…",
|
||||
"compose_event.participation_requests.authorize": "تفويض",
|
||||
"compose_event.participation_requests.authorize_success": "تم قبول المستخدم",
|
||||
"compose_event.participation_requests.authorize_success": "قُبِل المستخدم",
|
||||
"compose_event.participation_requests.reject": "رفض",
|
||||
"compose_event.participation_requests.reject_success": "تم رفض المستخدم",
|
||||
"compose_event.reset_location": "حذف الموقع",
|
||||
"compose_event.participation_requests.reject_success": "رُفِض المستخدم",
|
||||
"compose_event.reset_location": "إعادة تعيين الموقع",
|
||||
"compose_event.submit_success": "تم إنشاء الحدث",
|
||||
"compose_event.tabs.edit": "تعديل التفاصيل",
|
||||
"compose_event.tabs.pending": "إدارة الطلبات",
|
||||
|
@ -494,10 +499,10 @@
|
|||
"confirmations.kick_from_group.confirm": "طرد",
|
||||
"confirmations.kick_from_group.message": "هل أنت متأكد أنك تريد طرد @ {name} من هذه المجموعة؟",
|
||||
"confirmations.leave_event.confirm": "الخروج من الحدث",
|
||||
"confirmations.leave_event.message": "إذا كنت تريد إعادة الانضمام إلى الحدث ، فستتم مراجعة الطلب يدويًا مرة أخرى. هل انت متأكد انك تريد المتابعة؟",
|
||||
"confirmations.leave_group.confirm": "ترك",
|
||||
"confirmations.leave_event.message": "إذا كنت تريد إعادة الانضمام إلى الحدث ، سيتم مراجعة الطلب يدويًا مرة أخرى. متأكد أنك تريد المتابعة؟",
|
||||
"confirmations.leave_group.confirm": "مغادرة",
|
||||
"confirmations.leave_group.heading": "مغادرة المجموعة",
|
||||
"confirmations.leave_group.message": "أنت على وشك مغادرة المجموعة هل تريد الاستمرار؟?",
|
||||
"confirmations.leave_group.message": "أنت على وشك مغادرة المجموعة. هل تريد الاستمرار؟",
|
||||
"confirmations.mute.confirm": "كتم",
|
||||
"confirmations.mute.heading": "كتم @{name}",
|
||||
"confirmations.mute.message": "هل تود حقًا كتم {name}؟",
|
||||
|
@ -523,11 +528,11 @@
|
|||
"confirmations.scheduled_status_delete.message": "هل تود حقا حذف هذا المنشور المجدول؟",
|
||||
"confirmations.unfollow.confirm": "إلغاء المتابعة",
|
||||
"copy.success": "نسخ إلى الحافظة!",
|
||||
"crypto_donate.explanation_box.message": "{siteTitle} يقبل العملات الرقمية . بإمكانك التبرع عبر أي من هذه العناوين في الأسفل . شكرا لدعمك!",
|
||||
"crypto_donate.explanation_box.title": "يتم إرسال العملات الرقمية",
|
||||
"crypto_donate.explanation_box.message": "يمكنك أن تدعم منصة {siteTitle} من خلال التبرع بالعملات الرقمية على العناوين الظاهرة في الأسفل. شكراً جزيلاً لك على الدعم!",
|
||||
"crypto_donate.explanation_box.title": "التبرع بالعملات الرقمية",
|
||||
"crypto_donate_panel.actions.view": "اضغط لعرض {count, plural, one {# محفظة} other {# محفظة}}",
|
||||
"crypto_donate_panel.heading": "تبرّع بالعملات الرقمية",
|
||||
"crypto_donate_panel.intro.message": "يقبل {siteTitle} العملات الرقمية لدعم تواجه . شكراً لدعمك!",
|
||||
"crypto_donate_panel.intro.message": "منصّة {siteTitle} تقبل تبرعاتكم بالعملات الرقمية لدعم تواجدها . شكراً جزيلاً لدعمكم!",
|
||||
"datepicker.day": "يوم",
|
||||
"datepicker.hint": "مُجدول للنشر في…",
|
||||
"datepicker.month": "شهر",
|
||||
|
@ -615,7 +620,7 @@
|
|||
"emoji_button.recent": "المُستخدمة حديثا",
|
||||
"emoji_button.search": "البحث…",
|
||||
"emoji_button.search_results": "نتائج البحث",
|
||||
"emoji_button.skins_1": "الإفتراضي",
|
||||
"emoji_button.skins_1": "الافتراضي",
|
||||
"emoji_button.skins_2": "فاتح",
|
||||
"emoji_button.skins_3": "ضوء المتوسط",
|
||||
"emoji_button.skins_4": "متوسط",
|
||||
|
@ -635,7 +640,7 @@
|
|||
"empty_column.bookmarks": "ليس لديك أي علامات ، ستظهر هنا عند اضافتها.",
|
||||
"empty_column.community": "لا توجد منشورات في الخط المحلي بعد. أكتب شيئا ما للعامة كبداية!",
|
||||
"empty_column.direct": "لم تتلقَ أي رسالة خاصة مباشرة بعد. ستعرض الرسائل المباشرة هنا في حال أرسلت أو تلقيت بعضها.",
|
||||
"empty_column.dislikes": "لا أحد قام بعدم إعجاب هذا المنشور حتى الآن. عندما يفعل شخص ما ، سيظهرون هنا.",
|
||||
"empty_column.dislikes": "لم يتفاعل أي شخص بعدم الإعجاب على هذا المنشور بعد. عندما يفعل شخص ما ، سيظهرون هنا.",
|
||||
"empty_column.domain_blocks": "ليس هناك نطاقات مخفية بعد.",
|
||||
"empty_column.event_participant_requests": "لا توجد طلبات معلقة للمشاركة في الحدث.",
|
||||
"empty_column.event_participants": "لم ينضم أحد إلى هذا الحدث حتى الآن. عندما يفعل شخص ما ، سوف يظهر هنا.",
|
||||
|
@ -684,7 +689,7 @@
|
|||
"event.quote": "اقتباس الحدث",
|
||||
"event.reblog": "إعادة نشر الحدث",
|
||||
"event.show_on_map": "العرض على الخريطة",
|
||||
"event.unreblog": "حدث لم يُعَدْ نشره",
|
||||
"event.unreblog": "إلغاء مشاركة الحدث",
|
||||
"event.website": "روابط خارجية",
|
||||
"event_map.navigate": "التنقل",
|
||||
"events.create_event": "إنشاء حدث",
|
||||
|
@ -732,7 +737,7 @@
|
|||
"filters.filters_list_warn": "ترشيح العرض",
|
||||
"filters.removed": "حُذف المُرشِّح.",
|
||||
"followRecommendations.heading": "الحسابات المقترحة",
|
||||
"follow_request.authorize": "ترخيص بالوصول",
|
||||
"follow_request.authorize": "السماح بالمتابعة",
|
||||
"follow_request.reject": "رفض",
|
||||
"gdpr.accept": "الموافقة",
|
||||
"gdpr.learn_more": "معرفة المزيد",
|
||||
|
@ -1401,7 +1406,7 @@
|
|||
"status.group_mod_delete": "حذف المشاركة من المجموعة",
|
||||
"status.interactions.dislikes": "{count, plural, one {عدم اعجاب} other {عدم اعجاب}}",
|
||||
"status.interactions.favourites": "{count, plural, one {إعجاب واحد} other {إعجاب}}",
|
||||
"status.interactions.quotes": "{count, plural, one {# صوت} other {# أصوات}}",
|
||||
"status.interactions.quotes": "{count, plural, one {صوت} other {أصوات}}",
|
||||
"status.interactions.reblogs": "{count, plural, one {مشاركة} other {مشاركات}}",
|
||||
"status.load_more": "تحميل المزيد",
|
||||
"status.mention": "ذِكر @{name}",
|
||||
|
|
|
@ -164,6 +164,8 @@
|
|||
"alert.unexpected.links.support": "Support",
|
||||
"alert.unexpected.message": "Something went wrong.",
|
||||
"alert.unexpected.return_home": "Return Home",
|
||||
"alert.unexpected.submit_feedback": "Submit Feedback",
|
||||
"alert.unexpected.thanks": "Thanks for your feedback!",
|
||||
"aliases.account.add": "Create alias",
|
||||
"aliases.account_label": "Old account:",
|
||||
"aliases.aliases_list_delete": "Unlink alias",
|
||||
|
@ -196,6 +198,9 @@
|
|||
"birthdays_modal.empty": "None of your friends have birthday today.",
|
||||
"boost_modal.combo": "You can press {combo} to skip this next time",
|
||||
"boost_modal.title": "Repost?",
|
||||
"bundle_column_error.body": "Something went wrong while loading this page.",
|
||||
"bundle_column_error.retry": "Try again",
|
||||
"bundle_column_error.title": "Network error",
|
||||
"card.back.label": "Back",
|
||||
"chat.actions.send": "Send",
|
||||
"chat.failed_to_send": "Message failed to send.",
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
"account.follows_you": "במעקב אחריך",
|
||||
"account.header.alt": "Profile header",
|
||||
"account.hide_reblogs": "להסתיר הידהודים מאת @{name}",
|
||||
"account.last_status": "פעיל לאחרונה",
|
||||
"account.last_status": "פעיל הלפנה",
|
||||
"account.link_verified_on": "בעלות על הקישור הזה נבדקה לאחרונה ב{date}",
|
||||
"account.locked_info": "החשבון הוגדר כנעול. בעל החשבון בודק ידנית מי יכול לעקוב אחריו.",
|
||||
"account.login": "התחברות",
|
||||
|
@ -197,7 +197,7 @@
|
|||
"boost_modal.combo": "ניתן להקיש {combo} כדי לדלג בפעם הבאה",
|
||||
"boost_modal.title": "Repost?",
|
||||
"card.back.label": "Back",
|
||||
"chat.actions.send": "שליחה",
|
||||
"chat.actions.send": "שלח",
|
||||
"chat.failed_to_send": "שליחת ההודעה נכשלה.",
|
||||
"chat.input.placeholder": "הקלד הודעה",
|
||||
"chat.new_message.title": "הודעה חדשה",
|
||||
|
@ -213,15 +213,18 @@
|
|||
"chat_composer.unblock": "הסרת חסימה",
|
||||
"chat_list_item.blocked_you": "משתמש זה חסם אותך",
|
||||
"chat_list_item.blocking": "אתה חסמת את המשתמש זה",
|
||||
"chat_message_list.blocked": "אתה חסמת את המשתמש זה",
|
||||
"chat_message_list.blocked": "משתמש זה נחסם על ידיך",
|
||||
"chat_message_list.blockedBy": "אתה חסום על ידי",
|
||||
"chat_message_list.network_failure.action": "לנסות שוב",
|
||||
"chat_message_list.network_failure.subtitle": "נתקלנו בכשל ברשת.",
|
||||
"chat_message_list.network_failure.title": "אופס!",
|
||||
"chat_message_list_intro.actions.leave_chat": "עזוב את השיחה",
|
||||
"chat_message_list_intro.actions.message_lifespan": "הודעות ישנות יותר מ {day, plural, one {# יום} other {# ימים}} נמחקות.",
|
||||
"chat_message_list_intro.actions.report": "דווח",
|
||||
"chat_message_list_intro.leave_chat.confirm": "עזוב את השיחה",
|
||||
"chat_message_list_intro.leave_chat.heading": "עזוב את השיחה",
|
||||
"chat_message_list_intro.intro": "רוצה להתחיל לשוחח איתך",
|
||||
"chat_message_list_intro.leave_chat.confirm": "צא מהשיחה",
|
||||
"chat_message_list_intro.leave_chat.heading": "צא מהשיחה",
|
||||
"chat_message_list_intro.leave_chat.message": "אתה בטוח שאתה רוצה לעזוב את הצ'אט הזה? הודעות יימחקו עבורך והצ'אט הזה יוסר מרשימת הצ'אט שלך.",
|
||||
"chat_pane.blankslate.action": "הודעה למישהו",
|
||||
"chat_pane.blankslate.body": "חפשו מישהו לשוחח איתו.",
|
||||
"chat_pane.blankslate.title": "עדיין אין הודעות",
|
||||
|
@ -239,17 +242,22 @@
|
|||
"chat_settings.auto_delete.days": "{day, plural, one {# יום} other {# ימים}}",
|
||||
"chat_settings.block.confirm": "חסימה",
|
||||
"chat_settings.block.heading": "חסימת @{acct}",
|
||||
"chat_settings.leave.confirm": "עזוב את השיחה",
|
||||
"chat_settings.leave.heading": "עזוב את השיחה",
|
||||
"chat_settings.leave.confirm": "צא מהשיחה",
|
||||
"chat_settings.leave.heading": "צא מהשיחה",
|
||||
"chat_settings.options.block_user": "חסימת @{acct}",
|
||||
"chat_settings.options.leave_chat": "עזוב את השיחה",
|
||||
"chat_settings.options.leave_chat": "צא מהשיחה",
|
||||
"chat_settings.options.report_user": "דיווח על @{acct}",
|
||||
"chat_settings.options.unblock_user": "הסרת חסימה מעל @{acct}",
|
||||
"chat_settings.title": "פרטים הצ'אט",
|
||||
"chat_settings.unblock.confirm": "הסרת חסימה",
|
||||
"chat_settings.unblock.heading": "הסרת חסימה מעל @{acct}",
|
||||
"chat_window.auto_delete_tooltip": "הודעות צ'אט מוגדרות למחיקה אוטומטית לאחר {day, plural, one {# יום} other {# ימים}} לאחר שליחה.",
|
||||
"chats.actions.delete": "מחק לכולם",
|
||||
"chats.actions.deleteForMe": "למחוק עבורי",
|
||||
"chats.actions.more": "עוד",
|
||||
"chats.actions.report": "דווח",
|
||||
"chats.dividers.today": "היום",
|
||||
"chats.main.blankslate.title": "עדיין אין הודעות",
|
||||
"chats.search_placeholder": "התחל שיחה עם…",
|
||||
"colum.filters.expiration.1800": "30 דקות",
|
||||
"colum.filters.expiration.21600": "6 שעות",
|
||||
|
@ -284,6 +292,7 @@
|
|||
"column.developers.service_worker": "Service Worker",
|
||||
"column.direct": "הודעות ישירות",
|
||||
"column.directory": "דפדף בין פרופילים",
|
||||
"column.dislikes": "לא אהבתי",
|
||||
"column.domain_blocks": "דומיינים מוסתרים",
|
||||
"column.edit_profile": "ערוך פרופיל",
|
||||
"column.export_data": "יצא נתונים",
|
||||
|
@ -604,9 +613,19 @@
|
|||
"empty_column.search.hashtags": "אין תוצאות האשטאג עבור \"{term}\"",
|
||||
"empty_column.search.statuses": "אין תוצאות פוסטים עבור \"{term}\"",
|
||||
"empty_column.test": "The test timeline is empty.",
|
||||
"event.discussion.empty": "אף אחד עדיין לא הגיב על האירוע הזה. כשמישהו יגיב, התגובה תופיע כאן.",
|
||||
"event.export_ics": "ייצוא לוח השנה שלך",
|
||||
"event.external": "צפו באירוע על {Domain}",
|
||||
"event.join_state.accept": "הולך",
|
||||
"event.join_state.empty": "השתתפות",
|
||||
"event.join_state.pending": "בהמתנה",
|
||||
"event.join_state.rejected": "הולך",
|
||||
"event.location": "מיקום",
|
||||
"event.manage": "ניהול",
|
||||
"event.organized_by": "מאורגן על ידי {name}",
|
||||
"event.reblog": "פרסום אירוע מחדש",
|
||||
"event.unreblog": "בטל פרסום מחדש של האירוע",
|
||||
"event.website": "קישורים חיצוניים",
|
||||
"export_data.actions.export": "ייצא נתונים",
|
||||
"export_data.actions.export_blocks": "ייצוא רשימת חסימות",
|
||||
"export_data.actions.export_follows": "ייצא מעקבים",
|
||||
|
@ -714,6 +733,7 @@
|
|||
"group.update.success": "הקבוצה נשמרה בהצלחה",
|
||||
"group.upload_banner": "העלה תמונה",
|
||||
"group.upload_banner.title": "העלה תמונת רקע",
|
||||
"groups.discover.popular.show_more": "להציג עוד",
|
||||
"groups.discover.popular.title": "קבוצות פופולריות",
|
||||
"groups.discover.search.error.subtitle": "נא לנסות שוב מאוחר יותר.",
|
||||
"groups.discover.search.error.title": "התרחשה שגיאה",
|
||||
|
@ -725,6 +745,9 @@
|
|||
"groups.discover.search.recent_searches.clear_all": "נקה הכל",
|
||||
"groups.discover.search.recent_searches.title": "חיפושים אחרונים",
|
||||
"groups.discover.search.results.groups": "קבוצות",
|
||||
"groups.discover.suggested.show_more": "להציג עוד",
|
||||
"groups.discover.suggested.title": "הצעות בשבילך",
|
||||
"groups.discover.tags.show_more": "להציג עוד",
|
||||
"header.login.label": "התחברות",
|
||||
"header.register.label": "Register",
|
||||
"home.column_settings.show_reblogs": "הצגת הדהודים",
|
||||
|
@ -879,6 +902,7 @@
|
|||
"navigation_bar.favourites": "חיבובים",
|
||||
"navigation_bar.filters": "מילים מושתקות",
|
||||
"navigation_bar.follow_requests": "בקשות מעקב",
|
||||
"navigation_bar.followed_tags": "האשטגים עקבתי אחריהם",
|
||||
"navigation_bar.import_data": "יבא נתונים",
|
||||
"navigation_bar.in_reply_to": "בתשובה ל",
|
||||
"navigation_bar.invites": "הזמנות",
|
||||
|
@ -887,6 +911,12 @@
|
|||
"navigation_bar.preferences": "העדפות",
|
||||
"navigation_bar.profile_directory": "ספריית פרופילים",
|
||||
"navigation_bar.soapbox_config": "תצורת סבוניה",
|
||||
"new_event_panel.action": "צור אירוע",
|
||||
"new_event_panel.subtitle": "לא מוצא משהו בשבילך? תיצר אירוע משלך.",
|
||||
"new_event_panel.title": "צור אירוע חדש",
|
||||
"new_group_panel.action": "צור קבוצה",
|
||||
"new_group_panel.subtitle": "לא מוצא משהו בשבילך? תקים קבוצה פרטית או ציבורית משלך.",
|
||||
"new_group_panel.title": "הקמת קבוצה חדשה",
|
||||
"notification.favourite": "הפוסט שלך חובב על ידי {name}",
|
||||
"notification.follow": "{name} במעקב אחרייך",
|
||||
"notification.follow_request": "{name} ביקש לעקוב אחריך",
|
||||
|
|
1884
src/locales/id.json
1884
src/locales/id.json
File diff suppressed because it is too large
Load Diff
|
@ -10,6 +10,7 @@
|
|||
"account.block_domain": "{domain}全体を非表示",
|
||||
"account.blocked": "ブロック済み",
|
||||
"account.chat": "@{name}さんとチャット",
|
||||
"account.copy": "プロフィールへのリンクをコピー",
|
||||
"account.deactivated": "非アクティブ化",
|
||||
"account.direct": "@{name}さんにダイレクトメッセージ",
|
||||
"account.domain_blocked": "ドメイン非表示",
|
||||
|
@ -82,6 +83,11 @@
|
|||
"account_search.placeholder": "アカウントを検索",
|
||||
"actualStatus.edited": "{date}に編集済",
|
||||
"actualStatuses.quote_tombstone": "Post is unavailable.",
|
||||
"admin.announcements.action": "アナウンスを作成",
|
||||
"admin.announcements.delete": "削除",
|
||||
"admin.announcements.edit": "編集",
|
||||
"admin.announcements.ends_at": "終了日時:",
|
||||
"admin.announcements.starts_at": "開始日時:",
|
||||
"admin.awaiting_approval.empty_message": "There is nobody waiting for approval. When a new user signs up, you can review them here.",
|
||||
"admin.dashboard.registration_mode.approval_hint": "Users can sign up, but their account only gets activated when an admin approves it.",
|
||||
"admin.dashboard.registration_mode.approval_label": "Approval Required",
|
||||
|
@ -98,6 +104,12 @@
|
|||
"admin.dashcounters.user_count_label": "total users",
|
||||
"admin.dashwidgets.email_list_header": "Email list",
|
||||
"admin.dashwidgets.software_header": "Software",
|
||||
"admin.edit_announcement.created": "アナウンスが作成されました",
|
||||
"admin.edit_announcement.deleted": "アナウンスを削除しました",
|
||||
"admin.edit_announcement.fields.all_day_label": "終日",
|
||||
"admin.edit_announcement.fields.content_label": "内容",
|
||||
"admin.edit_announcement.fields.content_placeholder": "アナウンスの内容",
|
||||
"admin.edit_announcement.fields.end_time_label": "終了日",
|
||||
"admin.latest_accounts_panel.more": "クリックして {count} 人のおすすめユーザーを表示",
|
||||
"admin.latest_accounts_panel.title": "Latest Accounts",
|
||||
"admin.moderation_log.empty_message": "You have not performed any moderation actions yet. When you do, a history will be shown here.",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -84,7 +84,7 @@
|
|||
"account_note.placeholder": "Nie wprowadzono opisu",
|
||||
"account_search.placeholder": "Szukaj konta",
|
||||
"actualStatus.edited": "Edytowano {date}",
|
||||
"actualStatuses.quote_tombstone": "Wpis jest niedostępny",
|
||||
"actualStatuses.quote_tombstone": "Wpis jest niedostępny.",
|
||||
"admin.announcements.action": "Utwórz ogłoszenie",
|
||||
"admin.announcements.all_day": "Cały dzień",
|
||||
"admin.announcements.delete": "Usuń",
|
||||
|
@ -164,6 +164,8 @@
|
|||
"alert.unexpected.links.support": "Wsparcie techniczne",
|
||||
"alert.unexpected.message": "Wystąpił nieoczekiwany błąd.",
|
||||
"alert.unexpected.return_home": "Wróć na stronę główną",
|
||||
"alert.unexpected.submit_feedback": "Prześlij opinię",
|
||||
"alert.unexpected.thanks": "Dziękujemy za twoją opinię!",
|
||||
"aliases.account.add": "Utwórz alias",
|
||||
"aliases.account_label": "Stare konto:",
|
||||
"aliases.aliases_list_delete": "Odłącz alias",
|
||||
|
@ -196,6 +198,9 @@
|
|||
"birthdays_modal.empty": "Żaden z Twoich znajomych nie ma dziś urodzin.",
|
||||
"boost_modal.combo": "Naciśnij {combo}, aby pominąć to następnym razem",
|
||||
"boost_modal.title": "Repost?",
|
||||
"bundle_column_error.body": "Coś poszło nie tak podczas ładowania tej strony.",
|
||||
"bundle_column_error.retry": "Spróbuj ponownie",
|
||||
"bundle_column_error.title": "Błąd sieci",
|
||||
"card.back.label": "Wstecz",
|
||||
"chat.actions.send": "Wyślij",
|
||||
"chat.failed_to_send": "Nie udało się wysłać wiadomości.",
|
||||
|
@ -229,6 +234,9 @@
|
|||
"chat_message_list_intro.leave_chat.confirm": "Opuść czat",
|
||||
"chat_message_list_intro.leave_chat.heading": "Opuść czat",
|
||||
"chat_message_list_intro.leave_chat.message": "Czy na pewno chcesz opuścić ten czat? Wiadomości zostaną dla Ciebie usunięte, a czat zniknie z Twojej skrzynki.",
|
||||
"chat_pane.blankslate.action": "Napisz do kogoś",
|
||||
"chat_pane.blankslate.body": "Poszukaj kogoś do rozpoczęcia rozmowy.",
|
||||
"chat_pane.blankslate.title": "Brak wiadomości",
|
||||
"chat_search.blankslate.body": "Szukaj kogoś do rozpoczęcia rozmowy.",
|
||||
"chat_search.blankslate.title": "Rozpocznij rozmowę",
|
||||
"chat_search.empty_results_blankslate.body": "Spróbuj znaleźć inną nazwę.",
|
||||
|
@ -260,10 +268,10 @@
|
|||
"chat_window.auto_delete_label": "Usuwaj automatycznie po {day, plural, one {# dniu} other {# dniach}}",
|
||||
"chat_window.auto_delete_tooltip": "Wiadomości będą usuwane po {day, plural, one {# dniu} other {# dniach}} od wysłania.",
|
||||
"chats.actions.copy": "Kopiuj",
|
||||
"chats.actions.delete": "Usuń wiadomość",
|
||||
"chats.actions.delete": "Usuń dla wszystkich",
|
||||
"chats.actions.deleteForMe": "Usuń dla mnie",
|
||||
"chats.actions.more": "Więcej",
|
||||
"chats.actions.report": "Zgłoś użytkownika",
|
||||
"chats.actions.report": "Zgłoś",
|
||||
"chats.dividers.today": "Dzisiaj",
|
||||
"chats.main.blankslate.new_chat": "Napisz do kogoś",
|
||||
"chats.main.blankslate.subtitle": "Szukaj kogoś do rozpoczęcia rozmowy",
|
||||
|
@ -305,6 +313,7 @@
|
|||
"column.developers.service_worker": "Service Worker",
|
||||
"column.direct": "Wiadomości bezpośrednie",
|
||||
"column.directory": "Przeglądaj profile",
|
||||
"column.dislikes": "Nie lubi",
|
||||
"column.domain_blocks": "Ukryte domeny",
|
||||
"column.edit_profile": "Edytuj profil",
|
||||
"column.event_map": "Lokalizacja wydarzenia",
|
||||
|
@ -324,7 +333,7 @@
|
|||
"column.filters.delete_error": "Błąd usuwania filtru",
|
||||
"column.filters.drop_header": "Usuwaj zamiast ukrywać",
|
||||
"column.filters.drop_hint": "Filtrowane wpisy znikną bezpowrotnie, nawet jeżeli filtr zostanie później usunięty",
|
||||
"column.filters.edit": "Edytuj",
|
||||
"column.filters.edit": "Edytuj filtr",
|
||||
"column.filters.expires": "Wygasaj po",
|
||||
"column.filters.hide_header": "Całkowicie ukryj",
|
||||
"column.filters.hide_hint": "Całkowicie ukrywaj filtrowaną zawartość, zamiast wyświetlać ostrzeżenie",
|
||||
|
@ -359,10 +368,11 @@
|
|||
"column.notifications": "Powiadomienia",
|
||||
"column.pins": "Przypięte wpisy",
|
||||
"column.preferences": "Preferencje",
|
||||
"column.public": "Globalna oś czasu",
|
||||
"column.public": "Sfederowana oś czasu",
|
||||
"column.quotes": "Cytatu wpisu",
|
||||
"column.reactions": "Reakcje",
|
||||
"column.reblogs": "Podbicia",
|
||||
"column.registration": "Zarejestruj się",
|
||||
"column.scheduled_statuses": "Zaplanowane wpisy",
|
||||
"column.search": "Szukaj",
|
||||
"column.settings_store": "Settings store",
|
||||
|
@ -589,7 +599,7 @@
|
|||
"edit_profile.hints.discoverable": "Wyświetlaj konto w katalogu profilów i pozwalaj na indeksowanie przez zewnętrzne usługi",
|
||||
"edit_profile.hints.hide_network": "To, kogo obserwujesz i kto Cię obserwuje nie będzie wyświetlane na Twoim profilu",
|
||||
"edit_profile.hints.locked": "Wymaga ręcznego zatwierdzania obserwacji",
|
||||
"edit_profile.hints.meta_fields": "Możesz ustawić {count, plural, one {# niestandardowe pole wyświetlane} few {# niestandardowe pola wyświetlane} many {# niestandardowych pól wyświetlanych}} na Twoim profilu.",
|
||||
"edit_profile.hints.meta_fields": "Możesz ustawić {count, plural, one {# niestandardowe pole wyświetlane} few {# niestandardowe pola wyświetlane} other {# niestandardowych pól wyświetlanych}} na Twoim profilu.",
|
||||
"edit_profile.hints.stranger_notifications": "Wyświetlaj tylko powiadomienia od osób, które obserwujesz",
|
||||
"edit_profile.save": "Zapisz",
|
||||
"edit_profile.success": "Zapisano profil!",
|
||||
|
@ -1060,7 +1070,7 @@
|
|||
"notification.mentioned": "{name} wspomniał(a) o tobie",
|
||||
"notification.move": "{name} przeniósł(-osła) się na {targetName}",
|
||||
"notification.name": "{link}{others}",
|
||||
"notification.others": " + {count} więcej",
|
||||
"notification.others": "+ {count} więcej",
|
||||
"notification.pleroma:chat_mention": "{name} wysłał(a) Ci wiadomośść",
|
||||
"notification.pleroma:emoji_reaction": "{name} zareagował(a) na Twój wpis",
|
||||
"notification.pleroma:event_reminder": "Wydarzenie w którym bierzesz udział wkrótce się zaczyna",
|
||||
|
@ -1355,13 +1365,15 @@
|
|||
"soapbox_config.promo_panel.meta_fields.icon_placeholder": "Ikona",
|
||||
"soapbox_config.promo_panel.meta_fields.label_placeholder": "Podpis",
|
||||
"soapbox_config.promo_panel.meta_fields.url_placeholder": "Adres URL",
|
||||
"soapbox_config.raw_json_hint": "Edytuj ustawienia bezpośrednio. Zmiany dokonane w pliku JSON zastąpią powyższe ustawienia. Naciśnij Zapisz, aby zastosować zmiany.",
|
||||
"soapbox_config.raw_json_hint": "Edytuj ustawienia bezpośrednio. Zmiany dokonane w pliku JSON zastąpią powyższe ustawienia. Naciśnij „Zapisz”, aby zastosować zmiany.",
|
||||
"soapbox_config.raw_json_invalid": "jest nieprawidłowe",
|
||||
"soapbox_config.raw_json_label": "Zaawansowane: Edytuj surowe dane JSON",
|
||||
"soapbox_config.redirect_root_no_login_hint": "Cel przekierowania, jeśli użytkownik jest niezalogowany.",
|
||||
"soapbox_config.redirect_root_no_login_label": "Przekieruj stronę główną",
|
||||
"soapbox_config.save": "Zapisz",
|
||||
"soapbox_config.saved": "Zapisano konfigurację Soapbox!",
|
||||
"soapbox_config.sentry_dsn_hint": "Adres URL DSN do zgłaszania błędów. Działa z Sentry i GlitchTip.",
|
||||
"soapbox_config.sentry_dsn_label": "DSN Sentry",
|
||||
"soapbox_config.tile_server_attribution_label": "Atrybucja kafelków map",
|
||||
"soapbox_config.tile_server_label": "Serwer kafelków map",
|
||||
"soapbox_config.verified_can_edit_name_label": "Pozwól zweryfikowanym użytkownikom na zmianę swojej nazwy wyświetlanej.",
|
||||
|
@ -1388,7 +1400,7 @@
|
|||
"status.group": "Napisano w {group}",
|
||||
"status.group_mod_delete": "Usuń wpis z grupy",
|
||||
"status.interactions.favourites": "{count, plural, one {Polubienie} few {Polubienia} other {Polubień}}",
|
||||
"status.interactions.quotes": "{count, plural, one {cytat} few {cytaty} many {cytatów}}",
|
||||
"status.interactions.quotes": "{count, plural, one {Cytat} few {Cytaty} other {Cytatów}}",
|
||||
"status.interactions.reblogs": "{count, plural, one {Podanie dalej} few {Podania dalej} other {Podań dalej}}",
|
||||
"status.load_more": "Załaduj więcej",
|
||||
"status.mention": "Wspomnij o @{name}",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue