-
-
-
+
+
-
-
-
+
- {account.verified &&
}
+ {account.verified && (
+
+
+
+ )}
-
- {account.display_name}
-
+
@{displayFqn ? account.fqn : account.acct}
diff --git a/app/soapbox/features/edit-profile/index.tsx b/app/soapbox/features/edit-profile/index.tsx
index 1967e9138..2f77e1142 100644
--- a/app/soapbox/features/edit-profile/index.tsx
+++ b/app/soapbox/features/edit-profile/index.tsx
@@ -15,16 +15,17 @@ import {
FormGroup,
HStack,
Input,
+ Streamfield,
Textarea,
Toggle,
} from 'soapbox/components/ui';
-import Streamfield, { StreamfieldComponent } from 'soapbox/components/ui/streamfield/streamfield';
import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures } from 'soapbox/hooks';
import { normalizeAccount } from 'soapbox/normalizers';
import resizeImage from 'soapbox/utils/resize-image';
import ProfilePreview from './components/profile-preview';
+import type { StreamfieldComponent } from 'soapbox/components/ui/streamfield/streamfield';
import type { Account } from 'soapbox/types/entities';
/**
@@ -198,7 +199,10 @@ const EditProfile: React.FC = () => {
const handleSubmit: React.FormEventHandler = (event) => {
const promises = [];
- promises.push(dispatch(patchMe(data, true)));
+ const params = { ...data };
+ if (params.fields_attributes?.length === 0) params.fields_attributes = [{ name: '', value: '' }];
+
+ promises.push(dispatch(patchMe(params, true)));
if (features.muteStrangers) {
promises.push(
diff --git a/app/soapbox/features/email-confirmation/index.tsx b/app/soapbox/features/email-confirmation/index.tsx
index 0c4939eed..45d18444e 100644
--- a/app/soapbox/features/email-confirmation/index.tsx
+++ b/app/soapbox/features/email-confirmation/index.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { Redirect } from 'react-router-dom';
diff --git a/app/soapbox/features/emoji/__tests__/emoji.test.ts b/app/soapbox/features/emoji/__tests__/emoji.test.ts
index 83b6ef14d..df6798ef7 100644
--- a/app/soapbox/features/emoji/__tests__/emoji.test.ts
+++ b/app/soapbox/features/emoji/__tests__/emoji.test.ts
@@ -88,5 +88,10 @@ describe('emoji', () => {
expect(emojify('💂♀️💂♂️'))
.toEqual('


');
});
+
+ it('keeps ordering as expected (issue fixed by PR 20677)', () => {
+ expect(emojify('
💕 #foo test: foo.
'))
+ .toEqual('
#foo test: foo.
');
+ });
});
});
diff --git a/app/soapbox/features/emoji/emoji.js b/app/soapbox/features/emoji/emoji.js
index 9eadddbc6..e9b4caa35 100644
--- a/app/soapbox/features/emoji/emoji.js
+++ b/app/soapbox/features/emoji/emoji.js
@@ -6,8 +6,6 @@ import unicodeMapping from './emoji-unicode-mapping-light';
const trie = new Trie(Object.keys(unicodeMapping));
-const domParser = new DOMParser();
-
const emojifyTextNode = (node, customEmojis, autoPlayGif = false) => {
let str = node.textContent;
@@ -26,7 +24,7 @@ const emojifyTextNode = (node, customEmojis, autoPlayGif = false) => {
}
}
- let rend, replacement = '';
+ let rend, replacement = null;
if (i === str.length) {
break;
} else if (str[i] === ':') {
@@ -39,7 +37,14 @@ const emojifyTextNode = (node, customEmojis, autoPlayGif = false) => {
// if you want additional emoji handler, add statements below which set replacement and return true.
if (shortname in customEmojis) {
const filename = autoPlayGif ? customEmojis[shortname].url : customEmojis[shortname].static_url;
- replacement = `

`;
+ replacement = document.createElement('img');
+ replacement.setAttribute('draggable', false);
+ replacement.setAttribute('class', 'emojione custom-emoji');
+ replacement.setAttribute('alt', shortname);
+ replacement.setAttribute('title', shortname);
+ replacement.setAttribute('src', filename);
+ replacement.setAttribute('data-original', customEmojis[shortname].url);
+ replacement.setAttribute('data-static', customEmojis[shortname].static_url);
return true;
}
return false;
@@ -47,8 +52,12 @@ const emojifyTextNode = (node, customEmojis, autoPlayGif = false) => {
} else { // matched to unicode emoji
const { filename, shortCode } = unicodeMapping[match];
const title = shortCode ? `:${shortCode}:` : '';
- const src = joinPublicPath(`packs/emoji/${filename}.svg`);
- replacement = `

`;
+ replacement = document.createElement('img');
+ replacement.setAttribute('draggable', false);
+ replacement.setAttribute('class', 'emojione');
+ replacement.setAttribute('alt', match);
+ replacement.setAttribute('title', title);
+ replacement.setAttribute('src', joinPublicPath(`packs/emoji/${filename}.svg`));
rend = i + match.length;
// If the matched character was followed by VS15 (for selecting text presentation), skip it.
if (str.codePointAt(rend) === 65038) {
@@ -58,7 +67,7 @@ const emojifyTextNode = (node, customEmojis, autoPlayGif = false) => {
fragment.append(document.createTextNode(str.slice(0, i)));
if (replacement) {
- fragment.append(domParser.parseFromString(replacement, 'text/html').documentElement.getElementsByTagName('img')[0]);
+ fragment.append(replacement);
}
node.textContent = str.slice(0, i);
str = str.slice(rend);
diff --git a/app/soapbox/features/federation-restrictions/components/instance-restrictions.tsx b/app/soapbox/features/federation-restrictions/components/instance-restrictions.tsx
index ac86039fd..a912f3f4d 100644
--- a/app/soapbox/features/federation-restrictions/components/instance-restrictions.tsx
+++ b/app/soapbox/features/federation-restrictions/components/instance-restrictions.tsx
@@ -4,7 +4,7 @@ import React from 'react';
import { FormattedMessage } from 'react-intl';
import Icon from 'soapbox/components/icon';
-import { Text } from 'soapbox/components/ui';
+import { HStack, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import type { Map as ImmutableMap } from 'immutable';
@@ -16,6 +16,23 @@ const hasRestrictions = (remoteInstance: ImmutableMap
): boolean =>
.reduce((acc: boolean, value: boolean) => acc || value, false);
};
+interface IRestriction {
+ icon: string,
+ children: React.ReactNode,
+}
+
+const Restriction: React.FC = ({ icon, children }) => {
+ return (
+
+
+
+
+ {children}
+
+
+ );
+};
+
interface IInstanceRestrictions {
remoteInstance: ImmutableMap,
}
@@ -40,57 +57,52 @@ const InstanceRestrictions: React.FC = ({ remoteInstance
if (followers_only) {
items.push((
-
-
+
-
+
));
} else if (federated_timeline_removal) {
items.push((
-
-
+
-
+
));
}
if (fullMediaRemoval) {
items.push((
-
-
+
-
+
));
} else if (partialMediaRemoval) {
items.push((
-
-
+
-
+
));
}
if (!fullMediaRemoval && media_nsfw) {
items.push((
-
-
+
-
+
));
}
@@ -105,46 +117,45 @@ const InstanceRestrictions: React.FC = ({ remoteInstance
if (remoteInstance.getIn(['federation', 'reject']) === true) {
return (
-
-
+
-
+
);
} else if (hasRestrictions(remoteInstance)) {
- return [
- (
-
+ return (
+ <>
+
-
- ),
- renderRestrictions(),
- ];
+
+
+ {renderRestrictions()}
+ >
+ );
} else {
return (
-
-
+
-
+
);
}
};
return (
-
+
{renderContent()}
-
+
);
};
diff --git a/app/soapbox/features/feed-suggestions/feed-suggestions.tsx b/app/soapbox/features/feed-suggestions/feed-suggestions.tsx
index 61f7a09af..dc2b334c1 100644
--- a/app/soapbox/features/feed-suggestions/feed-suggestions.tsx
+++ b/app/soapbox/features/feed-suggestions/feed-suggestions.tsx
@@ -35,7 +35,7 @@ const SuggestionItem = ({ accountId }: { accountId: string }) => {
{
-
+
{suggestedProfiles.slice(0, 4).map((suggestedProfile) => (
))}
diff --git a/app/soapbox/features/landing-page/__tests__/landing-page.test.tsx b/app/soapbox/features/landing-page/__tests__/landing-page.test.tsx
index a52dbd975..6e96672ba 100644
--- a/app/soapbox/features/landing-page/__tests__/landing-page.test.tsx
+++ b/app/soapbox/features/landing-page/__tests__/landing-page.test.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React from 'react';
import LandingPage from '..';
import { rememberInstance } from '../../../actions/instance';
diff --git a/app/soapbox/features/landing-page/index.tsx b/app/soapbox/features/landing-page/index.tsx
index 08b9c2242..b508ff2d9 100644
--- a/app/soapbox/features/landing-page/index.tsx
+++ b/app/soapbox/features/landing-page/index.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React from 'react';
import { FormattedMessage } from 'react-intl';
import { prepareRequest } from 'soapbox/actions/consumer-auth';
@@ -106,7 +106,7 @@ const LandingPage = () => {
-
+
diff --git a/app/soapbox/features/list-adder/components/account.tsx b/app/soapbox/features/list-adder/components/account.tsx
deleted file mode 100644
index e35a0ce96..000000000
--- a/app/soapbox/features/list-adder/components/account.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React, { useCallback } from 'react';
-
-import DisplayName from 'soapbox/components/display-name';
-import { Avatar } from 'soapbox/components/ui';
-import { useAppSelector } from 'soapbox/hooks';
-import { makeGetAccount } from 'soapbox/selectors';
-
-interface IAccount {
- accountId: string,
-}
-
-const Account: React.FC = ({ accountId }) => {
- const getAccount = useCallback(makeGetAccount(), []);
-
- const account = useAppSelector((state) => getAccount(state, accountId));
-
- if (!account) return null;
-
- return (
-
- );
-};
-
-export default Account;
diff --git a/app/soapbox/features/list-adder/index.tsx b/app/soapbox/features/list-adder/index.tsx
index 1e9d7c745..f47e338d7 100644
--- a/app/soapbox/features/list-adder/index.tsx
+++ b/app/soapbox/features/list-adder/index.tsx
@@ -4,11 +4,11 @@ import { createSelector } from 'reselect';
import { setupListAdder, resetListAdder } from 'soapbox/actions/lists';
import { CardHeader, CardTitle, Modal } from 'soapbox/components/ui';
+import AccountContainer from 'soapbox/containers/account-container';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import NewListForm from '../lists/components/new-list-form';
-import Account from './components/account';
import List from './components/list';
import type { List as ImmutableList } from 'immutable';
@@ -58,7 +58,7 @@ const ListAdder: React.FC = ({ accountId, onClose }) => {
title={}
onClose={onClickClose}
>
-
+
diff --git a/app/soapbox/features/list-editor/components/account.tsx b/app/soapbox/features/list-editor/components/account.tsx
index b6c04a9e6..5023a5b8b 100644
--- a/app/soapbox/features/list-editor/components/account.tsx
+++ b/app/soapbox/features/list-editor/components/account.tsx
@@ -1,12 +1,11 @@
-import React, { useCallback } from 'react';
+import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { removeFromListEditor, addToListEditor } from 'soapbox/actions/lists';
-import DisplayName from 'soapbox/components/display-name';
import IconButton from 'soapbox/components/icon-button';
-import { Avatar } from 'soapbox/components/ui';
+import { HStack } from 'soapbox/components/ui';
+import AccountContainer from 'soapbox/containers/account-container';
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
-import { makeGetAccount } from 'soapbox/selectors';
const messages = defineMessages({
remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
@@ -20,37 +19,27 @@ interface IAccount {
const Account: React.FC = ({ accountId }) => {
const intl = useIntl();
const dispatch = useAppDispatch();
- const getAccount = useCallback(makeGetAccount(), []);
- const account = useAppSelector((state) => getAccount(state, accountId));
const isAdded = useAppSelector((state) => state.listEditor.accounts.items.includes(accountId));
const onRemove = () => dispatch(removeFromListEditor(accountId));
const onAdd = () => dispatch(addToListEditor(accountId));
- if (!account) return null;
-
let button;
if (isAdded) {
- button = ;
+ button = ;
} else {
- button = ;
+ button = ;
}
return (
-
-
+ {button}
+
);
};
diff --git a/app/soapbox/features/notifications/components/__tests__/notification.test.tsx b/app/soapbox/features/notifications/components/__tests__/notification.test.tsx
index b9c5df641..e75562485 100644
--- a/app/soapbox/features/notifications/components/__tests__/notification.test.tsx
+++ b/app/soapbox/features/notifications/components/__tests__/notification.test.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React from 'react';
import { updateNotifications } from 'soapbox/actions/notifications';
import { render, screen, rootState, createTestStore } from 'soapbox/jest/test-helpers';
diff --git a/app/soapbox/features/onboarding/onboarding-wizard.tsx b/app/soapbox/features/onboarding/onboarding-wizard.tsx
index ae3c3c74c..f89204885 100644
--- a/app/soapbox/features/onboarding/onboarding-wizard.tsx
+++ b/app/soapbox/features/onboarding/onboarding-wizard.tsx
@@ -1,5 +1,5 @@
import classNames from 'clsx';
-import * as React from 'react';
+import React from 'react';
import { useDispatch } from 'react-redux';
import ReactSwipeableViews from 'react-swipeable-views';
diff --git a/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx b/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx
index 753ef4d7f..f5f9f7274 100644
--- a/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx
+++ b/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx
@@ -1,6 +1,6 @@
import classNames from 'clsx';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
+import React from 'react';
+import { defineMessages, FormattedMessage } from 'react-intl';
import { useDispatch } from 'react-redux';
import { patchMe } from 'soapbox/actions/me';
@@ -11,6 +11,10 @@ import resizeImage from 'soapbox/utils/resize-image';
import type { AxiosError } from 'axios';
+const messages = defineMessages({
+ error: { id: 'onboarding.error', defaultMessage: 'An unexpected error occurred. Please try again or skip this step.' },
+});
+
/** Default avatar filenames from various backends */
const DEFAULT_AVATARS = [
'/avatars/original/missing.png', // Mastodon
@@ -64,7 +68,7 @@ const AvatarSelectionStep = ({ onNext }: { onNext: () => void }) => {
if (error.response?.status === 422) {
dispatch(snackbar.error((error.response.data as any).error.replace('Validation failed: ', '')));
} else {
- dispatch(snackbar.error('An unexpected error occurred. Please try again or skip this step.'));
+ dispatch(snackbar.error(messages.error));
}
});
}).catch(console.error);
diff --git a/app/soapbox/features/onboarding/steps/bio-step.tsx b/app/soapbox/features/onboarding/steps/bio-step.tsx
index 31c7bc6c9..38ec425ad 100644
--- a/app/soapbox/features/onboarding/steps/bio-step.tsx
+++ b/app/soapbox/features/onboarding/steps/bio-step.tsx
@@ -1,5 +1,5 @@
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
+import React from 'react';
+import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { useDispatch } from 'react-redux';
import { patchMe } from 'soapbox/actions/me';
@@ -9,7 +9,13 @@ import { useOwnAccount } from 'soapbox/hooks';
import type { AxiosError } from 'axios';
+const messages = defineMessages({
+ bioPlaceholder: { id: 'onboarding.bio.placeholder', defaultMessage: 'Tell the world a little about yourself…' },
+ error: { id: 'onboarding.error', defaultMessage: 'An unexpected error occurred. Please try again or skip this step.' },
+});
+
const BioStep = ({ onNext }: { onNext: () => void }) => {
+ const intl = useIntl();
const dispatch = useDispatch();
const account = useOwnAccount();
@@ -32,7 +38,7 @@ const BioStep = ({ onNext }: { onNext: () => void }) => {
if (error.response?.status === 422) {
setErrors([(error.response.data as any).error.replace('Validation failed: ', '')]);
} else {
- dispatch(snackbar.error('An unexpected error occurred. Please try again or skip this step.'));
+ dispatch(snackbar.error(messages.error));
}
});
};
@@ -56,13 +62,13 @@ const BioStep = ({ onNext }: { onNext: () => void }) => {
}
+ labelText={
}
errors={errors}
>
+
diff --git a/app/soapbox/features/ui/components/profile-field.tsx b/app/soapbox/features/ui/components/profile-field.tsx
new file mode 100644
index 000000000..2593c5201
--- /dev/null
+++ b/app/soapbox/features/ui/components/profile-field.tsx
@@ -0,0 +1,73 @@
+import classNames from 'clsx';
+import React from 'react';
+import { defineMessages, useIntl, FormatDateOptions } from 'react-intl';
+
+import Markup from 'soapbox/components/markup';
+import { HStack, Icon } from 'soapbox/components/ui';
+import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
+import { CryptoAddress } from 'soapbox/features/ui/util/async-components';
+
+import type { Field } from 'soapbox/types/entities';
+
+const getTicker = (value: string): string => (value.match(/\$([a-zA-Z]*)/i) || [])[1];
+const isTicker = (value: string): boolean => Boolean(getTicker(value));
+
+const messages = defineMessages({
+ linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },
+});
+
+const dateFormatOptions: FormatDateOptions = {
+ month: 'short',
+ day: 'numeric',
+ year: 'numeric',
+ hour12: true,
+ hour: 'numeric',
+ minute: '2-digit',
+};
+
+interface IProfileField {
+ field: Field,
+}
+
+/** Renders a single profile field. */
+const ProfileField: React.FC
= ({ field }) => {
+ const intl = useIntl();
+
+ if (isTicker(field.name)) {
+ return (
+
+ {Component => (
+
+ )}
+
+ );
+ }
+
+ return (
+
+ -
+
+
+
+ -
+
+ {field.verified_at && (
+
+
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default ProfileField;
diff --git a/app/soapbox/features/ui/components/profile-fields-panel.tsx b/app/soapbox/features/ui/components/profile-fields-panel.tsx
index 1ee911e34..1babfb63f 100644
--- a/app/soapbox/features/ui/components/profile-fields-panel.tsx
+++ b/app/soapbox/features/ui/components/profile-fields-panel.tsx
@@ -1,77 +1,11 @@
-import classNames from 'clsx';
import React from 'react';
-import { defineMessages, useIntl, FormattedMessage, FormatDateOptions } from 'react-intl';
+import { FormattedMessage } from 'react-intl';
-import Markup from 'soapbox/components/markup';
-import { Widget, Stack, HStack, Icon } from 'soapbox/components/ui';
-import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
-import { CryptoAddress } from 'soapbox/features/ui/util/async-components';
+import { Widget, Stack } from 'soapbox/components/ui';
-import type { Account, Field } from 'soapbox/types/entities';
+import ProfileField from './profile-field';
-const getTicker = (value: string): string => (value.match(/\$([a-zA-Z]*)/i) || [])[1];
-const isTicker = (value: string): boolean => Boolean(getTicker(value));
-
-const messages = defineMessages({
- linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },
- account_locked: { id: 'account.locked_info', defaultMessage: 'This account privacy status is set to locked. The owner manually reviews who can follow them.' },
- deactivated: { id: 'account.deactivated', defaultMessage: 'Deactivated' },
- bot: { id: 'account.badges.bot', defaultMessage: 'Bot' },
-});
-
-const dateFormatOptions: FormatDateOptions = {
- month: 'short',
- day: 'numeric',
- year: 'numeric',
- hour12: true,
- hour: 'numeric',
- minute: '2-digit',
-};
-
-interface IProfileField {
- field: Field,
-}
-
-/** Renders a single profile field. */
-const ProfileField: React.FC = ({ field }) => {
- const intl = useIntl();
-
- if (isTicker(field.name)) {
- return (
-
- {Component => (
-
- )}
-
- );
- }
-
- return (
-
- -
-
-
-
- -
-
- {field.verified_at && (
-
-
-
- )}
-
-
-
-
-
- );
-};
+import type { Account } from 'soapbox/types/entities';
interface IProfileFieldsPanel {
account: Account,
diff --git a/app/soapbox/features/ui/components/profile-info-panel.tsx b/app/soapbox/features/ui/components/profile-info-panel.tsx
index 89239bd61..a765b38f2 100644
--- a/app/soapbox/features/ui/components/profile-info-panel.tsx
+++ b/app/soapbox/features/ui/components/profile-info-panel.tsx
@@ -13,6 +13,7 @@ import { badgeToTag, getBadges as getAccountBadges } from 'soapbox/utils/badges'
import { capitalize } from 'soapbox/utils/strings';
import ProfileFamiliarFollowers from './profile-familiar-followers';
+import ProfileField from './profile-field';
import ProfileStats from './profile-stats';
import type { Account } from 'soapbox/types/entities';
@@ -231,6 +232,14 @@ const ProfileInfoPanel: React.FC = ({ account, username }) =>
+
+ {account.fields.size > 0 && (
+
+ {account.fields.map((field, i) => (
+
+ ))}
+
+ )}
);
};
diff --git a/app/soapbox/features/ui/components/promo-panel.tsx b/app/soapbox/features/ui/components/promo-panel.tsx
index 6766a6ad4..9add33b27 100644
--- a/app/soapbox/features/ui/components/promo-panel.tsx
+++ b/app/soapbox/features/ui/components/promo-panel.tsx
@@ -20,7 +20,7 @@ const PromoPanel: React.FC = () => {
{promoItems.map((item, i) => (
-
+
{item.textLocales.get(locale) || item.text}
diff --git a/app/soapbox/features/ui/components/theme-selector.tsx b/app/soapbox/features/ui/components/theme-selector.tsx
index e285788e0..8ce8199e7 100644
--- a/app/soapbox/features/ui/components/theme-selector.tsx
+++ b/app/soapbox/features/ui/components/theme-selector.tsx
@@ -1,9 +1,7 @@
import React, { useMemo } from 'react';
import { defineMessages, useIntl } from 'react-intl';
-import { Icon } from 'soapbox/components/ui';
-
-import Select from '../../../components/ui/select/select';
+import { Icon, Select } from 'soapbox/components/ui';
const messages = defineMessages({
light: { id: 'theme_toggle.light', defaultMessage: 'Light' },
diff --git a/app/soapbox/features/ui/components/trends-panel.tsx b/app/soapbox/features/ui/components/trends-panel.tsx
index 75ef4f151..e7f11683a 100644
--- a/app/soapbox/features/ui/components/trends-panel.tsx
+++ b/app/soapbox/features/ui/components/trends-panel.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { Link } from 'react-router-dom';
diff --git a/app/soapbox/features/ui/components/upload-area.tsx b/app/soapbox/features/ui/components/upload-area.tsx
index 5cc0c9e64..6d6fb395b 100644
--- a/app/soapbox/features/ui/components/upload-area.tsx
+++ b/app/soapbox/features/ui/components/upload-area.tsx
@@ -1,5 +1,5 @@
import classNames from 'clsx';
-import * as React from 'react';
+import React from 'react';
import { FormattedMessage } from 'react-intl';
import { spring } from 'react-motion';
diff --git a/app/soapbox/features/ui/components/user-panel.tsx b/app/soapbox/features/ui/components/user-panel.tsx
index 8f0fbf517..918d94efd 100644
--- a/app/soapbox/features/ui/components/user-panel.tsx
+++ b/app/soapbox/features/ui/components/user-panel.tsx
@@ -36,13 +36,9 @@ const UserPanel: React.FC
= ({ accountId, action, badges, domain })
-
+
{header && (
-
+
)}
diff --git a/app/soapbox/features/ui/components/who-to-follow-panel.tsx b/app/soapbox/features/ui/components/who-to-follow-panel.tsx
index f479acead..dd2fc91fa 100644
--- a/app/soapbox/features/ui/components/who-to-follow-panel.tsx
+++ b/app/soapbox/features/ui/components/who-to-follow-panel.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { Link } from 'react-router-dom';
diff --git a/app/soapbox/features/verification/email-passthru.tsx b/app/soapbox/features/verification/email-passthru.tsx
index e51f3220f..bfdc017de 100644
--- a/app/soapbox/features/verification/email-passthru.tsx
+++ b/app/soapbox/features/verification/email-passthru.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useHistory, useParams } from 'react-router-dom';
diff --git a/app/soapbox/features/verification/index.tsx b/app/soapbox/features/verification/index.tsx
index 4470bd4c2..88c9dc435 100644
--- a/app/soapbox/features/verification/index.tsx
+++ b/app/soapbox/features/verification/index.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React from 'react';
import { Redirect } from 'react-router-dom';
import { fetchVerificationConfig } from 'soapbox/actions/verification';
diff --git a/app/soapbox/features/verification/registration.tsx b/app/soapbox/features/verification/registration.tsx
index e4bf2c1e2..6539ca8c8 100644
--- a/app/soapbox/features/verification/registration.tsx
+++ b/app/soapbox/features/verification/registration.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { Redirect } from 'react-router-dom';
@@ -16,22 +16,12 @@ import PasswordIndicator from './components/password-indicator';
import type { AxiosError } from 'axios';
const messages = defineMessages({
- success: {
- id: 'registrations.success',
- defaultMessage: 'Welcome to {siteTitle}!',
- },
- usernameHint: {
- id: 'registrations.username.hint',
- defaultMessage: 'May only contain A-Z, 0-9, and underscores',
- },
- usernameTaken: {
- id: 'registrations.unprocessable_entity',
- defaultMessage: 'This username has already been taken.',
- },
- error: {
- id: 'registrations.error',
- defaultMessage: 'Failed to register your account.',
- },
+ success: { id: 'registrations.success', defaultMessage: 'Welcome to {siteTitle}!' },
+ usernameLabel: { id: 'registrations.username.label', defaultMessage: 'Your username' },
+ usernameHint: { id: 'registrations.username.hint', defaultMessage: 'May only contain A-Z, 0-9, and underscores' },
+ usernameTaken: { id: 'registrations.unprocessable_entity', defaultMessage: 'This username has already been taken.' },
+ passwordLabel: { id: 'registrations.password.label', defaultMessage: 'Password' },
+ error: { id: 'registrations.error', defaultMessage: 'Failed to register your account.' },
});
const initialState = {
@@ -108,7 +98,7 @@ const Registration = () => {
diff --git a/app/soapbox/features/verification/steps/email-verification.tsx b/app/soapbox/features/verification/steps/email-verification.tsx
index 98c11b829..a83483616 100644
--- a/app/soapbox/features/verification/steps/email-verification.tsx
+++ b/app/soapbox/features/verification/steps/email-verification.tsx
@@ -13,6 +13,7 @@ const messages = defineMessages({
verificationFail: { id: 'email_verification.fail', defaultMessage: 'Failed to request email verification.' },
verificationFailTakenAlert: { id: 'email_verifilcation.exists', defaultMessage: 'This email has already been taken.' },
verificationFailTaken: { id: 'email_verification.taken', defaultMessage: 'is taken' },
+ emailLabel: { id: 'email_verification.email.label', defaultMessage: 'E-mail address' },
});
const Statuses = {
@@ -122,7 +123,7 @@ const EmailVerification = () => {
diff --git a/app/soapbox/features/verification/steps/sms-verification.tsx b/app/soapbox/features/verification/steps/sms-verification.tsx
index 7337c706d..efe0a5ffc 100644
--- a/app/soapbox/features/verification/steps/sms-verification.tsx
+++ b/app/soapbox/features/verification/steps/sms-verification.tsx
@@ -13,6 +13,7 @@ const messages = defineMessages({
verificationSuccess: { id: 'sms_verification.success', defaultMessage: 'A verification code has been sent to your phone number.' },
verificationFail: { id: 'sms_verification.fail', defaultMessage: 'Failed to send SMS message to your phone number.' },
verificationExpired: { id: 'sms_verification.expired', defaultMessage: 'Your SMS token has expired.' },
+ phoneLabel: { id: 'sms_verification.phone.label', defaultMessage: 'Phone number' },
});
const Statuses = {
@@ -98,7 +99,7 @@ const SmsVerification = () => {
- We sent you a 6-digit code via SMS. Enter it below.
+
{
onClick={resendVerificationCode}
disabled={requestedAnother}
>
- Resend verification code?
+
@@ -138,7 +139,7 @@ const SmsVerification = () => {
diff --git a/app/soapbox/features/verification/waitlist-page.tsx b/app/soapbox/features/verification/waitlist-page.tsx
index 71677d3d3..ebfe6a00d 100644
--- a/app/soapbox/features/verification/waitlist-page.tsx
+++ b/app/soapbox/features/verification/waitlist-page.tsx
@@ -1,4 +1,5 @@
import React, { useEffect } from 'react';
+import { FormattedMessage } from 'react-intl';
import { useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
@@ -40,9 +41,9 @@ const WaitlistPage = (/* { account } */) => {
-
@@ -55,13 +56,17 @@ const WaitlistPage = (/* { account } */) => {
- Welcome back to {title}! You were previously placed on our
- waitlist. Please verify your phone number to receive
- immediate access to your account!
+
-
+
diff --git a/app/soapbox/features/video/index.tsx b/app/soapbox/features/video/index.tsx
index f418714bd..71aaae65d 100644
--- a/app/soapbox/features/video/index.tsx
+++ b/app/soapbox/features/video/index.tsx
@@ -2,17 +2,14 @@ import classNames from 'clsx';
import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';
import React, { useCallback, useEffect, useRef, useState } from 'react';
-import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
+import { defineMessages, useIntl } from 'react-intl';
import Blurhash from 'soapbox/components/blurhash';
import Icon from 'soapbox/components/icon';
-import { useSettings } from 'soapbox/hooks';
import { isPanoramic, isPortrait, minimumAspectRatio, maximumAspectRatio } from 'soapbox/utils/media-aspect-ratio';
import { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen';
-import type { Attachment } from 'soapbox/types/entities';
-
const DEFAULT_HEIGHT = 300;
type Position = { x: number, y: number };
@@ -107,15 +104,11 @@ interface IVideo {
alt?: string,
width?: number,
height?: number,
- sensitive?: boolean,
startTime?: number,
- onOpenVideo?: (attachment: Attachment, time: number) => void,
- onCloseVideo?: () => void,
detailed?: boolean,
inline?: boolean,
cacheWidth?: (width: number) => void,
visible?: boolean,
- onToggleVisibility?: () => void,
blurhash?: string,
link?: React.ReactNode,
aspectRatio?: number,
@@ -125,23 +118,18 @@ interface IVideo {
const Video: React.FC = ({
width,
visible = false,
- sensitive = false,
detailed = false,
cacheWidth,
- onToggleVisibility,
startTime,
src,
height,
alt,
- onCloseVideo,
inline,
aspectRatio = 16 / 9,
link,
blurhash,
}) => {
const intl = useIntl();
- const settings = useSettings();
- const displayMedia = settings.get('displayMedia') as string | undefined;
const player = useRef(null);
const video = useRef(null);
@@ -157,7 +145,6 @@ const Video: React.FC = ({
const [fullscreen, setFullscreen] = useState(false);
const [hovered, setHovered] = useState(false);
const [muted, setMuted] = useState(false);
- const [revealed, setRevealed] = useState(visible !== undefined ? visible : (displayMedia !== 'hide_all' && !sensitive || displayMedia === 'show_all'));
const [buffer, setBuffer] = useState(0);
const setDimensions = () => {
@@ -342,7 +329,6 @@ const Video: React.FC = ({
// If we are in fullscreen mode, we don't want any hotkeys
// interacting with the UI that's not visible
-
if (fullscreen) {
e.preventDefault();
e.stopPropagation();
@@ -411,16 +397,6 @@ const Video: React.FC = ({
}
};
- const toggleReveal: React.MouseEventHandler = (e) => {
- e.stopPropagation();
-
- if (onToggleVisibility) {
- onToggleVisibility();
- } else {
- setRevealed(!revealed);
- }
- };
-
const handleLoadedData = () => {
if (video.current && startTime) {
video.current.currentTime = startTime;
@@ -459,14 +435,6 @@ const Video: React.FC = ({
playerStyle.height = height || DEFAULT_HEIGHT;
}
- let warning;
-
- if (sensitive) {
- warning = ;
- } else {
- warning = ;
- }
-
useEffect(() => {
document.addEventListener('fullscreenchange', handleFullscreenChange, true);
document.addEventListener('webkitfullscreenchange', handleFullscreenChange, true);
@@ -488,21 +456,15 @@ const Video: React.FC = ({
}, []);
useEffect(() => {
- if (visible) {
- setRevealed(true);
- }
- }, [visible]);
-
- useEffect(() => {
- if (!revealed) {
+ if (!visible) {
video.current?.pause();
}
- }, [revealed]);
+ }, [visible]);
return (
= ({
onKeyDown={handleKeyDown}
tabIndex={0}
>
-
-
- {revealed && (
-
+ {!fullscreen && (
+
)}
-
-
-
+
@@ -605,18 +556,6 @@ const Video: React.FC = ({
- {(sensitive && !onCloseVideo) && (
-
- )}
-