diff --git a/app/index.ejs b/app/index.ejs
index 17cf261c3..0f3ec664c 100644
--- a/app/index.ejs
+++ b/app/index.ejs
@@ -9,33 +9,6 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/soapbox/components/account.tsx b/app/soapbox/components/account.tsx
index 47dc5d769..cc4efe3fb 100644
--- a/app/soapbox/components/account.tsx
+++ b/app/soapbox/components/account.tsx
@@ -4,7 +4,7 @@ import { Link } from 'react-router-dom';
import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper';
import VerificationBadge from 'soapbox/components/verification_badge';
import ActionButton from 'soapbox/features/ui/components/action_button';
-import { useAppSelector } from 'soapbox/hooks';
+import { useAppSelector, useOnScreen } from 'soapbox/hooks';
import { getAcct } from 'soapbox/utils/accounts';
import { displayFqn } from 'soapbox/utils/state';
@@ -52,8 +52,9 @@ const Account = ({
timestampUrl,
withRelationship = true,
}: IAccount) => {
- const overflowRef = React.useRef(null);
- const actionRef = React.useRef(null);
+ const overflowRef = React.useRef
(null);
+ const actionRef = React.useRef(null);
+ const isOnScreen = useOnScreen(overflowRef);
const [style, setStyle] = React.useState({ visibility: 'hidden' });
@@ -93,18 +94,19 @@ const Account = ({
};
React.useEffect(() => {
- const style: React.CSSProperties = {};
+ if (isOnScreen) {
+ const style: React.CSSProperties = {};
+ const actionWidth = actionRef.current?.clientWidth;
- const actionWidth = actionRef.current?.clientWidth;
+ if (overflowRef.current) {
+ style.maxWidth = overflowRef.current.clientWidth - 30 - avatarSize - actionWidth;
+ } else {
+ style.visibility = 'hidden';
+ }
- if (overflowRef.current) {
- style.maxWidth = overflowRef.current.clientWidth - 30 - avatarSize - actionWidth;
- } else {
- style.visibility = 'hidden';
+ setStyle(style);
}
-
- setStyle(style);
- }, [overflowRef, actionRef]);
+ }, [isOnScreen, overflowRef, actionRef]);
if (!account) {
return null;
@@ -161,8 +163,8 @@ const Account = ({
-
- @{username}
+
+ @{username}
{(timestamp) ? (
<>
diff --git a/app/soapbox/components/avatar.js b/app/soapbox/components/avatar.js
index a61917252..d5000264d 100644
--- a/app/soapbox/components/avatar.js
+++ b/app/soapbox/components/avatar.js
@@ -8,7 +8,7 @@ import StillImage from 'soapbox/components/still_image';
export default class Avatar extends React.PureComponent {
static propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
size: PropTypes.number,
style: PropTypes.object,
className: PropTypes.string,
diff --git a/app/soapbox/components/avatar_overlay.js b/app/soapbox/components/avatar_overlay.js
index 01e35b4d1..ce9784c95 100644
--- a/app/soapbox/components/avatar_overlay.js
+++ b/app/soapbox/components/avatar_overlay.js
@@ -6,7 +6,7 @@ import StillImage from 'soapbox/components/still_image';
export default class AvatarOverlay extends React.PureComponent {
static propTypes = {
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
friend: ImmutablePropTypes.map.isRequired,
};
diff --git a/app/soapbox/components/display_name.js b/app/soapbox/components/display_name.js
index 87947af46..69a1c0177 100644
--- a/app/soapbox/components/display_name.js
+++ b/app/soapbox/components/display_name.js
@@ -22,7 +22,7 @@ export default @connect(mapStateToProps)
class DisplayName extends React.PureComponent {
static propTypes = {
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
displayFqn: PropTypes.bool,
others: ImmutablePropTypes.list,
children: PropTypes.node,
diff --git a/app/soapbox/components/dropdown_menu.js b/app/soapbox/components/dropdown_menu.js
index bddb47d1a..c471ac27b 100644
--- a/app/soapbox/components/dropdown_menu.js
+++ b/app/soapbox/components/dropdown_menu.js
@@ -207,7 +207,7 @@ class Dropdown extends React.PureComponent {
pressed: PropTypes.bool,
title: PropTypes.string,
disabled: PropTypes.bool,
- status: ImmutablePropTypes.map,
+ status: ImmutablePropTypes.record,
isUserTouching: PropTypes.func,
isModalOpen: PropTypes.bool.isRequired,
onOpen: PropTypes.func.isRequired,
diff --git a/app/soapbox/components/icon.js b/app/soapbox/components/icon.js
index 3f357a1a3..7c7625806 100644
--- a/app/soapbox/components/icon.js
+++ b/app/soapbox/components/icon.js
@@ -17,15 +17,16 @@ export default class Icon extends React.PureComponent {
id: PropTypes.string,
src: PropTypes.string,
className: PropTypes.string,
+ fixedWidth: PropTypes.bool,
};
render() {
- const { id, src, ...rest } = this.props;
+ const { id, src, fixedWidth, ...rest } = this.props;
if (src) {
return ;
} else {
- return ;
+ return ;
}
}
diff --git a/app/soapbox/components/media_gallery.js b/app/soapbox/components/media_gallery.js
index bb293f416..df1e4db42 100644
--- a/app/soapbox/components/media_gallery.js
+++ b/app/soapbox/components/media_gallery.js
@@ -45,7 +45,7 @@ const shouldLetterbox = attachment => {
class Item extends React.PureComponent {
static propTypes = {
- attachment: ImmutablePropTypes.map.isRequired,
+ attachment: ImmutablePropTypes.record.isRequired,
standalone: PropTypes.bool,
index: PropTypes.number.isRequired,
size: PropTypes.number.isRequired,
diff --git a/app/soapbox/components/permalink.js b/app/soapbox/components/permalink.js
deleted file mode 100644
index 5bae087ac..000000000
--- a/app/soapbox/components/permalink.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { withRouter } from 'react-router-dom';
-
-export default @withRouter
-class Permalink extends React.PureComponent {
-
- static propTypes = {
- className: PropTypes.string,
- href: PropTypes.string.isRequired,
- to: PropTypes.string.isRequired,
- children: PropTypes.node,
- onInterceptClick: PropTypes.func,
- history: PropTypes.object,
- };
-
- handleClick = e => {
- if (this.props.onInterceptClick && this.props.onInterceptClick()) {
- e.preventDefault();
- return;
- }
-
- if (this.props.history && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
- e.preventDefault();
- this.props.history.push(this.props.to);
- }
- }
-
- render() {
- const { href, children, className, onInterceptClick, ...other } = this.props;
-
- return (
-
- {children}
-
- );
- }
-
-}
diff --git a/app/soapbox/components/permalink.tsx b/app/soapbox/components/permalink.tsx
new file mode 100644
index 000000000..db68811e5
--- /dev/null
+++ b/app/soapbox/components/permalink.tsx
@@ -0,0 +1,37 @@
+import * as React from 'react';
+import { useHistory } from 'react-router-dom';
+
+interface IPermaLink extends Pick, 'dangerouslySetInnerHTML'> {
+ className?: string,
+ href: string,
+ title?: string,
+ to: string,
+}
+
+const Permalink: React.FC = (props) => {
+ const history = useHistory();
+
+ const { className, href, title, to, children, ...filteredProps } = props;
+
+ const handleClick = (event: React.MouseEvent) => {
+ if (event.button === 0 && !(event.ctrlKey || event.metaKey)) {
+ event.preventDefault();
+ history.push(to);
+ }
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default Permalink;
diff --git a/app/soapbox/components/profile_hover_card.js b/app/soapbox/components/profile_hover_card.js
index 0a7e57509..a1da1e435 100644
--- a/app/soapbox/components/profile_hover_card.js
+++ b/app/soapbox/components/profile_hover_card.js
@@ -134,7 +134,7 @@ export const ProfileHoverCard = ({ visible }) => {
ProfileHoverCard.propTypes = {
visible: PropTypes.bool,
accountId: PropTypes.string,
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
};
ProfileHoverCard.defaultProps = {
diff --git a/app/soapbox/components/scrollable_list.js b/app/soapbox/components/scrollable_list.js
index 1c96b5d57..8021acf32 100644
--- a/app/soapbox/components/scrollable_list.js
+++ b/app/soapbox/components/scrollable_list.js
@@ -43,7 +43,7 @@ class ScrollableList extends PureComponent {
children: PropTypes.node,
onScrollToTop: PropTypes.func,
onScroll: PropTypes.func,
- placeholderComponent: PropTypes.func,
+ placeholderComponent: PropTypes.object,
placeholderCount: PropTypes.number,
autoload: PropTypes.bool,
onRefresh: PropTypes.func,
diff --git a/app/soapbox/components/status.js b/app/soapbox/components/status.js
index 261ada64e..a2c086912 100644
--- a/app/soapbox/components/status.js
+++ b/app/soapbox/components/status.js
@@ -55,8 +55,8 @@ export default @injectIntl @withRouter
class Status extends ImmutablePureComponent {
static propTypes = {
- status: ImmutablePropTypes.map,
- account: ImmutablePropTypes.map,
+ status: ImmutablePropTypes.record,
+ account: ImmutablePropTypes.record,
otherAccounts: ImmutablePropTypes.list,
onClick: PropTypes.func,
onReply: PropTypes.func,
diff --git a/app/soapbox/components/status_action_bar.js b/app/soapbox/components/status_action_bar.js
index dbdb7f8d0..00937f00d 100644
--- a/app/soapbox/components/status_action_bar.js
+++ b/app/soapbox/components/status_action_bar.js
@@ -69,7 +69,7 @@ const messages = defineMessages({
class StatusActionBar extends ImmutablePureComponent {
static propTypes = {
- status: ImmutablePropTypes.map.isRequired,
+ status: ImmutablePropTypes.record.isRequired,
onOpenUnauthorizedModal: PropTypes.func.isRequired,
onOpenReblogsModal: PropTypes.func.isRequired,
onReply: PropTypes.func,
diff --git a/app/soapbox/components/status_content.js b/app/soapbox/components/status_content.js
index be07ed28d..2e6105a52 100644
--- a/app/soapbox/components/status_content.js
+++ b/app/soapbox/components/status_content.js
@@ -28,7 +28,7 @@ export default @connect(mapStateToProps)
class StatusContent extends React.PureComponent {
static propTypes = {
- status: ImmutablePropTypes.map.isRequired,
+ status: ImmutablePropTypes.record.isRequired,
reblogContent: PropTypes.string,
expanded: PropTypes.bool,
onExpandedToggle: PropTypes.func,
diff --git a/app/soapbox/components/status_list.js b/app/soapbox/components/status_list.js
index 65bbdba52..c8bcbb217 100644
--- a/app/soapbox/components/status_list.js
+++ b/app/soapbox/components/status_list.js
@@ -223,7 +223,7 @@ export default class StatusList extends ImmutablePureComponent {
isLoading={isLoading}
showLoading={isLoading && statusIds.size === 0}
onLoadMore={onLoadMore && this.handleLoadOlder}
- placeholderComponent={() => }
+ placeholderComponent={PlaceholderStatus}
placeholderCount={20}
ref={this.setRef}
className={divideType === 'border' ? 'divide-y divide-solid divide-gray-200' : 'sm:space-y-3 divide-y divide-solid divide-gray-200 sm:divide-none'}
diff --git a/app/soapbox/components/status_reply_mentions.js b/app/soapbox/components/status_reply_mentions.js
index 0e9484aa0..76a48d5df 100644
--- a/app/soapbox/components/status_reply_mentions.js
+++ b/app/soapbox/components/status_reply_mentions.js
@@ -23,7 +23,7 @@ export default @connect(null, mapDispatchToProps)
class StatusReplyMentions extends ImmutablePureComponent {
static propTypes = {
- status: ImmutablePropTypes.map.isRequired,
+ status: ImmutablePropTypes.record.isRequired,
onOpenMentionsModal: PropTypes.func,
}
diff --git a/app/soapbox/components/thumb_navigation.js b/app/soapbox/components/thumb_navigation.js
index 17256569d..caf6566f6 100644
--- a/app/soapbox/components/thumb_navigation.js
+++ b/app/soapbox/components/thumb_navigation.js
@@ -33,7 +33,7 @@ class ThumbNavigation extends React.PureComponent {
static propTypes = {
logo: PropTypes.string,
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
dashboardCount: PropTypes.number,
notificationCount: PropTypes.number,
chatsCount: PropTypes.number,
diff --git a/app/soapbox/components/ui/hstack/hstack.tsx b/app/soapbox/components/ui/hstack/hstack.tsx
index 224a322b5..d97697670 100644
--- a/app/soapbox/components/ui/hstack/hstack.tsx
+++ b/app/soapbox/components/ui/hstack/hstack.tsx
@@ -29,6 +29,7 @@ interface IHStack {
justifyContent?: 'between' | 'center',
space?: 0.5 | 1 | 1.5 | 2 | 3 | 4 | 6,
grow?: boolean,
+ style?: React.CSSProperties
}
const HStack: React.FC = (props) => {
diff --git a/app/soapbox/containers/soapbox.js b/app/soapbox/containers/soapbox.js
index aad96badb..3571a687d 100644
--- a/app/soapbox/containers/soapbox.js
+++ b/app/soapbox/containers/soapbox.js
@@ -97,7 +97,7 @@ class SoapboxMount extends React.PureComponent {
static propTypes = {
showIntroduction: PropTypes.bool,
me: SoapboxPropTypes.me,
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
instanceLoaded: PropTypes.bool,
reduceMotion: PropTypes.bool,
underlineLinks: PropTypes.bool,
diff --git a/app/soapbox/features/account/components/header.js b/app/soapbox/features/account/components/header.js
index 42fcad65d..65c2160c0 100644
--- a/app/soapbox/features/account/components/header.js
+++ b/app/soapbox/features/account/components/header.js
@@ -86,8 +86,8 @@ export default @connect(mapStateToProps)
class Header extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map,
- meAccount: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
+ meaccount: ImmutablePropTypes.record,
identity_props: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired,
username: PropTypes.string,
diff --git a/app/soapbox/features/account_timeline/components/header.js b/app/soapbox/features/account_timeline/components/header.js
index add4ff79f..f827e9314 100644
--- a/app/soapbox/features/account_timeline/components/header.js
+++ b/app/soapbox/features/account_timeline/components/header.js
@@ -12,7 +12,7 @@ export default @withRouter
class Header extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
identity_proofs: ImmutablePropTypes.list,
onFollow: PropTypes.func.isRequired,
onBlock: PropTypes.func.isRequired,
diff --git a/app/soapbox/features/admin/components/report_status.js b/app/soapbox/features/admin/components/report_status.js
index 90c0d062f..721dfdfb2 100644
--- a/app/soapbox/features/admin/components/report_status.js
+++ b/app/soapbox/features/admin/components/report_status.js
@@ -22,7 +22,7 @@ export default @connect()
class ReportStatus extends ImmutablePureComponent {
static propTypes = {
- status: ImmutablePropTypes.map.isRequired,
+ status: ImmutablePropTypes.record.isRequired,
report: ImmutablePropTypes.map,
};
diff --git a/app/soapbox/features/admin/components/unapproved_account.js b/app/soapbox/features/admin/components/unapproved_account.js
index f00b0dd6a..80ca4821d 100644
--- a/app/soapbox/features/admin/components/unapproved_account.js
+++ b/app/soapbox/features/admin/components/unapproved_account.js
@@ -35,7 +35,7 @@ class UnapprovedAccount extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
};
handleApprove = () => {
diff --git a/app/soapbox/features/admin/index.js b/app/soapbox/features/admin/index.js
index db76d4407..61e6e1211 100644
--- a/app/soapbox/features/admin/index.js
+++ b/app/soapbox/features/admin/index.js
@@ -50,7 +50,7 @@ class Dashboard extends ImmutablePureComponent {
intl: PropTypes.object.isRequired,
instance: ImmutablePropTypes.map.isRequired,
supportsEmailList: PropTypes.bool,
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
};
handleSubscribersClick = e => {
diff --git a/app/soapbox/features/aliases/components/account.js b/app/soapbox/features/aliases/components/account.js
index fd0abd21b..38bce11bb 100644
--- a/app/soapbox/features/aliases/components/account.js
+++ b/app/soapbox/features/aliases/components/account.js
@@ -49,7 +49,7 @@ export default @connect(makeMapStateToProps, mapDispatchToProps)
class Account extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
apId: PropTypes.string.isRequired,
intl: PropTypes.object.isRequired,
onAdd: PropTypes.func.isRequired,
diff --git a/app/soapbox/features/birthdays/account.js b/app/soapbox/features/birthdays/account.js
index e79273f89..b29d79589 100644
--- a/app/soapbox/features/birthdays/account.js
+++ b/app/soapbox/features/birthdays/account.js
@@ -36,7 +36,7 @@ class Account extends ImmutablePureComponent {
static propTypes = {
accountId: PropTypes.string.isRequired,
intl: PropTypes.object.isRequired,
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
};
static defaultProps = {
diff --git a/app/soapbox/features/compose/components/privacy_dropdown.js b/app/soapbox/features/compose/components/privacy_dropdown.js
index 415789ba5..23111ab1b 100644
--- a/app/soapbox/features/compose/components/privacy_dropdown.js
+++ b/app/soapbox/features/compose/components/privacy_dropdown.js
@@ -256,8 +256,6 @@ class PrivacyDropdown extends React.PureComponent {
className='text-gray-400 hover:text-gray-600'
src={valueOption.icon}
title={intl.formatMessage(messages.change_privacy)}
- expanded={open}
- active={open}
onClick={this.handleToggle}
onMouseDown={this.handleMouseDown}
onKeyDown={this.handleButtonKeyDown}
diff --git a/app/soapbox/features/compose/components/reply_indicator.js b/app/soapbox/features/compose/components/reply_indicator.js
index b3e8109be..24deb8906 100644
--- a/app/soapbox/features/compose/components/reply_indicator.js
+++ b/app/soapbox/features/compose/components/reply_indicator.js
@@ -12,7 +12,7 @@ import { isRtl } from '../../../rtl';
export default class ReplyIndicator extends ImmutablePureComponent {
static propTypes = {
- status: ImmutablePropTypes.map,
+ status: ImmutablePropTypes.record,
onCancel: PropTypes.func.isRequired,
hideActions: PropTypes.bool,
};
diff --git a/app/soapbox/features/developers/apps/create.js b/app/soapbox/features/developers/apps/create.js
index a06aa9811..de237d451 100644
--- a/app/soapbox/features/developers/apps/create.js
+++ b/app/soapbox/features/developers/apps/create.js
@@ -40,7 +40,7 @@ class CreateApp extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
defaultScopes: PropTypes.string,
}
diff --git a/app/soapbox/features/directory/components/account_card.js b/app/soapbox/features/directory/components/account_card.js
index 36b53d416..cc64dbad1 100644
--- a/app/soapbox/features/directory/components/account_card.js
+++ b/app/soapbox/features/directory/components/account_card.js
@@ -34,7 +34,7 @@ class AccountCard extends ImmutablePureComponent {
static propTypes = {
me: SoapboxPropTypes.me,
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
autoPlayGif: PropTypes.bool,
};
diff --git a/app/soapbox/features/edit_profile/components/profile_preview.js b/app/soapbox/features/edit_profile/components/profile_preview.js
index ad1db11ed..7fe1e8e4c 100644
--- a/app/soapbox/features/edit_profile/components/profile_preview.js
+++ b/app/soapbox/features/edit_profile/components/profile_preview.js
@@ -39,7 +39,7 @@ const ProfilePreview = ({ account, displayFqn }) => (
);
ProfilePreview.propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
displayFqn: PropTypes.bool,
};
diff --git a/app/soapbox/features/edit_profile/index.js b/app/soapbox/features/edit_profile/index.js
index 008711462..a656d6e0b 100644
--- a/app/soapbox/features/edit_profile/index.js
+++ b/app/soapbox/features/edit_profile/index.js
@@ -88,7 +88,7 @@ class EditProfile extends ImmutablePureComponent {
static propTypes = {
dispatch: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
maxFields: PropTypes.number,
verifiedCanEditName: PropTypes.bool,
};
diff --git a/app/soapbox/features/follow_recommendations/components/account.js b/app/soapbox/features/follow_recommendations/components/account.js
index bca3c8400..c15fc6bcc 100644
--- a/app/soapbox/features/follow_recommendations/components/account.js
+++ b/app/soapbox/features/follow_recommendations/components/account.js
@@ -30,7 +30,7 @@ export default @connect(makeMapStateToProps)
class Account extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
intl: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
};
diff --git a/app/soapbox/features/follow_requests/components/account_authorize.js b/app/soapbox/features/follow_requests/components/account_authorize.js
index 8dd6a9252..56aac382a 100644
--- a/app/soapbox/features/follow_requests/components/account_authorize.js
+++ b/app/soapbox/features/follow_requests/components/account_authorize.js
@@ -18,7 +18,7 @@ export default @injectIntl
class AccountAuthorize extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
onAuthorize: PropTypes.func.isRequired,
onReject: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
diff --git a/app/soapbox/features/groups/timeline/index.js b/app/soapbox/features/groups/timeline/index.js
index 529c971ff..0e60bd886 100644
--- a/app/soapbox/features/groups/timeline/index.js
+++ b/app/soapbox/features/groups/timeline/index.js
@@ -35,7 +35,7 @@ class GroupTimeline extends React.PureComponent {
hasUnread: PropTypes.bool,
group: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.bool]),
relationships: ImmutablePropTypes.map,
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
intl: PropTypes.object.isRequired,
};
diff --git a/app/soapbox/features/list_adder/components/account.js b/app/soapbox/features/list_adder/components/account.js
index bbf792d17..014f3ac22 100644
--- a/app/soapbox/features/list_adder/components/account.js
+++ b/app/soapbox/features/list_adder/components/account.js
@@ -24,7 +24,7 @@ export default @connect(makeMapStateToProps)
class Account extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
};
render() {
diff --git a/app/soapbox/features/list_adder/index.js b/app/soapbox/features/list_adder/index.js
index 3283ac04f..7df28d07f 100644
--- a/app/soapbox/features/list_adder/index.js
+++ b/app/soapbox/features/list_adder/index.js
@@ -51,7 +51,7 @@ class ListAdder extends ImmutablePureComponent {
onInitialize: PropTypes.func.isRequired,
onReset: PropTypes.func.isRequired,
listIds: ImmutablePropTypes.list.isRequired,
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
};
componentDidMount() {
diff --git a/app/soapbox/features/list_editor/components/account.js b/app/soapbox/features/list_editor/components/account.js
index eee56b97a..8054bb52f 100644
--- a/app/soapbox/features/list_editor/components/account.js
+++ b/app/soapbox/features/list_editor/components/account.js
@@ -37,7 +37,7 @@ export default @connect(makeMapStateToProps, mapDispatchToProps)
class Account extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
intl: PropTypes.object.isRequired,
onRemove: PropTypes.func.isRequired,
onAdd: PropTypes.func.isRequired,
diff --git a/app/soapbox/features/notifications/components/follow_request.js b/app/soapbox/features/notifications/components/follow_request.js
index 2a2e79269..2bf25131b 100644
--- a/app/soapbox/features/notifications/components/follow_request.js
+++ b/app/soapbox/features/notifications/components/follow_request.js
@@ -18,7 +18,7 @@ export default @injectIntl
class FollowRequest extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
onAuthorize: PropTypes.func.isRequired,
onReject: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
diff --git a/app/soapbox/features/notifications/components/notification.js b/app/soapbox/features/notifications/components/notification.js
index 3c5462ce3..7ff10cc2c 100644
--- a/app/soapbox/features/notifications/components/notification.js
+++ b/app/soapbox/features/notifications/components/notification.js
@@ -228,7 +228,7 @@ const Notification = (props) => {
Notification.propTypes = {
hidden: PropTypes.bool,
- notification: ImmutablePropTypes.map.isRequired,
+ notification: ImmutablePropTypes.record.isRequired,
onMoveUp: PropTypes.func.isRequired,
onMoveDown: PropTypes.func.isRequired,
onMention: PropTypes.func.isRequired,
diff --git a/app/soapbox/features/report/components/status_check_box.js b/app/soapbox/features/report/components/status_check_box.js
index fcb73c902..b74253f96 100644
--- a/app/soapbox/features/report/components/status_check_box.js
+++ b/app/soapbox/features/report/components/status_check_box.js
@@ -11,7 +11,7 @@ import { MediaGallery, Video, Audio } from '../../ui/util/async-components';
export default class StatusCheckBox extends React.PureComponent {
static propTypes = {
- status: ImmutablePropTypes.map.isRequired,
+ status: ImmutablePropTypes.record.isRequired,
checked: PropTypes.bool,
onToggle: PropTypes.func.isRequired,
disabled: PropTypes.bool,
diff --git a/app/soapbox/features/scheduled_statuses/components/scheduled_status_action_bar.js b/app/soapbox/features/scheduled_statuses/components/scheduled_status_action_bar.js
index 0e1773901..7ed5c4d08 100644
--- a/app/soapbox/features/scheduled_statuses/components/scheduled_status_action_bar.js
+++ b/app/soapbox/features/scheduled_statuses/components/scheduled_status_action_bar.js
@@ -48,7 +48,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
class ScheduledStatusActionBar extends ImmutablePureComponent {
static propTypes = {
- status: ImmutablePropTypes.map.isRequired,
+ status: ImmutablePropTypes.record.isRequired,
intl: PropTypes.object.isRequired,
me: SoapboxPropTypes.me,
onCancelClick: PropTypes.func.isRequired,
diff --git a/app/soapbox/features/status/components/action_bar.js b/app/soapbox/features/status/components/action_bar.js
index 317cdfe6a..b3af67ca2 100644
--- a/app/soapbox/features/status/components/action_bar.js
+++ b/app/soapbox/features/status/components/action_bar.js
@@ -84,7 +84,7 @@ const mapDispatchToProps = (dispatch, { status }) => ({
class ActionBar extends React.PureComponent {
static propTypes = {
- status: ImmutablePropTypes.map.isRequired,
+ status: ImmutablePropTypes.record.isRequired,
onReply: PropTypes.func.isRequired,
onReblog: PropTypes.func.isRequired,
onQuote: PropTypes.func.isRequired,
diff --git a/app/soapbox/features/status/components/card.js b/app/soapbox/features/status/components/card.js
index c9f1ec309..ac933ff42 100644
--- a/app/soapbox/features/status/components/card.js
+++ b/app/soapbox/features/status/components/card.js
@@ -61,7 +61,7 @@ const addAutoPlay = html => {
export default class Card extends React.PureComponent {
static propTypes = {
- card: ImmutablePropTypes.map,
+ card: ImmutablePropTypes.record,
maxDescription: PropTypes.number,
onOpenMedia: PropTypes.func.isRequired,
compact: PropTypes.bool,
diff --git a/app/soapbox/features/status/components/detailed_status.js b/app/soapbox/features/status/components/detailed_status.js
index 8d45af06b..0ae645129 100644
--- a/app/soapbox/features/status/components/detailed_status.js
+++ b/app/soapbox/features/status/components/detailed_status.js
@@ -27,7 +27,7 @@ export default @injectIntl
class DetailedStatus extends ImmutablePureComponent {
static propTypes = {
- status: ImmutablePropTypes.map,
+ status: ImmutablePropTypes.record,
onOpenMedia: PropTypes.func.isRequired,
onOpenVideo: PropTypes.func.isRequired,
onToggleHidden: PropTypes.func.isRequired,
diff --git a/app/soapbox/features/status/components/quoted_status.js b/app/soapbox/features/status/components/quoted_status.js
index c3af169ce..c31415a02 100644
--- a/app/soapbox/features/status/components/quoted_status.js
+++ b/app/soapbox/features/status/components/quoted_status.js
@@ -20,7 +20,7 @@ export default @injectIntl @withRouter
class QuotedStatus extends ImmutablePureComponent {
static propTypes = {
- status: ImmutablePropTypes.map,
+ status: ImmutablePropTypes.record,
onCancel: PropTypes.func,
intl: PropTypes.object.isRequired,
compose: PropTypes.bool,
diff --git a/app/soapbox/features/status/components/status_interaction_bar.js b/app/soapbox/features/status/components/status_interaction_bar.js
index 6c69699c0..e1f931865 100644
--- a/app/soapbox/features/status/components/status_interaction_bar.js
+++ b/app/soapbox/features/status/components/status_interaction_bar.js
@@ -55,7 +55,7 @@ export default @connect(mapStateToProps, mapDispatchToProps)
class StatusInteractionBar extends ImmutablePureComponent {
static propTypes = {
- status: ImmutablePropTypes.map,
+ status: ImmutablePropTypes.record,
me: SoapboxPropTypes.me,
allowedEmoji: ImmutablePropTypes.list,
features: PropTypes.object.isRequired,
diff --git a/app/soapbox/features/status/index.js b/app/soapbox/features/status/index.js
index fc0359d69..cf8fce97b 100644
--- a/app/soapbox/features/status/index.js
+++ b/app/soapbox/features/status/index.js
@@ -165,7 +165,7 @@ class Status extends ImmutablePureComponent {
static propTypes = {
params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
- status: ImmutablePropTypes.map,
+ status: ImmutablePropTypes.record,
ancestorsIds: ImmutablePropTypes.orderedSet,
descendantsIds: ImmutablePropTypes.orderedSet,
intl: PropTypes.object.isRequired,
diff --git a/app/soapbox/features/ui/components/action_button.js b/app/soapbox/features/ui/components/action_button.js
index 2ccdb8309..926134c39 100644
--- a/app/soapbox/features/ui/components/action_button.js
+++ b/app/soapbox/features/ui/components/action_button.js
@@ -68,7 +68,7 @@ export default @connect(mapStateToProps, mapDispatchToProps)
class ActionButton extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
onFollow: PropTypes.func.isRequired,
onBlock: PropTypes.func.isRequired,
onOpenUnauthorizedModal: PropTypes.func.isRequired,
diff --git a/app/soapbox/features/ui/components/actions_modal.js b/app/soapbox/features/ui/components/actions_modal.js
index 3429c166e..bcac0c67c 100644
--- a/app/soapbox/features/ui/components/actions_modal.js
+++ b/app/soapbox/features/ui/components/actions_modal.js
@@ -74,7 +74,7 @@ const ActionsModal = ({ status, actions, onClick, onClose }) => {
};
ActionsModal.propTypes = {
- status: ImmutablePropTypes.map,
+ status: ImmutablePropTypes.record,
actions: PropTypes.array,
onClick: PropTypes.func,
onClose: PropTypes.func.isRequired,
diff --git a/app/soapbox/features/ui/components/boost_modal.js b/app/soapbox/features/ui/components/boost_modal.js
index 49763625f..8a3862b35 100644
--- a/app/soapbox/features/ui/components/boost_modal.js
+++ b/app/soapbox/features/ui/components/boost_modal.js
@@ -18,7 +18,7 @@ export default @injectIntl @withRouter
class BoostModal extends ImmutablePureComponent {
static propTypes = {
- status: ImmutablePropTypes.map.isRequired,
+ status: ImmutablePropTypes.record.isRequired,
onReblog: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
diff --git a/app/soapbox/features/ui/components/compose_modal.js b/app/soapbox/features/ui/components/compose_modal.js
index 7d6bf119b..ff9ce136e 100644
--- a/app/soapbox/features/ui/components/compose_modal.js
+++ b/app/soapbox/features/ui/components/compose_modal.js
@@ -29,7 +29,7 @@ const mapStateToProps = state => {
class ComposeModal extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
intl: PropTypes.object.isRequired,
onClose: PropTypes.func.isRequired,
composeText: PropTypes.string,
diff --git a/app/soapbox/features/ui/components/link_footer.js b/app/soapbox/features/ui/components/link_footer.js
index 7861242b0..a049a6a18 100644
--- a/app/soapbox/features/ui/components/link_footer.js
+++ b/app/soapbox/features/ui/components/link_footer.js
@@ -6,10 +6,11 @@ import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { logOut } from 'soapbox/actions/auth';
+import { getSoapboxConfig } from 'soapbox/actions/soapbox';
import { Text } from 'soapbox/components/ui';
import emojify from 'soapbox/features/emoji/emoji';
import { getBaseURL } from 'soapbox/utils/accounts';
-// import sourceCode from 'soapbox/utils/code';
+import sourceCode from 'soapbox/utils/code';
import { getFeatures } from 'soapbox/utils/features';
import { openModal } from '../../../actions/modals';
@@ -19,9 +20,11 @@ const mapStateToProps = state => {
const account = state.getIn(['accounts', me]);
const instance = state.get('instance');
const features = getFeatures(instance);
+ const soapboxConfig = getSoapboxConfig(state);
return {
account,
+ soapboxConfig,
profileDirectory: features.profileDirectory,
federating: features.federating,
showAliases: features.accountAliasesAPI,
@@ -41,7 +44,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
},
});
-const LinkFooter = ({ onOpenHotkeys, account, profileDirectory, federating, showAliases, importAPI, onClickLogOut, baseURL }) => (
+const LinkFooter = ({ onOpenHotkeys, account, profileDirectory, federating, showAliases, importAPI, onClickLogOut, baseURL, soapboxConfig }) => (
{account && <>
@@ -68,26 +71,29 @@ const LinkFooter = ({ onOpenHotkeys, account, profileDirectory, federating, show
- {/*{sourceCode.repository},
- code_version: sourceCode.version,
- }}
- />*/}
- }}
- />
+ {soapboxConfig.get('linkFooterMessage') ? (
+
+ ) : (
+ {sourceCode.repository},
+ code_version: sourceCode.version,
+ }}
+ />
+ )}
);
LinkFooter.propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
+ soapboxConfig: ImmutablePropTypes.map,
profileDirectory: PropTypes.bool,
federating: PropTypes.bool,
showAliases: PropTypes.bool,
diff --git a/app/soapbox/features/ui/components/media_modal.js b/app/soapbox/features/ui/components/media_modal.js
index 8e8053549..31571cde3 100644
--- a/app/soapbox/features/ui/components/media_modal.js
+++ b/app/soapbox/features/ui/components/media_modal.js
@@ -26,8 +26,8 @@ class MediaModal extends ImmutablePureComponent {
static propTypes = {
media: ImmutablePropTypes.list.isRequired,
- status: ImmutablePropTypes.map,
- account: ImmutablePropTypes.map,
+ status: ImmutablePropTypes.record,
+ account: ImmutablePropTypes.record,
index: PropTypes.number.isRequired,
onClose: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
diff --git a/app/soapbox/features/ui/components/profile-dropdown.tsx b/app/soapbox/features/ui/components/profile-dropdown.tsx
index 43f31cfa3..7ff98ea1a 100644
--- a/app/soapbox/features/ui/components/profile-dropdown.tsx
+++ b/app/soapbox/features/ui/components/profile-dropdown.tsx
@@ -116,7 +116,7 @@ const ProfileDropdown: React.FC = ({ account, children }) => {
const itemProps = menuItem.action ? { onSelect: menuItem.action } : { to: menuItem.to, as: Link };
return (
-
+
{menuItem.text}
);
diff --git a/app/soapbox/features/ui/components/profile_info_panel.js b/app/soapbox/features/ui/components/profile_info_panel.js
index 8a19dd83f..41fef805e 100644
--- a/app/soapbox/features/ui/components/profile_info_panel.js
+++ b/app/soapbox/features/ui/components/profile_info_panel.js
@@ -37,7 +37,7 @@ const messages = defineMessages({
class ProfileInfoPanel extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
identity_proofs: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired,
username: PropTypes.string,
diff --git a/app/soapbox/features/ui/components/profile_media_panel.js b/app/soapbox/features/ui/components/profile_media_panel.js
index dfdc70fff..54482ad79 100644
--- a/app/soapbox/features/ui/components/profile_media_panel.js
+++ b/app/soapbox/features/ui/components/profile_media_panel.js
@@ -16,7 +16,7 @@ import MediaItem from '../../account_gallery/components/media_item';
class ProfileMediaPanel extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
attachments: ImmutablePropTypes.list,
dispatch: PropTypes.func.isRequired,
};
diff --git a/app/soapbox/features/ui/components/profile_stats.js b/app/soapbox/features/ui/components/profile_stats.js
index 1a43e858b..325a9c72f 100644
--- a/app/soapbox/features/ui/components/profile_stats.js
+++ b/app/soapbox/features/ui/components/profile_stats.js
@@ -18,7 +18,7 @@ class ProfileStats extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
className: PropTypes.string,
onClickHandler: PropTypes.func,
}
diff --git a/app/soapbox/features/ui/components/report_modal.js b/app/soapbox/features/ui/components/report_modal.js
index c9ecf622a..4dc572d65 100644
--- a/app/soapbox/features/ui/components/report_modal.js
+++ b/app/soapbox/features/ui/components/report_modal.js
@@ -53,7 +53,7 @@ class ReportModal extends ImmutablePureComponent {
static propTypes = {
isSubmitting: PropTypes.bool,
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
statusIds: ImmutablePropTypes.orderedSet.isRequired,
comment: PropTypes.string.isRequired,
forward: PropTypes.bool,
diff --git a/app/soapbox/features/ui/components/subscription_button.js b/app/soapbox/features/ui/components/subscription_button.js
index f8fec8436..1de1a6f88 100644
--- a/app/soapbox/features/ui/components/subscription_button.js
+++ b/app/soapbox/features/ui/components/subscription_button.js
@@ -49,7 +49,7 @@ export default @connect(mapStateToProps, mapDispatchToProps)
class SubscriptionButton extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
features: PropTypes.object.isRequired,
};
diff --git a/app/soapbox/features/ui/components/user_panel.js b/app/soapbox/features/ui/components/user_panel.js
index 0c849c151..e77268614 100644
--- a/app/soapbox/features/ui/components/user_panel.js
+++ b/app/soapbox/features/ui/components/user_panel.js
@@ -19,7 +19,7 @@ import { makeGetAccount } from '../../../selectors';
class UserPanel extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
displayFqn: PropTypes.bool,
intl: PropTypes.object.isRequired,
domain: PropTypes.string,
diff --git a/app/soapbox/features/ui/components/video_modal.js b/app/soapbox/features/ui/components/video_modal.js
index a42cc76d2..066aa9d79 100644
--- a/app/soapbox/features/ui/components/video_modal.js
+++ b/app/soapbox/features/ui/components/video_modal.js
@@ -12,8 +12,8 @@ class VideoModal extends ImmutablePureComponent {
static propTypes = {
media: ImmutablePropTypes.map.isRequired,
- status: ImmutablePropTypes.map,
- account: ImmutablePropTypes.map,
+ status: ImmutablePropTypes.record,
+ account: ImmutablePropTypes.record,
time: PropTypes.number,
onClose: PropTypes.func.isRequired,
history: PropTypes.object,
diff --git a/app/soapbox/features/ui/components/welcome_button.js b/app/soapbox/features/ui/components/welcome_button.js
index f4f352f2f..c9c8fe386 100644
--- a/app/soapbox/features/ui/components/welcome_button.js
+++ b/app/soapbox/features/ui/components/welcome_button.js
@@ -40,7 +40,7 @@ class WelcomeButton extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
- account: ImmutablePropTypes.map.isRequired,
+ account: ImmutablePropTypes.record.isRequired,
onClick: PropTypes.func.isRequired,
};
diff --git a/app/soapbox/features/ui/util/react_router_helpers.js b/app/soapbox/features/ui/util/react_router_helpers.js
index 4942787b8..295e20019 100644
--- a/app/soapbox/features/ui/util/react_router_helpers.js
+++ b/app/soapbox/features/ui/util/react_router_helpers.js
@@ -30,7 +30,7 @@ class WrappedRoute extends React.Component {
content: PropTypes.node,
componentParams: PropTypes.object,
layout: PropTypes.object,
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
settings: ImmutablePropTypes.map.isRequired,
publicRoute: PropTypes.bool,
staffOnly: PropTypes.bool,
diff --git a/app/soapbox/hooks/index.ts b/app/soapbox/hooks/index.ts
index 88f47b434..9fe270dd4 100644
--- a/app/soapbox/hooks/index.ts
+++ b/app/soapbox/hooks/index.ts
@@ -1 +1,2 @@
export { useAppSelector } from './useAppSelector';
+export { useOnScreen } from './useOnScreen';
diff --git a/app/soapbox/hooks/useOnScreen.ts b/app/soapbox/hooks/useOnScreen.ts
new file mode 100644
index 000000000..1ae207326
--- /dev/null
+++ b/app/soapbox/hooks/useOnScreen.ts
@@ -0,0 +1,19 @@
+import * as React from 'react';
+
+export const useOnScreen = (ref: React.MutableRefObject) => {
+ const [isIntersecting, setIntersecting] = React.useState(false);
+
+ const observer = new IntersectionObserver(
+ ([entry]) => setIntersecting(entry.isIntersecting),
+ );
+
+ React.useEffect(() => {
+ observer.observe(ref.current);
+
+ return () => {
+ observer.disconnect();
+ };
+ }, []);
+
+ return isIntersecting;
+};
diff --git a/app/soapbox/pages/groups_page.js b/app/soapbox/pages/groups_page.js
index 76a86c714..e11096abf 100644
--- a/app/soapbox/pages/groups_page.js
+++ b/app/soapbox/pages/groups_page.js
@@ -20,7 +20,7 @@ export default @connect(mapStateToProps)
class GroupsPage extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
};
render() {
diff --git a/app/soapbox/pages/profile_page.js b/app/soapbox/pages/profile_page.js
index 58c2d53bc..05960b6fe 100644
--- a/app/soapbox/pages/profile_page.js
+++ b/app/soapbox/pages/profile_page.js
@@ -68,7 +68,7 @@ export default @connect(mapStateToProps)
class ProfilePage extends ImmutablePureComponent {
static propTypes = {
- account: ImmutablePropTypes.map,
+ account: ImmutablePropTypes.record,
accountUsername: PropTypes.string.isRequired,
displayFqn: PropTypes.bool,
features: PropTypes.object,
diff --git a/app/styles/components/snackbar.scss b/app/styles/components/snackbar.scss
index da22a3ff3..7a397ef1e 100644
--- a/app/styles/components/snackbar.scss
+++ b/app/styles/components/snackbar.scss
@@ -40,7 +40,7 @@
}
.notification-bar-wrapper {
- @apply p-4 flex items-start;
+ @apply p-4 flex items-center justify-between w-full space-x-2;
}
.notification-bar-title {
@@ -50,3 +50,10 @@
.notification-bar-message {
@apply text-sm text-gray-700;
}
+
+.notification-bar-action a {
+ @apply inline-flex items-center px-2.5 py-1 border border-solid border-gray-300
+ shadow-sm text-xs font-medium rounded-full text-gray-700 bg-white
+ hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2
+ focus:ring-primary-500;
+}