diff --git a/app/soapbox/components/account.tsx b/app/soapbox/components/account.tsx index a1c428c39..cd8ee546e 100644 --- a/app/soapbox/components/account.tsx +++ b/app/soapbox/components/account.tsx @@ -96,18 +96,16 @@ const Account = ({ }; React.useEffect(() => { - if (isOnScreen) { - const style: React.CSSProperties = {}; - const actionWidth = actionRef.current?.clientWidth || 0; + const style: React.CSSProperties = {}; + const actionWidth = actionRef.current?.clientWidth || 0; - if (overflowRef.current) { - style.maxWidth = overflowRef.current.clientWidth - 30 - avatarSize - actionWidth; - } else { - style.visibility = 'hidden'; - } - - setStyle(style); + if (overflowRef.current) { + style.maxWidth = overflowRef.current.clientWidth - 30 - avatarSize - actionWidth; + } else { + style.visibility = 'hidden'; } + + setStyle(style); }, [isOnScreen, overflowRef, actionRef]); if (!account) { diff --git a/app/soapbox/components/helmet.js b/app/soapbox/components/helmet.js deleted file mode 100644 index 9e86883b4..000000000 --- a/app/soapbox/components/helmet.js +++ /dev/null @@ -1,87 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import { Helmet } from'react-helmet'; -import { connect } from 'react-redux'; -import { withRouter } from 'react-router-dom'; - -import { getSettings } from 'soapbox/actions/settings'; -// import sourceCode from 'soapbox/utils/code'; -import FaviconService from 'soapbox/utils/favicon_service'; - -FaviconService.initFaviconService(); - -const getNotifTotals = state => { - const notifications = state.getIn(['notifications', 'unread'], 0); - const chats = state.getIn(['chats', 'items']).reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0); - const reports = state.getIn(['admin', 'openReports']).count(); - const approvals = state.getIn(['admin', 'awaitingApproval']).count(); - return notifications + chats + reports + approvals; -}; - -const mapStateToProps = state => { - const settings = getSettings(state); - - return { - siteTitle: state.getIn(['instance', 'title']), - unreadCount: getNotifTotals(state), - demetricator: settings.get('demetricator'), - }; -}; - -class SoapboxHelmet extends React.Component { - - static propTypes = { - siteTitle: PropTypes.string, - children: PropTypes.node, - unreadCount: PropTypes.number, - demetricator: PropTypes.bool, - }; - - hasUnread = () => { - const { unreadCount, demetricator } = this.props; - return !(unreadCount < 1 || demetricator); - } - - addCounter = title => { - const { unreadCount } = this.props; - const hasUnread = this.hasUnread(); - return hasUnread ? `(${unreadCount}) ${title}` : title; - } - - updateFaviconBadge = () => { - const hasUnread = this.hasUnread(); - - if (hasUnread) { - FaviconService.drawFaviconBadge(); - } else { - FaviconService.clearFaviconBadge(); - } - } - - componentDidUpdate(prevProps) { - if (this.props.unreadCount !== prevProps.unreadCount || this.props.demetricator !== prevProps.demetricator) { - this.updateFaviconBadge(); - } - } - - componentDidMount() { - this.updateFaviconBadge(); - } - - render() { - const { siteTitle, children } = this.props; - - return ( - - {children} - - ); - } - -} - -export default withRouter(connect(mapStateToProps)(SoapboxHelmet)); diff --git a/app/soapbox/components/helmet.tsx b/app/soapbox/components/helmet.tsx new file mode 100644 index 000000000..7eee6538c --- /dev/null +++ b/app/soapbox/components/helmet.tsx @@ -0,0 +1,53 @@ +import * as React from 'react'; +import { Helmet as ReactHelmet } from'react-helmet'; + +import { useAppSelector, useSettings } from 'soapbox/hooks'; +import FaviconService from 'soapbox/utils/favicon_service'; + +FaviconService.initFaviconService(); + +const getNotifTotals = (state: any) => { + const notifications = state.getIn(['notifications', 'unread'], 0); + const chats = state.getIn(['chats', 'items']).reduce((acc: any, curr: any) => acc + Math.min(curr.get('unread', 0), 1), 0); + const reports = state.getIn(['admin', 'openReports']).count(); + const approvals = state.getIn(['admin', 'awaitingApproval']).count(); + return notifications + chats + reports + approvals; +}; + +const Helmet: React.FC = ({ children }) => { + const settings = useSettings(); + + const title = useAppSelector((state) => state.instance.get('title')); + const unreadCount = useAppSelector((state) => getNotifTotals(state)); + const demetricator = useAppSelector((state) => settings.get('demetricator')); + + const hasUnreadNotifications = React.useMemo(() => !(unreadCount < 1 || demetricator), [unreadCount, demetricator]); + + const addCounter = (string: string) => { + return hasUnreadNotifications ? `(${unreadCount}) ${title}` : title; + }; + + const updateFaviconBadge = () => { + if (hasUnreadNotifications) { + FaviconService.drawFaviconBadge(); + } else { + FaviconService.clearFaviconBadge(); + } + }; + + React.useEffect(() => { + updateFaviconBadge(); + }, [unreadCount, demetricator]); + + return ( + + {children} + + ); +}; + +export default Helmet; diff --git a/app/soapbox/containers/soapbox.js b/app/soapbox/containers/soapbox.js index f9ddf8bb1..c1a7db84e 100644 --- a/app/soapbox/containers/soapbox.js +++ b/app/soapbox/containers/soapbox.js @@ -166,15 +166,16 @@ class SoapboxMount extends React.PureComponent { return ( + + + + {themeCss && } + + + <> - - - - {themeCss && } - - diff --git a/app/soapbox/features/followers/index.js b/app/soapbox/features/followers/index.js index d8fd3656a..aa7067b5c 100644 --- a/app/soapbox/features/followers/index.js +++ b/app/soapbox/features/followers/index.js @@ -105,19 +105,15 @@ class Followers extends ImmutablePureComponent { if (accountId === -1 || (!accountIds)) { return ( - - - + ); } if (unavailable) { return ( - -
- -
-
+
+ +
); } diff --git a/app/soapbox/features/following/index.js b/app/soapbox/features/following/index.js index 4cb034fc7..cfa7c2741 100644 --- a/app/soapbox/features/following/index.js +++ b/app/soapbox/features/following/index.js @@ -105,19 +105,15 @@ class Following extends ImmutablePureComponent { if (accountId === -1 || (!accountIds)) { return ( - - - + ); } if (unavailable) { return ( - -
- -
-
+
+ +
); } diff --git a/app/soapbox/features/ui/components/profile_info_panel.js b/app/soapbox/features/ui/components/profile_info_panel.js index 41fef805e..1f57ed483 100644 --- a/app/soapbox/features/ui/components/profile_info_panel.js +++ b/app/soapbox/features/ui/components/profile_info_panel.js @@ -186,7 +186,7 @@ class ProfileInfoPanel extends ImmutablePureComponent { } -
+
{isLocal(account) ? ( - - {isSafeUrl(account.get('website')) ? ( - {account.get('website')} - ) : ( - account.get('website') - )} - +
+ + {isSafeUrl(account.get('website')) ? ( + {account.get('website')} + ) : ( + account.get('website') + )} + +
) : null} diff --git a/package.json b/package.json index f4baa47fc..4ec9a6372 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "@types/escape-html": "^1.0.1", "@types/http-link-header": "^1.0.3", "@types/lodash": "^4.14.180", + "@types/react-helmet": "^6.1.5", "@types/react-router-dom": "^5.3.3", "@types/uuid": "^8.3.4", "array-includes": "^3.0.3", diff --git a/yarn.lock b/yarn.lock index 8cb374efb..26d2650a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2095,6 +2095,13 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== +"@types/react-helmet@^6.1.5": + version "6.1.5" + resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.1.5.tgz#35f89a6b1646ee2bc342a33a9a6c8777933f9083" + integrity sha512-/ICuy7OHZxR0YCAZLNg9r7I9aijWUWvxaPR6uTuyxe8tAj5RL4Sw1+R6NhXUtOsarkGYPmaHdBDvuXh2DIN/uA== + dependencies: + "@types/react" "*" + "@types/react-redux@^7.1.16": version "7.1.18" resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.18.tgz#2bf8fd56ebaae679a90ebffe48ff73717c438e04"