about summary refs log tree commit diff
path: root/app/javascript/mastodon/features/ui/components
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2022-10-09 15:55:32 +0200
committerGitHub <noreply@github.com>2022-10-09 15:55:32 +0200
commit07653246223251052f5150e1e74139bf8ff41ec4 (patch)
treeb61d5697d912e366feadbf49ce44d4e57fa848f3 /app/javascript/mastodon/features/ui/components
parent2b00ccdbd555f9391aa87778f8b41eedcb7f8a04 (diff)
Fix intermediary responsive layout, accessibility on navigation in web UI (#19324)
* Fix intermediary responsive layout, accessibility on navigation in web UI

* `yarn test:jest -u`

Co-authored-by: Yamagishi Kazutoshi <ykzts@desire.sh>
Diffstat (limited to 'app/javascript/mastodon/features/ui/components')
-rw-r--r--app/javascript/mastodon/features/ui/components/column_link.js20
-rw-r--r--app/javascript/mastodon/features/ui/components/follow_requests_column_link.js (renamed from app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js)24
-rw-r--r--app/javascript/mastodon/features/ui/components/header.js3
-rw-r--r--app/javascript/mastodon/features/ui/components/navigation_panel.js59
4 files changed, 71 insertions, 35 deletions
diff --git a/app/javascript/mastodon/features/ui/components/column_link.js b/app/javascript/mastodon/features/ui/components/column_link.js
index 0a25f1ea2..42da05c0a 100644
--- a/app/javascript/mastodon/features/ui/components/column_link.js
+++ b/app/javascript/mastodon/features/ui/components/column_link.js
@@ -1,37 +1,41 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Link } from 'react-router-dom';
+import { NavLink } from 'react-router-dom';
 import Icon from 'mastodon/components/icon';
+import classNames from 'classnames';
 
