From 07653246223251052f5150e1e74139bf8ff41ec4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 9 Oct 2022 15:55:32 +0200 Subject: [PATCH] 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 --- .../__snapshots__/avatar-test.js.snap | 4 ++ app/javascript/mastodon/components/avatar.js | 2 + app/javascript/mastodon/components/logo.js | 3 +- .../features/ui/components/column_link.js | 20 ++++--- ...link.js => follow_requests_column_link.js} | 24 ++++++-- .../mastodon/features/ui/components/header.js | 3 +- .../ui/components/navigation_panel.js | 59 +++++++++++++------ .../styles/mastodon/components.scss | 34 +++++++++-- app/javascript/styles/mastodon/variables.scss | 2 +- 9 files changed, 109 insertions(+), 42 deletions(-) rename app/javascript/mastodon/features/ui/components/{follow_requests_nav_link.js => follow_requests_column_link.js} (52%) diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap index 1c200b1848..f5c10aa377 100644 --- a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap @@ -2,9 +2,11 @@ exports[` Autoplay renders a animated avatar 1`] = `
Autoplay renders a animated avatar 1`] = ` exports[` Still renders a still avatar 1`] = `
); } diff --git a/app/javascript/mastodon/components/logo.js b/app/javascript/mastodon/components/logo.js index 3570b3644b..ee5c22496c 100644 --- a/app/javascript/mastodon/components/logo.js +++ b/app/javascript/mastodon/components/logo.js @@ -1,7 +1,8 @@ import React from 'react'; const Logo = () => ( - + + Mastodon ); diff --git a/app/javascript/mastodon/features/ui/components/column_link.js b/app/javascript/mastodon/features/ui/components/column_link.js index 0a25f1ea20..42da05c0ac 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' ? {badge} : null; + const iconElement = typeof icon === 'string' ? : icon; if (href) { return ( - - + + {iconElement} {text} {badgeElement} ); } else { return ( - - + + {iconElement} {text} {badgeElement} - + ); } }; 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 similarity index 52% rename from app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js rename to app/javascript/mastodon/features/ui/components/follow_requests_column_link.js index 950ed7b273..8d4057782c 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 ; + return ( + } + 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 cddab820c6..c49f48cc98 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 }) => ( - - {account.get('acct')} + )); diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.js b/app/javascript/mastodon/features/ui/components/navigation_panel.js index a9b80e71db..aa917c1ca5 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'; -export default class NavigationPanel extends React.Component { +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 @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 && ( - - - + + } text={intl.formatMessage(messages.notifications)} /> + )} - + {signedIn || timelinePreview && ( <> - - + + )} @@ -53,23 +74,23 @@ export default class NavigationPanel extends React.Component { {signedIn && ( - - - - + + + +
- - + +
)}

- +
{showTrends && ( diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 02c2a14bff..039d0b9041 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -2604,12 +2604,14 @@ $ui-header-height: 55px; } @media screen and (max-width: $no-gap-breakpoint - 1px) { + $sidebar-width: 285px; + .with-fab .scrollable .item-list:last-child { padding-bottom: 5.25rem; } .columns-area__panels__main { - width: calc(100% - 55px); + width: calc(100% - $sidebar-width); } .columns-area__panels { @@ -2617,10 +2619,10 @@ $ui-header-height: 55px; } .columns-area__panels__pane--navigational { - min-width: 55px; + min-width: $sidebar-width; .columns-area__panels__pane__inner { - width: 55px; + width: $sidebar-width; } .navigation-panel { @@ -2630,7 +2632,6 @@ $ui-header-height: 55px; height: 100vh; } - .column-link span, .navigation-panel__sign-in-banner, .navigation-panel__logo, .getting-started__trends { @@ -2655,11 +2656,31 @@ $ui-header-height: 55px; } } +@media screen and (max-width: $no-gap-breakpoint - 285px - 1px) { + $sidebar-width: 55px; + + .columns-area__panels__main { + width: calc(100% - $sidebar-width); + } + + .columns-area__panels__pane--navigational { + min-width: $sidebar-width; + + .columns-area__panels__pane__inner { + width: $sidebar-width; + } + + .column-link span { + display: none; + } + } +} + .explore__search-header { display: none; } -@media screen and (max-width: $no-gap-breakpoint + 285px - 1px) { +@media screen and (max-width: $no-gap-breakpoint - 1px) { .columns-area__panels__pane--compositional { display: none; } @@ -3145,6 +3166,9 @@ $ui-header-height: 55px; font-size: 16px; padding: 15px; text-decoration: none; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; &:hover, &:focus, diff --git a/app/javascript/styles/mastodon/variables.scss b/app/javascript/styles/mastodon/variables.scss index 775a12e687..2f6c41d5f2 100644 --- a/app/javascript/styles/mastodon/variables.scss +++ b/app/javascript/styles/mastodon/variables.scss @@ -53,7 +53,7 @@ $media-modal-media-max-width: 100%; // put margins on top and bottom of image to avoid the screen covered by image. $media-modal-media-max-height: 80%; -$no-gap-breakpoint: 890px; +$no-gap-breakpoint: 1175px; $font-sans-serif: 'mastodon-font-sans-serif' !default; $font-display: 'mastodon-font-display' !default;