-const ColumnLink = ({ icon, text, to, href, method, badge }) => {
+const ColumnLink = ({ icon, text, to, href, method, badge, transparent, ...other }) => {
+  const className = classNames('column-link', { 'column-link--transparent': transparent });
   const badgeElement = typeof badge !== 'undefined' ? <span className='column-link__badge'>{badge}</span> : null;
+  const iconElement = typeof icon === 'string' ? <Icon id={icon} fixedWidth className='column-link__icon' /> : icon;
 
   if (href) {
     return (
-      <a href={href} className='column-link' data-method={method}>
-        <Icon id={icon} fixedWidth className='column-link__icon' />
+      <a href={href} className={className} data-method={method} title={text} {...other}>
+        {iconElement}
         {text}
         {badgeElement}
       </a>
     );
   } else {
     return (
-      <Link to={to} className='column-link'>
-        <Icon id={icon} fixedWidth className='column-link__icon' />
+      <NavLink to={to} className={className} title={text} {...other}>
+        {iconElement}
         {text}
         {badgeElement}
-      </Link>
+      </NavLink>
     );
   }
 };
 
 ColumnLink.propTypes = {
-  icon: PropTypes.string.isRequired,
+  icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
   text: PropTypes.string.isRequired,
   to: PropTypes.string,
   href: PropTypes.string,
   method: PropTypes.string,
   badge: PropTypes.node,
+  transparent: PropTypes.bool,
 };
 
 export default ColumnLink;
diff --git a/app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js b/app/javascript/mastodon/features/ui/components/follow_requests_column_link.js
index 950ed7b27..8d4057782 100644
--- a/app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js
+++ b/app/javascript/mastodon/features/ui/components/follow_requests_column_link.js
@@ -2,22 +2,27 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { fetchFollowRequests } from 'mastodon/actions/accounts';
 import { connect } from 'react-redux';
-import { NavLink, withRouter } from 'react-router-dom';
+import ColumnLink from 'mastodon/features/ui/components/column_link';
 import IconWithBadge from 'mastodon/components/icon_with_badge';
 import { List as ImmutableList } from 'immutable';
-import { FormattedMessage } from 'react-intl';
+import { injectIntl, defineMessages } from 'react-intl';
+
+const messages = defineMessages({
+  text: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
+});
 
 const mapStateToProps = state => ({
   count: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size,
 });
 
-export default @withRouter
+export default @injectIntl
 @connect(mapStateToProps)
-class FollowRequestsNavLink extends React.Component {
+class FollowRequestsColumnLink extends React.Component {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
     count: PropTypes.number.isRequired,
+    intl: PropTypes.object.isRequired,
   };
 
   componentDidMount () {
@@ -27,13 +32,20 @@ class FollowRequestsNavLink extends React.Component {
   }
 
   render () {
-    const { count } = this.props;
+    const { count, intl } = this.props;
 
     if (count === 0) {
       return null;
     }
 
-    return <NavLink className='column-link column-link--transparent' to='/follow_requests'><IconWithBadge className='column-link__icon' id='user-plus' count={count} /><FormattedMessage id='navigation_bar.follow_requests' defaultMessage='Follow requests' /></NavLink>;
+    return (
+      <ColumnLink
+        transparent
+        to='/follow_requests'
+        icon={<IconWithBadge className='column-link__icon' id='user-plus' count={count} />}
+        text={intl.formatMessage(messages.text)}
+      />
+    );
   }
 
 }
diff --git a/app/javascript/mastodon/features/ui/components/header.js b/app/javascript/mastodon/features/ui/components/header.js
index cddab820c..c49f48cc9 100644
--- a/app/javascript/mastodon/features/ui/components/header.js
+++ b/app/javascript/mastodon/features/ui/components/header.js
@@ -11,8 +11,7 @@ import { connect } from 'react-redux';
 const Account = connect(state => ({
   account: state.getIn(['accounts', me]),
 }))(({ account }) => (
-  <Permalink href={account.get('url')} to={`/@${account.get('acct')}`}>
-    <span style={{ display: 'none' }}>{account.get('acct')}</span>
+  <Permalink href={account.get('url')} to={`/@${account.get('acct')}`} title={account.get('acct')}>
     <Avatar account={account} size={35} />
   </Permalink>
 ));
diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.js b/app/javascript/mastodon/features/ui/components/navigation_panel.js
index a9b80e71d..aa917c1ca 100644
--- a/app/javascript/mastodon/features/ui/components/navigation_panel.js
+++ b/app/javascript/mastodon/features/ui/components/navigation_panel.js
@@ -1,24 +1,45 @@
-import PropTypes from 'prop-types';
 import React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { Link, NavLink } from 'react-router-dom';
-import Icon from 'mastodon/components/icon';
+import PropTypes from 'prop-types';
+import { defineMessages, injectIntl } from 'react-intl';
+import { Link } from 'react-router-dom';
 import Logo from 'mastodon/components/logo';
 import TrendsContainer from 'mastodon/features/getting_started/containers/trends_container';
 import { showTrends, timelinePreview } from 'mastodon/initial_state';
-import FollowRequestsNavLink from './follow_requests_nav_link';
+import FollowRequestsColumnLink from './follow_requests_column_link';
 import ListPanel from './list_panel';
 import NotificationsCounterIcon from './notifications_counter_icon';
 import SignInBanner from './sign_in_banner';
+import ColumnLink from 'mastodon/features/ui/components/column_link';
+
+const messages = defineMessages({
+  home: { id: 'tabs_bar.home', defaultMessage: 'Home' },
+  notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
+  explore: { id: 'explore.title', defaultMessage: 'Explore' },
+  local: { id: 'tabs_bar.local_timeline', defaultMessage: 'Local' },
+  federated: { id: 'tabs_bar.federated_timeline', defaultMessage: 'Federated' },
+  direct: { id: 'navigation_bar.direct', defaultMessage: 'Direct messages' },
+  favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
+  bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' },
+  lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
+  preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
+  followsAndFollowers: { id: 'navigation_bar.follows_and_followers', defaultMessage: 'Follows and followers' },
+  about: { id: 'navigation_bar.about', defaultMessage: 'About' },
+});
 
-export default class NavigationPanel extends React.Component {
+export default @injectIntl
+class NavigationPanel extends React.Component {
 
   static contextTypes = {
     router: PropTypes.object.isRequired,
     identity: PropTypes.object.isRequired,
   };
 
+  static propTypes = {
+    intl: PropTypes.object.isRequired,
+  };
+
   render () {
+    const { intl } = this.props;
     const { signedIn } = this.context.identity;
 
     return (
@@ -30,17 +51,17 @@ export default class NavigationPanel extends React.Component {
 
         {signedIn && (
           <React.Fragment>
-            <NavLink className='column-link column-link--transparent' to='/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon className='column-link__icon' id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>
-            <NavLink className='column-link column-link--transparent' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon className='column-link__icon' /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>
-            <FollowRequestsNavLink />
+            <ColumnLink transparent to='/home' icon='home' text={intl.formatMessage(messages.home)} />
+            <ColumnLink transparent to='/notifications' icon={<NotificationsCounterIcon className='column-link__icon' />} text={intl.formatMessage(messages.notifications)} />
+            <FollowRequestsColumnLink />
           </React.Fragment>
         )}
 
-        <NavLink className='column-link column-link--transparent' to='/explore' data-preview-title-id='explore.title' data-preview-icon='hashtag'><Icon className='column-link__icon' id='hashtag' fixedWidth /><FormattedMessage id='explore.title' defaultMessage='Explore' /></NavLink>
+        <ColumnLink transparent to='/explore' icon='hashtag' text={intl.formatMessage(messages.explore)} />
         {signedIn || timelinePreview && (
           <>
-            <NavLink className='column-link column-link--transparent' to='/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>
-            <NavLink className='column-link column-link--transparent' exact to='/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon className='column-link__icon' id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>
+            <ColumnLink transparent to='/public/local' icon='users' text={intl.formatMessage(messages.local)} />
+            <ColumnLink transparent exact to='/public' icon='globe' text={intl.formatMessage(messages.federated)} />
           </>
         )}
 
@@ -53,23 +74,23 @@ export default class NavigationPanel extends React.Component {
 
         {signedIn && (
           <React.Fragment>
-            <NavLink className='column-link column-link--transparent' to='/conversations'><Icon className='column-link__icon' id='at' fixedWidth /><FormattedMessage id='navigation_bar.direct' defaultMessage='Direct messages' /></NavLink>
-            <NavLink className='column-link column-link--transparent' to='/favourites'><Icon className='column-link__icon' id='star' fixedWidth /><FormattedMessage id='navigation_bar.favourites' defaultMessage='Favourites' /></NavLink>
-            <NavLink className='column-link column-link--transparent' to='/bookmarks'><Icon className='column-link__icon' id='bookmark' fixedWidth /><FormattedMessage id='navigation_bar.bookmarks' defaultMessage='Bookmarks' /></NavLink>
-            <NavLink className='column-link column-link--transparent' to='/lists'><Icon className='column-link__icon' id='list-ul' fixedWidth /><FormattedMessage id='navigation_bar.lists' defaultMessage='Lists' /></NavLink>
+            <ColumnLink transparent to='/conversations' icon='at' text={intl.formatMessage(messages.direct)} />
+            <ColumnLink transparent to='/favourites' icon='star' text={intl.formatMessage(messages.favourites)} />
+            <ColumnLink transparent to='/bookmarks' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} />
+            <ColumnLink transparent to='/lists' icon='list-ul' text={intl.formatMessage(messages.lists)} />
 
             <ListPanel />
 
             <hr />
 
-            <a className='column-link column-link--transparent' href='/settings/preferences'><Icon className='column-link__icon' id='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a>
-            <a className='column-link column-link--transparent' href='/relationships'><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a>
+            <ColumnLink transparent href='/settings/preferences' icon='cog' text={intl.formatMessage(messages.preferences)} />
+            <ColumnLink transparent href='/relationships' icon='users' text={intl.formatMessage(messages.followsAndFollowers)} />
           </React.Fragment>
         )}
 
         <div className='navigation-panel__legal'>
           <hr />
-          <NavLink className='column-link column-link--transparent' to='/about'><Icon className='column-link__icon' id='ellipsis-h' fixedWidth /><FormattedMessage id='navigation_bar.about' defaultMessage='About' /></NavLink>
+          <ColumnLink transparent to='/about' icon='ellipsis-h' text={intl.formatMessage(messages.about)} />
         </div>
 
         {showTrends && (