Change icons in web UI (#27385)
Co-authored-by: Renaud Chaput <renchap@gmail.com>
This commit is contained in:
		
							
								
								
									
										3
									
								
								app/javascript/__mocks__/svg.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/javascript/__mocks__/svg.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					// eslint-disable-next-line import/no-anonymous-default-export
 | 
				
			||||||
 | 
					export default 'SvgrURL';
 | 
				
			||||||
 | 
					export const ReactComponent = 'div';
 | 
				
			||||||
@@ -18,7 +18,6 @@ import { Avatar } from './avatar';
 | 
				
			|||||||
import { Button } from './button';
 | 
					import { Button } from './button';
 | 
				
			||||||
import { FollowersCounter } from './counters';
 | 
					import { FollowersCounter } from './counters';
 | 
				
			||||||
import { DisplayName } from './display_name';
 | 
					import { DisplayName } from './display_name';
 | 
				
			||||||
import { IconButton } from './icon_button';
 | 
					 | 
				
			||||||
import { RelativeTimestamp } from './relative_timestamp';
 | 
					import { RelativeTimestamp } from './relative_timestamp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
@@ -45,10 +44,7 @@ class Account extends ImmutablePureComponent {
 | 
				
			|||||||
    intl: PropTypes.object.isRequired,
 | 
					    intl: PropTypes.object.isRequired,
 | 
				
			||||||
    hidden: PropTypes.bool,
 | 
					    hidden: PropTypes.bool,
 | 
				
			||||||
    minimal: PropTypes.bool,
 | 
					    minimal: PropTypes.bool,
 | 
				
			||||||
    actionIcon: PropTypes.string,
 | 
					 | 
				
			||||||
    actionTitle: PropTypes.string,
 | 
					 | 
				
			||||||
    defaultAction: PropTypes.string,
 | 
					    defaultAction: PropTypes.string,
 | 
				
			||||||
    onActionClick: PropTypes.func,
 | 
					 | 
				
			||||||
    withBio: PropTypes.bool,
 | 
					    withBio: PropTypes.bool,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -76,12 +72,8 @@ class Account extends ImmutablePureComponent {
 | 
				
			|||||||
    this.props.onMuteNotifications(this.props.account, false);
 | 
					    this.props.onMuteNotifications(this.props.account, false);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleAction = () => {
 | 
					 | 
				
			||||||
    this.props.onActionClick(this.props.account);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { account, intl, hidden, withBio, onActionClick, actionIcon, actionTitle, defaultAction, size, minimal } = this.props;
 | 
					    const { account, intl, hidden, withBio, defaultAction, size, minimal } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!account) {
 | 
					    if (!account) {
 | 
				
			||||||
      return <EmptyAccount size={size} minimal={minimal} />;
 | 
					      return <EmptyAccount size={size} minimal={minimal} />;
 | 
				
			||||||
@@ -98,9 +90,7 @@ class Account extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let buttons;
 | 
					    let buttons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (actionIcon && onActionClick) {
 | 
					    if (account.get('id') !== me && account.get('relationship', null) !== null) {
 | 
				
			||||||
      buttons = <IconButton icon={actionIcon} title={actionTitle} onClick={this.handleAction} />;
 | 
					 | 
				
			||||||
    } else if (!actionIcon && account.get('id') !== me && account.get('relationship', null) !== null) {
 | 
					 | 
				
			||||||
      const following = account.getIn(['relationship', 'following']);
 | 
					      const following = account.getIn(['relationship', 'following']);
 | 
				
			||||||
      const requested = account.getIn(['relationship', 'requested']);
 | 
					      const requested = account.getIn(['relationship', 'requested']);
 | 
				
			||||||
      const blocking  = account.getIn(['relationship', 'blocking']);
 | 
					      const blocking  = account.getIn(['relationship', 'blocking']);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@ import classNames from 'classnames';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as LinkIcon } from '@material-symbols/svg-600/outlined/link.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
 | 
					const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
 | 
				
			||||||
@@ -25,7 +27,7 @@ export default class AttachmentList extends ImmutablePureComponent {
 | 
				
			|||||||
      <div className={classNames('attachment-list', { compact })}>
 | 
					      <div className={classNames('attachment-list', { compact })}>
 | 
				
			||||||
        {!compact && (
 | 
					        {!compact && (
 | 
				
			||||||
          <div className='attachment-list__icon'>
 | 
					          <div className='attachment-list__icon'>
 | 
				
			||||||
            <Icon id='link' />
 | 
					            <Icon id='link' icon={LinkIcon} />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,7 +38,7 @@ export default class AttachmentList extends ImmutablePureComponent {
 | 
				
			|||||||
            return (
 | 
					            return (
 | 
				
			||||||
              <li key={attachment.get('id')}>
 | 
					              <li key={attachment.get('id')}>
 | 
				
			||||||
                <a href={displayUrl} target='_blank' rel='noopener noreferrer'>
 | 
					                <a href={displayUrl} target='_blank' rel='noopener noreferrer'>
 | 
				
			||||||
                  {compact && <Icon id='link' />}
 | 
					                  {compact && <Icon id='link' icon={LinkIcon} />}
 | 
				
			||||||
                  {compact && ' ' }
 | 
					                  {compact && ' ' }
 | 
				
			||||||
                  {displayUrl ? filename(displayUrl) : <FormattedMessage id='attachments_list.unprocessed' defaultMessage='(unprocessed)' />}
 | 
					                  {displayUrl ? filename(displayUrl) : <FormattedMessage id='attachments_list.unprocessed' defaultMessage='(unprocessed)' />}
 | 
				
			||||||
                </a>
 | 
					                </a>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,9 +2,9 @@ import PropTypes from 'prop-types';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { FormattedMessage } from 'react-intl';
 | 
					import { FormattedMessage } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { ReactComponent as GroupsIcon } from '@material-design-icons/svg/outlined/group.svg';
 | 
					import { ReactComponent as GroupsIcon } from '@material-symbols/svg-600/outlined/group.svg';
 | 
				
			||||||
import { ReactComponent as PersonIcon } from '@material-design-icons/svg/outlined/person.svg';
 | 
					import { ReactComponent as PersonIcon } from '@material-symbols/svg-600/outlined/person.svg';
 | 
				
			||||||
import { ReactComponent as SmartToyIcon } from '@material-design-icons/svg/outlined/smart_toy.svg';
 | 
					import { ReactComponent as SmartToyIcon } from '@material-symbols/svg-600/outlined/smart_toy.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Badge = ({ icon, label, domain }) => (
 | 
					export const Badge = ({ icon, label, domain }) => (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
export const Check: React.FC = () => (
 | 
					 | 
				
			||||||
  <svg
 | 
					 | 
				
			||||||
    xmlns='http://www.w3.org/2000/svg'
 | 
					 | 
				
			||||||
    viewBox='0 0 20 20'
 | 
					 | 
				
			||||||
    fill='currentColor'
 | 
					 | 
				
			||||||
  >
 | 
					 | 
				
			||||||
    <path
 | 
					 | 
				
			||||||
      fillRule='evenodd'
 | 
					 | 
				
			||||||
      d='M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z'
 | 
					 | 
				
			||||||
      clipRule='evenodd'
 | 
					 | 
				
			||||||
    />
 | 
					 | 
				
			||||||
  </svg>
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
@@ -6,6 +6,8 @@ import { FormattedMessage } from 'react-intl';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { withRouter } from 'react-router-dom';
 | 
					import { withRouter } from 'react-router-dom';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
					import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,7 +36,7 @@ class ColumnBackButton extends PureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const component = (
 | 
					    const component = (
 | 
				
			||||||
      <button onClick={this.handleClick} className='column-back-button'>
 | 
					      <button onClick={this.handleClick} className='column-back-button'>
 | 
				
			||||||
        <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
 | 
					        <Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
 | 
				
			||||||
        <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
 | 
					        <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
import { FormattedMessage } from 'react-intl';
 | 
					import { FormattedMessage } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ColumnBackButton from './column_back_button';
 | 
					import ColumnBackButton from './column_back_button';
 | 
				
			||||||
@@ -10,7 +12,7 @@ export default class ColumnBackButtonSlim extends ColumnBackButton {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='column-back-button--slim'>
 | 
					      <div className='column-back-button--slim'>
 | 
				
			||||||
        <div role='button' tabIndex={0} onClick={this.handleClick} className='column-back-button column-back-button--slim-button'>
 | 
					        <div role='button' tabIndex={0} onClick={this.handleClick} className='column-back-button column-back-button--slim-button'>
 | 
				
			||||||
          <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
 | 
					          <Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
 | 
				
			||||||
          <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
 | 
					          <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,13 @@ import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
 | 
				
			|||||||
import classNames from 'classnames';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
import { withRouter } from 'react-router-dom';
 | 
					import { withRouter } from 'react-router-dom';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ChevronLeftIcon } from '@material-symbols/svg-600/outlined/chevron_left.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ChevronRightIcon } from '@material-symbols/svg-600/outlined/chevron_right.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as TuneIcon } from '@material-symbols/svg-600/outlined/tune.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
					import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -27,6 +34,7 @@ class ColumnHeader extends PureComponent {
 | 
				
			|||||||
    intl: PropTypes.object.isRequired,
 | 
					    intl: PropTypes.object.isRequired,
 | 
				
			||||||
    title: PropTypes.node,
 | 
					    title: PropTypes.node,
 | 
				
			||||||
    icon: PropTypes.string,
 | 
					    icon: PropTypes.string,
 | 
				
			||||||
 | 
					    iconComponent: PropTypes.func,
 | 
				
			||||||
    active: PropTypes.bool,
 | 
					    active: PropTypes.bool,
 | 
				
			||||||
    multiColumn: PropTypes.bool,
 | 
					    multiColumn: PropTypes.bool,
 | 
				
			||||||
    extraButton: PropTypes.node,
 | 
					    extraButton: PropTypes.node,
 | 
				
			||||||
@@ -87,7 +95,7 @@ class ColumnHeader extends PureComponent {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { title, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues, history } = this.props;
 | 
					    const { title, icon, iconComponent, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues, history } = this.props;
 | 
				
			||||||
    const { collapsed, animating } = this.state;
 | 
					    const { collapsed, animating } = this.state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const wrapperClassName = classNames('column-header__wrapper', {
 | 
					    const wrapperClassName = classNames('column-header__wrapper', {
 | 
				
			||||||
@@ -118,22 +126,22 @@ class ColumnHeader extends PureComponent {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (multiColumn && pinned) {
 | 
					    if (multiColumn && pinned) {
 | 
				
			||||||
      pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='times' /> <FormattedMessage id='column_header.unpin' defaultMessage='Unpin' /></button>;
 | 
					      pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='times' icon={CloseIcon} /> <FormattedMessage id='column_header.unpin' defaultMessage='Unpin' /></button>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      moveButtons = (
 | 
					      moveButtons = (
 | 
				
			||||||
        <div key='move-buttons' className='column-header__setting-arrows'>
 | 
					        <div key='move-buttons' className='column-header__setting-arrows'>
 | 
				
			||||||
          <button title={formatMessage(messages.moveLeft)} aria-label={formatMessage(messages.moveLeft)} className='icon-button column-header__setting-btn' onClick={this.handleMoveLeft}><Icon id='chevron-left' /></button>
 | 
					          <button title={formatMessage(messages.moveLeft)} aria-label={formatMessage(messages.moveLeft)} className='icon-button column-header__setting-btn' onClick={this.handleMoveLeft}><Icon id='chevron-left' icon={ChevronLeftIcon} /></button>
 | 
				
			||||||
          <button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='icon-button column-header__setting-btn' onClick={this.handleMoveRight}><Icon id='chevron-right' /></button>
 | 
					          <button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='icon-button column-header__setting-btn' onClick={this.handleMoveRight}><Icon id='chevron-right' icon={ChevronRightIcon} /></button>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else if (multiColumn && this.props.onPin) {
 | 
					    } else if (multiColumn && this.props.onPin) {
 | 
				
			||||||
      pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
 | 
					      pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' icon={AddIcon} /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!pinned && ((multiColumn && history.location?.state?.fromMastodon) || showBackButton)) {
 | 
					    if (!pinned && ((multiColumn && history.location?.state?.fromMastodon) || showBackButton)) {
 | 
				
			||||||
      backButton = (
 | 
					      backButton = (
 | 
				
			||||||
        <button onClick={this.handleBackClick} className='column-header__back-button'>
 | 
					        <button onClick={this.handleBackClick} className='column-header__back-button'>
 | 
				
			||||||
          <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
 | 
					          <Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
 | 
				
			||||||
          <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
 | 
					          <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -157,21 +165,21 @@ class ColumnHeader extends PureComponent {
 | 
				
			|||||||
          onClick={this.handleToggleClick}
 | 
					          onClick={this.handleToggleClick}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <i className='icon-with-badge'>
 | 
					          <i className='icon-with-badge'>
 | 
				
			||||||
            <Icon id='sliders' />
 | 
					            <Icon id='sliders' icon={TuneIcon} />
 | 
				
			||||||
            {collapseIssues && <i className='icon-with-badge__issue-badge' />}
 | 
					            {collapseIssues && <i className='icon-with-badge__issue-badge' />}
 | 
				
			||||||
          </i>
 | 
					          </i>
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const hasTitle = icon && title;
 | 
					    const hasTitle = (icon || iconComponent) && title;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const component = (
 | 
					    const component = (
 | 
				
			||||||
      <div className={wrapperClassName}>
 | 
					      <div className={wrapperClassName}>
 | 
				
			||||||
        <h1 className={buttonClassName}>
 | 
					        <h1 className={buttonClassName}>
 | 
				
			||||||
          {hasTitle && (
 | 
					          {hasTitle && (
 | 
				
			||||||
            <button onClick={this.handleTitleClick}>
 | 
					            <button onClick={this.handleTitleClick}>
 | 
				
			||||||
              <Icon id={icon} fixedWidth className='column-header__icon' />
 | 
					              <Icon id={icon} icon={iconComponent} className='column-header__icon' />
 | 
				
			||||||
              {title}
 | 
					              {title}
 | 
				
			||||||
            </button>
 | 
					            </button>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,8 @@ import { useCallback, useState } from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { defineMessages, useIntl } from 'react-intl';
 | 
					import { defineMessages, useIntl } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { bannerSettings } from 'mastodon/settings';
 | 
					import { bannerSettings } from 'mastodon/settings';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { IconButton } from './icon_button';
 | 
					import { IconButton } from './icon_button';
 | 
				
			||||||
@@ -36,6 +38,7 @@ export const DismissableBanner: React.FC<PropsWithChildren<Props>> = ({
 | 
				
			|||||||
      <div className='dismissable-banner__action'>
 | 
					      <div className='dismissable-banner__action'>
 | 
				
			||||||
        <IconButton
 | 
					        <IconButton
 | 
				
			||||||
          icon='times'
 | 
					          icon='times'
 | 
				
			||||||
 | 
					          iconComponent={CloseIcon}
 | 
				
			||||||
          title={intl.formatMessage(messages.dismiss)}
 | 
					          title={intl.formatMessage(messages.dismiss)}
 | 
				
			||||||
          onClick={handleDismiss}
 | 
					          onClick={handleDismiss}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,8 @@ import { useCallback } from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { defineMessages, useIntl } from 'react-intl';
 | 
					import { defineMessages, useIntl } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as LockOpenIcon } from '@material-symbols/svg-600/outlined/lock_open.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { IconButton } from './icon_button';
 | 
					import { IconButton } from './icon_button';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
@@ -34,6 +36,7 @@ export const Domain: React.FC<Props> = ({ domain, onUnblockDomain }) => {
 | 
				
			|||||||
          <IconButton
 | 
					          <IconButton
 | 
				
			||||||
            active
 | 
					            active
 | 
				
			||||||
            icon='unlock'
 | 
					            icon='unlock'
 | 
				
			||||||
 | 
					            iconComponent={LockOpenIcon}
 | 
				
			||||||
            title={intl.formatMessage(messages.unblockDomain, { domain })}
 | 
					            title={intl.formatMessage(messages.unblockDomain, { domain })}
 | 
				
			||||||
            onClick={handleDomainUnblock}
 | 
					            onClick={handleDomainUnblock}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ import { withRouter } from 'react-router-dom';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
import { supportsPassiveEvents } from 'detect-passive-events';
 | 
					import { supportsPassiveEvents } from 'detect-passive-events';
 | 
				
			||||||
import Overlay from 'react-overlays/Overlay';
 | 
					import Overlay from 'react-overlays/Overlay';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -163,6 +164,7 @@ class Dropdown extends PureComponent {
 | 
				
			|||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    children: PropTypes.node,
 | 
					    children: PropTypes.node,
 | 
				
			||||||
    icon: PropTypes.string,
 | 
					    icon: PropTypes.string,
 | 
				
			||||||
 | 
					    iconComponent: PropTypes.func,
 | 
				
			||||||
    items: PropTypes.oneOfType([PropTypes.array, ImmutablePropTypes.list]).isRequired,
 | 
					    items: PropTypes.oneOfType([PropTypes.array, ImmutablePropTypes.list]).isRequired,
 | 
				
			||||||
    loading: PropTypes.bool,
 | 
					    loading: PropTypes.bool,
 | 
				
			||||||
    size: PropTypes.number,
 | 
					    size: PropTypes.number,
 | 
				
			||||||
@@ -255,7 +257,7 @@ class Dropdown extends PureComponent {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  findTarget = () => {
 | 
					  findTarget = () => {
 | 
				
			||||||
    return this.target;
 | 
					    return this.target?.buttonRef?.current;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentWillUnmount = () => {
 | 
					  componentWillUnmount = () => {
 | 
				
			||||||
@@ -271,6 +273,7 @@ class Dropdown extends PureComponent {
 | 
				
			|||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const {
 | 
					    const {
 | 
				
			||||||
      icon,
 | 
					      icon,
 | 
				
			||||||
 | 
					      iconComponent,
 | 
				
			||||||
      items,
 | 
					      items,
 | 
				
			||||||
      size,
 | 
					      size,
 | 
				
			||||||
      title,
 | 
					      title,
 | 
				
			||||||
@@ -291,9 +294,11 @@ class Dropdown extends PureComponent {
 | 
				
			|||||||
      onMouseDown: this.handleMouseDown,
 | 
					      onMouseDown: this.handleMouseDown,
 | 
				
			||||||
      onKeyDown: this.handleButtonKeyDown,
 | 
					      onKeyDown: this.handleButtonKeyDown,
 | 
				
			||||||
      onKeyPress: this.handleKeyPress,
 | 
					      onKeyPress: this.handleKeyPress,
 | 
				
			||||||
 | 
					      ref: this.setTargetRef,
 | 
				
			||||||
    }) : (
 | 
					    }) : (
 | 
				
			||||||
      <IconButton
 | 
					      <IconButton
 | 
				
			||||||
        icon={!open ? icon : 'close'}
 | 
					        icon={!open ? icon : 'close'}
 | 
				
			||||||
 | 
					        iconComponent={!open ? iconComponent : CloseIcon}
 | 
				
			||||||
        title={title}
 | 
					        title={title}
 | 
				
			||||||
        active={open}
 | 
					        active={open}
 | 
				
			||||||
        disabled={disabled}
 | 
					        disabled={disabled}
 | 
				
			||||||
@@ -302,14 +307,14 @@ class Dropdown extends PureComponent {
 | 
				
			|||||||
        onMouseDown={this.handleMouseDown}
 | 
					        onMouseDown={this.handleMouseDown}
 | 
				
			||||||
        onKeyDown={this.handleButtonKeyDown}
 | 
					        onKeyDown={this.handleButtonKeyDown}
 | 
				
			||||||
        onKeyPress={this.handleKeyPress}
 | 
					        onKeyPress={this.handleKeyPress}
 | 
				
			||||||
 | 
					        ref={this.setTargetRef}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <>
 | 
					      <>
 | 
				
			||||||
        <span ref={this.setTargetRef}>
 | 
					        {button}
 | 
				
			||||||
          {button}
 | 
					
 | 
				
			||||||
        </span>
 | 
					 | 
				
			||||||
        <Overlay show={open} offset={[5, 5]} placement={'bottom'} flip target={this.findTarget} popperConfig={{ strategy: 'fixed' }}>
 | 
					        <Overlay show={open} offset={[5, 5]} placement={'bottom'} flip target={this.findTarget} popperConfig={{ strategy: 'fixed' }}>
 | 
				
			||||||
          {({ props, arrowProps, placement }) => (
 | 
					          {({ props, arrowProps, placement }) => (
 | 
				
			||||||
            <div {...props}>
 | 
					            <div {...props}>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@ import { FormattedMessage, injectIntl } from 'react-intl';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as ArrowDropDownIcon } from '@material-symbols/svg-600/outlined/arrow_drop_down.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { openModal } from 'mastodon/actions/modal';
 | 
					import { openModal } from 'mastodon/actions/modal';
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import InlineAccount from 'mastodon/components/inline_account';
 | 
					import InlineAccount from 'mastodon/components/inline_account';
 | 
				
			||||||
@@ -66,7 +68,7 @@ class EditedTimestamp extends PureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <DropdownMenu statusId={statusId} renderItem={this.renderItem} scrollable renderHeader={this.renderHeader} onItemClick={this.handleItemClick}>
 | 
					      <DropdownMenu statusId={statusId} renderItem={this.renderItem} scrollable renderHeader={this.renderHeader} onItemClick={this.handleItemClick}>
 | 
				
			||||||
        <button className='dropdown-menu__text-button'>
 | 
					        <button className='dropdown-menu__text-button'>
 | 
				
			||||||
          <FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: intl.formatDate(timestamp, { hour12: false, month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) }} /> <Icon id='caret-down' />
 | 
					          <FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: intl.formatDate(timestamp, { hour12: false, month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) }} /> <Icon id='caret-down' icon={ArrowDropDownIcon} />
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      </DropdownMenu>
 | 
					      </DropdownMenu>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,50 @@
 | 
				
			|||||||
import classNames from 'classnames';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Props extends React.HTMLAttributes<HTMLImageElement> {
 | 
					import { ReactComponent as CheckBoxOutlineBlankIcon } from '@material-symbols/svg-600/outlined/check_box_outline_blank.svg';
 | 
				
			||||||
  id: string;
 | 
					
 | 
				
			||||||
  className?: string;
 | 
					interface SVGPropsWithTitle extends React.SVGProps<SVGSVGElement> {
 | 
				
			||||||
  fixedWidth?: boolean;
 | 
					  title?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type IconProp = React.FC<SVGPropsWithTitle>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface Props extends React.SVGProps<SVGSVGElement> {
 | 
				
			||||||
  children?: never;
 | 
					  children?: never;
 | 
				
			||||||
 | 
					  id: string;
 | 
				
			||||||
 | 
					  icon: IconProp;
 | 
				
			||||||
 | 
					  title?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Icon: React.FC<Props> = ({
 | 
					export const Icon: React.FC<Props> = ({
 | 
				
			||||||
  id,
 | 
					  id,
 | 
				
			||||||
 | 
					  icon: IconComponent,
 | 
				
			||||||
  className,
 | 
					  className,
 | 
				
			||||||
  fixedWidth,
 | 
					  title: titleProp,
 | 
				
			||||||
  ...other
 | 
					  ...other
 | 
				
			||||||
}) => (
 | 
					}) => {
 | 
				
			||||||
  <i
 | 
					  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
				
			||||||
    className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })}
 | 
					  if (!IconComponent) {
 | 
				
			||||||
    {...other}
 | 
					    if (process.env.NODE_ENV !== 'production') {
 | 
				
			||||||
  />
 | 
					      throw new Error(`<Icon id="${id}"> is missing an "icon" prop.`);
 | 
				
			||||||
);
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    IconComponent = CheckBoxOutlineBlankIcon;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ariaHidden = titleProp ? undefined : true;
 | 
				
			||||||
 | 
					  const role = !ariaHidden ? 'img' : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Set the title to an empty string to remove the built-in SVG one if any
 | 
				
			||||||
 | 
					  // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
 | 
				
			||||||
 | 
					  const title = titleProp || '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <IconComponent
 | 
				
			||||||
 | 
					      className={classNames('icon', `icon-${id}`, className)}
 | 
				
			||||||
 | 
					      title={title}
 | 
				
			||||||
 | 
					      aria-hidden={ariaHidden}
 | 
				
			||||||
 | 
					      role={role}
 | 
				
			||||||
 | 
					      {...other}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,19 +1,20 @@
 | 
				
			|||||||
import { PureComponent } from 'react';
 | 
					import { PureComponent, createRef } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import classNames from 'classnames';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { AnimatedNumber } from './animated_number';
 | 
					import { AnimatedNumber } from './animated_number';
 | 
				
			||||||
 | 
					import type { IconProp } from './icon';
 | 
				
			||||||
import { Icon } from './icon';
 | 
					import { Icon } from './icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Props {
 | 
					interface Props {
 | 
				
			||||||
  className?: string;
 | 
					  className?: string;
 | 
				
			||||||
  title: string;
 | 
					  title: string;
 | 
				
			||||||
  icon: string;
 | 
					  icon: string;
 | 
				
			||||||
 | 
					  iconComponent: IconProp;
 | 
				
			||||||
  onClick?: React.MouseEventHandler<HTMLButtonElement>;
 | 
					  onClick?: React.MouseEventHandler<HTMLButtonElement>;
 | 
				
			||||||
  onMouseDown?: React.MouseEventHandler<HTMLButtonElement>;
 | 
					  onMouseDown?: React.MouseEventHandler<HTMLButtonElement>;
 | 
				
			||||||
  onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
 | 
					  onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
 | 
				
			||||||
  onKeyPress?: React.KeyboardEventHandler<HTMLButtonElement>;
 | 
					  onKeyPress?: React.KeyboardEventHandler<HTMLButtonElement>;
 | 
				
			||||||
  size: number;
 | 
					 | 
				
			||||||
  active: boolean;
 | 
					  active: boolean;
 | 
				
			||||||
  expanded?: boolean;
 | 
					  expanded?: boolean;
 | 
				
			||||||
  style?: React.CSSProperties;
 | 
					  style?: React.CSSProperties;
 | 
				
			||||||
@@ -32,8 +33,9 @@ interface States {
 | 
				
			|||||||
  deactivate: boolean;
 | 
					  deactivate: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export class IconButton extends PureComponent<Props, States> {
 | 
					export class IconButton extends PureComponent<Props, States> {
 | 
				
			||||||
 | 
					  buttonRef = createRef<HTMLButtonElement>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static defaultProps = {
 | 
					  static defaultProps = {
 | 
				
			||||||
    size: 18,
 | 
					 | 
				
			||||||
    active: false,
 | 
					    active: false,
 | 
				
			||||||
    disabled: false,
 | 
					    disabled: false,
 | 
				
			||||||
    animate: false,
 | 
					    animate: false,
 | 
				
			||||||
@@ -85,10 +87,6 @@ export class IconButton extends PureComponent<Props, States> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  render() {
 | 
					  render() {
 | 
				
			||||||
    const style = {
 | 
					    const style = {
 | 
				
			||||||
      fontSize: `${this.props.size}px`,
 | 
					 | 
				
			||||||
      width: `${this.props.size * 1.28571429}px`,
 | 
					 | 
				
			||||||
      height: `${this.props.size * 1.28571429}px`,
 | 
					 | 
				
			||||||
      lineHeight: `${this.props.size}px`,
 | 
					 | 
				
			||||||
      ...this.props.style,
 | 
					      ...this.props.style,
 | 
				
			||||||
      ...(this.props.active ? this.props.activeStyle : {}),
 | 
					      ...(this.props.active ? this.props.activeStyle : {}),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -99,6 +97,7 @@ export class IconButton extends PureComponent<Props, States> {
 | 
				
			|||||||
      disabled,
 | 
					      disabled,
 | 
				
			||||||
      expanded,
 | 
					      expanded,
 | 
				
			||||||
      icon,
 | 
					      icon,
 | 
				
			||||||
 | 
					      iconComponent,
 | 
				
			||||||
      inverted,
 | 
					      inverted,
 | 
				
			||||||
      overlay,
 | 
					      overlay,
 | 
				
			||||||
      tabIndex,
 | 
					      tabIndex,
 | 
				
			||||||
@@ -120,13 +119,9 @@ export class IconButton extends PureComponent<Props, States> {
 | 
				
			|||||||
      'icon-button--with-counter': typeof counter !== 'undefined',
 | 
					      'icon-button--with-counter': typeof counter !== 'undefined',
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (typeof counter !== 'undefined') {
 | 
					 | 
				
			||||||
      style.width = 'auto';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let contents = (
 | 
					    let contents = (
 | 
				
			||||||
      <>
 | 
					      <>
 | 
				
			||||||
        <Icon id={icon} fixedWidth aria-hidden='true' />{' '}
 | 
					        <Icon id={icon} icon={iconComponent} aria-hidden='true' />{' '}
 | 
				
			||||||
        {typeof counter !== 'undefined' && (
 | 
					        {typeof counter !== 'undefined' && (
 | 
				
			||||||
          <span className='icon-button__counter'>
 | 
					          <span className='icon-button__counter'>
 | 
				
			||||||
            <AnimatedNumber value={counter} />
 | 
					            <AnimatedNumber value={counter} />
 | 
				
			||||||
@@ -158,6 +153,7 @@ export class IconButton extends PureComponent<Props, States> {
 | 
				
			|||||||
        style={style}
 | 
					        style={style}
 | 
				
			||||||
        tabIndex={tabIndex}
 | 
					        tabIndex={tabIndex}
 | 
				
			||||||
        disabled={disabled}
 | 
					        disabled={disabled}
 | 
				
			||||||
 | 
					        ref={this.buttonRef}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        {contents}
 | 
					        {contents}
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,24 @@
 | 
				
			|||||||
 | 
					import type { IconProp } from './icon';
 | 
				
			||||||
import { Icon } from './icon';
 | 
					import { Icon } from './icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const formatNumber = (num: number): number | string => (num > 40 ? '40+' : num);
 | 
					const formatNumber = (num: number): number | string => (num > 40 ? '40+' : num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Props {
 | 
					interface Props {
 | 
				
			||||||
  id: string;
 | 
					  id: string;
 | 
				
			||||||
 | 
					  icon: IconProp;
 | 
				
			||||||
  count: number;
 | 
					  count: number;
 | 
				
			||||||
  issueBadge: boolean;
 | 
					  issueBadge: boolean;
 | 
				
			||||||
  className: string;
 | 
					  className: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export const IconWithBadge: React.FC<Props> = ({
 | 
					export const IconWithBadge: React.FC<Props> = ({
 | 
				
			||||||
  id,
 | 
					  id,
 | 
				
			||||||
 | 
					  icon,
 | 
				
			||||||
  count,
 | 
					  count,
 | 
				
			||||||
  issueBadge,
 | 
					  issueBadge,
 | 
				
			||||||
  className,
 | 
					  className,
 | 
				
			||||||
}) => (
 | 
					}) => (
 | 
				
			||||||
  <i className='icon-with-badge'>
 | 
					  <i className='icon-with-badge'>
 | 
				
			||||||
    <Icon id={id} fixedWidth className={className} />
 | 
					    <Icon id={id} icon={icon} className={className} />
 | 
				
			||||||
    {count > 0 && (
 | 
					    {count > 0 && (
 | 
				
			||||||
      <i className='icon-with-badge__badge'>{formatNumber(count)}</i>
 | 
					      <i className='icon-with-badge__badge'>{formatNumber(count)}</i>
 | 
				
			||||||
    )}
 | 
					    )}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,8 @@ import { useCallback } from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { useIntl, defineMessages } from 'react-intl';
 | 
					import { useIntl, defineMessages } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon } from 'mastodon/components/icon';
 | 
					import { Icon } from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
@@ -28,7 +30,7 @@ export const LoadGap: React.FC<Props> = ({ disabled, maxId, onClick }) => {
 | 
				
			|||||||
      onClick={handleClick}
 | 
					      onClick={handleClick}
 | 
				
			||||||
      aria-label={intl.formatMessage(messages.load_more)}
 | 
					      aria-label={intl.formatMessage(messages.load_more)}
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <Icon id='ellipsis-h' />
 | 
					      <Icon id='ellipsis-h' icon={MoreHorizIcon} />
 | 
				
			||||||
    </button>
 | 
					    </button>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import classNames from 'classnames';
 | 
				
			|||||||
import { is } from 'immutable';
 | 
					import { is } from 'immutable';
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Blurhash } from 'mastodon/components/blurhash';
 | 
					import { Blurhash } from 'mastodon/components/blurhash';
 | 
				
			||||||
@@ -323,7 +324,7 @@ class MediaGallery extends PureComponent {
 | 
				
			|||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else if (visible) {
 | 
					    } else if (visible) {
 | 
				
			||||||
      spoilerButton = <IconButton title={intl.formatMessage(messages.toggle_visible, { number: size })} icon='eye-slash' overlay onClick={this.handleOpen} ariaHidden />;
 | 
					      spoilerButton = <IconButton title={intl.formatMessage(messages.toggle_visible, { number: size })} icon='eye-slash' iconComponent={VisibilityOffIcon} overlay onClick={this.handleOpen} ariaHidden />;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      spoilerButton = (
 | 
					      spoilerButton = (
 | 
				
			||||||
        <button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'>
 | 
					        <button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@ import { FormattedMessage } from 'react-intl';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CancelPresentationIcon } from '@material-symbols/svg-600/outlined/cancel_presentation.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { removePictureInPicture } from 'mastodon/actions/picture_in_picture';
 | 
					import { removePictureInPicture } from 'mastodon/actions/picture_in_picture';
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,7 +27,7 @@ class PictureInPicturePlaceholder extends PureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='picture-in-picture-placeholder' style={{ aspectRatio }} role='button' tabIndex={0} onClick={this.handleClick}>
 | 
					      <div className='picture-in-picture-placeholder' style={{ aspectRatio }} role='button' tabIndex={0} onClick={this.handleClick}>
 | 
				
			||||||
        <Icon id='window-restore' />
 | 
					        <Icon id='window-restore' icon={CancelPresentationIcon} />
 | 
				
			||||||
        <FormattedMessage id='picture_in_picture.restore' defaultMessage='Put it back' />
 | 
					        <FormattedMessage id='picture_in_picture.restore' defaultMessage='Put it back' />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import classNames from 'classnames';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
 | 
				
			||||||
import escapeTextContentForBrowser from 'escape-html';
 | 
					import escapeTextContentForBrowser from 'escape-html';
 | 
				
			||||||
import spring from 'react-motion/lib/spring';
 | 
					import spring from 'react-motion/lib/spring';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -192,7 +193,7 @@ class Poll extends ImmutablePureComponent {
 | 
				
			|||||||
          />
 | 
					          />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          {!!voted && <span className='poll__voted'>
 | 
					          {!!voted && <span className='poll__voted'>
 | 
				
			||||||
            <Icon id='check' className='poll__voted__mark' title={intl.formatMessage(messages.voted)} />
 | 
					            <Icon id='check' icon={CheckIcon} className='poll__voted__mark' title={intl.formatMessage(messages.voted)} />
 | 
				
			||||||
          </span>}
 | 
					          </span>}
 | 
				
			||||||
        </label>
 | 
					        </label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,10 @@ import classNames from 'classnames';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PushPinIcon } from '@material-symbols/svg-600/outlined/push_pin.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
 | 
				
			||||||
import { HotKeys } from 'react-hotkeys';
 | 
					import { HotKeys } from 'react-hotkeys';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
@@ -27,6 +31,7 @@ import { getHashtagBarForStatus } from './hashtag_bar';
 | 
				
			|||||||
import { RelativeTimestamp } from './relative_timestamp';
 | 
					import { RelativeTimestamp } from './relative_timestamp';
 | 
				
			||||||
import StatusActionBar from './status_action_bar';
 | 
					import StatusActionBar from './status_action_bar';
 | 
				
			||||||
import StatusContent from './status_content';
 | 
					import StatusContent from './status_content';
 | 
				
			||||||
 | 
					import { VisibilityIcon } from './visibility_icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const domParser = new DOMParser();
 | 
					const domParser = new DOMParser();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -405,7 +410,7 @@ class Status extends ImmutablePureComponent {
 | 
				
			|||||||
    if (featured) {
 | 
					    if (featured) {
 | 
				
			||||||
      prepend = (
 | 
					      prepend = (
 | 
				
			||||||
        <div className='status__prepend'>
 | 
					        <div className='status__prepend'>
 | 
				
			||||||
          <div className='status__prepend-icon-wrapper'><Icon id='thumb-tack' className='status__prepend-icon' fixedWidth /></div>
 | 
					          <div className='status__prepend-icon-wrapper'><Icon id='thumb-tack' icon={PushPinIcon} className='status__prepend-icon' /></div>
 | 
				
			||||||
          <FormattedMessage id='status.pinned' defaultMessage='Pinned post' />
 | 
					          <FormattedMessage id='status.pinned' defaultMessage='Pinned post' />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -414,7 +419,7 @@ class Status extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      prepend = (
 | 
					      prepend = (
 | 
				
			||||||
        <div className='status__prepend'>
 | 
					        <div className='status__prepend'>
 | 
				
			||||||
          <div className='status__prepend-icon-wrapper'><Icon id='retweet' className='status__prepend-icon' fixedWidth /></div>
 | 
					          <div className='status__prepend-icon-wrapper'><Icon id='retweet' icon={RepeatIcon} className='status__prepend-icon' /></div>
 | 
				
			||||||
          <FormattedMessage id='status.reblogged_by' defaultMessage='{name} boosted' values={{ name: <a onClick={this.handlePrependAccountClick} data-id={status.getIn(['account', 'id'])} href={`/@${status.getIn(['account', 'acct'])}`} className='status__display-name muted'><bdi><strong dangerouslySetInnerHTML={display_name_html} /></bdi></a> }} />
 | 
					          <FormattedMessage id='status.reblogged_by' defaultMessage='{name} boosted' values={{ name: <a onClick={this.handlePrependAccountClick} data-id={status.getIn(['account', 'id'])} href={`/@${status.getIn(['account', 'acct'])}`} className='status__display-name muted'><bdi><strong dangerouslySetInnerHTML={display_name_html} /></bdi></a> }} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -426,7 +431,7 @@ class Status extends ImmutablePureComponent {
 | 
				
			|||||||
    } else if (status.get('visibility') === 'direct') {
 | 
					    } else if (status.get('visibility') === 'direct') {
 | 
				
			||||||
      prepend = (
 | 
					      prepend = (
 | 
				
			||||||
        <div className='status__prepend'>
 | 
					        <div className='status__prepend'>
 | 
				
			||||||
          <div className='status__prepend-icon-wrapper'><Icon id='at' className='status__prepend-icon' fixedWidth /></div>
 | 
					          <div className='status__prepend-icon-wrapper'><Icon id='at' icon={AlternateEmailIcon} className='status__prepend-icon' /></div>
 | 
				
			||||||
          <FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
 | 
					          <FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -435,7 +440,7 @@ class Status extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      prepend = (
 | 
					      prepend = (
 | 
				
			||||||
        <div className='status__prepend'>
 | 
					        <div className='status__prepend'>
 | 
				
			||||||
          <div className='status__prepend-icon-wrapper'><Icon id='reply' className='status__prepend-icon' fixedWidth /></div>
 | 
					          <div className='status__prepend-icon-wrapper'><Icon id='reply' icon={ReplyIcon} className='status__prepend-icon' /></div>
 | 
				
			||||||
          <FormattedMessage id='status.replied_to' defaultMessage='Replied to {name}' values={{ name: <a onClick={this.handlePrependAccountClick} data-id={status.getIn(['account', 'id'])} href={`/@${status.getIn(['account', 'acct'])}`} className='status__display-name muted'><bdi><strong dangerouslySetInnerHTML={display_name_html} /></bdi></a> }} />
 | 
					          <FormattedMessage id='status.replied_to' defaultMessage='Replied to {name}' values={{ name: <a onClick={this.handlePrependAccountClick} data-id={status.getIn(['account', 'id'])} href={`/@${status.getIn(['account', 'acct'])}`} className='status__display-name muted'><bdi><strong dangerouslySetInnerHTML={display_name_html} /></bdi></a> }} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@@ -534,15 +539,6 @@ class Status extends ImmutablePureComponent {
 | 
				
			|||||||
      statusAvatar = <AvatarOverlay account={status.get('account')} friend={account} />;
 | 
					      statusAvatar = <AvatarOverlay account={status.get('account')} friend={account} />;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const visibilityIconInfo = {
 | 
					 | 
				
			||||||
      'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
 | 
					 | 
				
			||||||
      'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
 | 
					 | 
				
			||||||
      'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
 | 
					 | 
				
			||||||
      'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const visibilityIcon = visibilityIconInfo[status.get('visibility')];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
 | 
					    const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
 | 
				
			||||||
    const expanded = !status.get('hidden') || status.get('spoiler_text').length === 0;
 | 
					    const expanded = !status.get('hidden') || status.get('spoiler_text').length === 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -557,7 +553,7 @@ class Status extends ImmutablePureComponent {
 | 
				
			|||||||
            {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
 | 
					            {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
 | 
				
			||||||
            <div onClick={this.handleClick} className='status__info'>
 | 
					            <div onClick={this.handleClick} className='status__info'>
 | 
				
			||||||
              <a href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
 | 
					              <a href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
 | 
				
			||||||
                <span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span>
 | 
					                <span className='status__visibility-icon'><VisibilityIcon visibility={status.get('visibility')} /></span>
 | 
				
			||||||
                <RelativeTimestamp timestamp={status.get('created_at')} />{status.get('edited_at') && <abbr title={intl.formatMessage(messages.edited, { date: intl.formatDate(status.get('edited_at'), { hour12: false, year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) })}> *</abbr>}
 | 
					                <RelativeTimestamp timestamp={status.get('created_at')} />{status.get('edited_at') && <abbr title={intl.formatMessage(messages.edited, { date: intl.formatDate(status.get('edited_at'), { hour12: false, year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) })}> *</abbr>}
 | 
				
			||||||
              </a>
 | 
					              </a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,16 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as BookmarkIcon } from '@material-symbols/svg-600/outlined/bookmark-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as BookmarkBorderIcon } from '@material-symbols/svg-600/outlined/bookmark.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlined/reply_all.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as VisibilityIcon } from '@material-symbols/svg-600/outlined/visibility.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
 | 
					import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
 | 
				
			||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
					import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -336,12 +346,15 @@ class StatusActionBar extends ImmutablePureComponent {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let replyIcon;
 | 
					    let replyIcon;
 | 
				
			||||||
 | 
					    let replyIconComponent;
 | 
				
			||||||
    let replyTitle;
 | 
					    let replyTitle;
 | 
				
			||||||
    if (status.get('in_reply_to_id', null) === null) {
 | 
					    if (status.get('in_reply_to_id', null) === null) {
 | 
				
			||||||
      replyIcon = 'reply';
 | 
					      replyIcon = 'reply';
 | 
				
			||||||
 | 
					      replyIconComponent = ReplyIcon;
 | 
				
			||||||
      replyTitle = intl.formatMessage(messages.reply);
 | 
					      replyTitle = intl.formatMessage(messages.reply);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      replyIcon = 'reply-all';
 | 
					      replyIcon = 'reply-all';
 | 
				
			||||||
 | 
					      replyIconComponent = ReplyAllIcon;
 | 
				
			||||||
      replyTitle = intl.formatMessage(messages.replyAll);
 | 
					      replyTitle = intl.formatMessage(messages.replyAll);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -359,29 +372,29 @@ class StatusActionBar extends ImmutablePureComponent {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const filterButton = this.props.onFilter && (
 | 
					    const filterButton = this.props.onFilter && (
 | 
				
			||||||
      <IconButton className='status__action-bar__button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleHideClick} />
 | 
					      <IconButton className='status__action-bar__button' title={intl.formatMessage(messages.hide)} icon='eye' iconComponent={VisibilityIcon} onClick={this.handleHideClick} />
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const isReply = status.get('in_reply_to_account_id') === status.getIn(['account', 'id']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='status__action-bar'>
 | 
					      <div className='status__action-bar'>
 | 
				
			||||||
        <IconButton className='status__action-bar__button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
 | 
					        <IconButton className='status__action-bar__button' title={replyTitle} icon={isReply ? 'reply' : replyIcon} iconComponent={isReply ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
 | 
				
			||||||
        <IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
 | 
					        <IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
 | 
				
			||||||
        <IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
 | 
					        <IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
 | 
				
			||||||
        <IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
 | 
					        <IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {filterButton}
 | 
					        {filterButton}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='status__action-bar__dropdown'>
 | 
					        <DropdownMenuContainer
 | 
				
			||||||
          <DropdownMenuContainer
 | 
					          scrollKey={scrollKey}
 | 
				
			||||||
            scrollKey={scrollKey}
 | 
					          status={status}
 | 
				
			||||||
            status={status}
 | 
					          items={menu}
 | 
				
			||||||
            items={menu}
 | 
					          icon='ellipsis-h'
 | 
				
			||||||
            icon='ellipsis-h'
 | 
					          iconComponent={MoreHorizIcon}
 | 
				
			||||||
            size={18}
 | 
					          direction='right'
 | 
				
			||||||
            direction='right'
 | 
					          title={intl.formatMessage(messages.more)}
 | 
				
			||||||
            title={intl.formatMessage(messages.more)}
 | 
					        />
 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,8 @@ import { Link, withRouter } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as ChevronRightIcon } from '@material-symbols/svg-600/outlined/chevron_right.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import PollContainer from 'mastodon/containers/poll_container';
 | 
					import PollContainer from 'mastodon/containers/poll_container';
 | 
				
			||||||
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';
 | 
					import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';
 | 
				
			||||||
@@ -257,7 +259,7 @@ class StatusContent extends PureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const readMoreButton = renderReadMore && (
 | 
					    const readMoreButton = renderReadMore && (
 | 
				
			||||||
      <button className='status__content__read-more-button' onClick={this.props.onClick} key='read-more'>
 | 
					      <button className='status__content__read-more-button' onClick={this.props.onClick} key='read-more'>
 | 
				
			||||||
        <FormattedMessage id='status.read_more' defaultMessage='Read more' /><Icon id='angle-right' fixedWidth />
 | 
					        <FormattedMessage id='status.read_more' defaultMessage='Read more' /><Icon id='angle-right' icon={ChevronRightIcon} />
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon } from './icon';
 | 
					import { Icon } from './icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const domParser = new DOMParser();
 | 
					const domParser = new DOMParser();
 | 
				
			||||||
@@ -21,7 +23,7 @@ interface Props {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
export const VerifiedBadge: React.FC<Props> = ({ link }) => (
 | 
					export const VerifiedBadge: React.FC<Props> = ({ link }) => (
 | 
				
			||||||
  <span className='verified-badge'>
 | 
					  <span className='verified-badge'>
 | 
				
			||||||
    <Icon id='check' className='verified-badge__mark' />
 | 
					    <Icon id='check' icon={CheckIcon} className='verified-badge__mark' />
 | 
				
			||||||
    <span dangerouslySetInnerHTML={stripRelMe(link)} />
 | 
					    <span dangerouslySetInnerHTML={stripRelMe(link)} />
 | 
				
			||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										62
									
								
								app/javascript/mastodon/components/visibility_icon.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								app/javascript/mastodon/components/visibility_icon.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					import { defineMessages, useIntl } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/lock.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as LockOpenIcon } from '@material-symbols/svg-600/outlined/lock_open.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Icon } from './icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Visibility = 'public' | 'unlisted' | 'private' | 'direct';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const messages = defineMessages({
 | 
				
			||||||
 | 
					  public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
 | 
				
			||||||
 | 
					  unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
 | 
				
			||||||
 | 
					  private_short: {
 | 
				
			||||||
 | 
					    id: 'privacy.private.short',
 | 
				
			||||||
 | 
					    defaultMessage: 'Followers only',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  direct_short: {
 | 
				
			||||||
 | 
					    id: 'privacy.direct.short',
 | 
				
			||||||
 | 
					    defaultMessage: 'Mentioned people only',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const VisibilityIcon: React.FC<{ visibility: Visibility }> = ({
 | 
				
			||||||
 | 
					  visibility,
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const intl = useIntl();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const visibilityIconInfo = {
 | 
				
			||||||
 | 
					    public: {
 | 
				
			||||||
 | 
					      icon: 'globe',
 | 
				
			||||||
 | 
					      iconComponent: PublicIcon,
 | 
				
			||||||
 | 
					      text: intl.formatMessage(messages.public_short),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    unlisted: {
 | 
				
			||||||
 | 
					      icon: 'unlock',
 | 
				
			||||||
 | 
					      iconComponent: LockOpenIcon,
 | 
				
			||||||
 | 
					      text: intl.formatMessage(messages.unlisted_short),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    private: {
 | 
				
			||||||
 | 
					      icon: 'lock',
 | 
				
			||||||
 | 
					      iconComponent: LockIcon,
 | 
				
			||||||
 | 
					      text: intl.formatMessage(messages.private_short),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    direct: {
 | 
				
			||||||
 | 
					      icon: 'at',
 | 
				
			||||||
 | 
					      iconComponent: AlternateEmailIcon,
 | 
				
			||||||
 | 
					      text: intl.formatMessage(messages.direct_short),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const visibilityIcon = visibilityIconInfo[visibility];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Icon
 | 
				
			||||||
 | 
					      id={visibilityIcon.icon}
 | 
				
			||||||
 | 
					      icon={visibilityIcon.iconComponent}
 | 
				
			||||||
 | 
					      title={visibilityIcon.text}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -10,6 +10,9 @@ import { List as ImmutableList } from 'immutable';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as ChevronRightIcon } from '@material-symbols/svg-600/outlined/chevron_right.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ExpandMoreIcon } from '@material-symbols/svg-600/outlined/expand_more.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { fetchServer, fetchExtendedDescription, fetchDomainBlocks  } from 'mastodon/actions/server';
 | 
					import { fetchServer, fetchExtendedDescription, fetchDomainBlocks  } from 'mastodon/actions/server';
 | 
				
			||||||
import Column from 'mastodon/components/column';
 | 
					import Column from 'mastodon/components/column';
 | 
				
			||||||
import { Icon  }  from 'mastodon/components/icon';
 | 
					import { Icon  }  from 'mastodon/components/icon';
 | 
				
			||||||
@@ -73,7 +76,7 @@ class Section extends PureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className={classNames('about__section', { active: !collapsed })}>
 | 
					      <div className={classNames('about__section', { active: !collapsed })}>
 | 
				
			||||||
        <div className='about__section__title' role='button' tabIndex={0} onClick={this.handleClick}>
 | 
					        <div className='about__section__title' role='button' tabIndex={0} onClick={this.handleClick}>
 | 
				
			||||||
          <Icon id={collapsed ? 'chevron-right' : 'chevron-down'} fixedWidth /> {title}
 | 
					          <Icon id={collapsed ? 'chevron-right' : 'chevron-down'} icon={collapsed ? ChevronRightIcon : ExpandMoreIcon} /> {title}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {!collapsed && (
 | 
					        {!collapsed && (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,9 @@ import { FormattedMessage } from 'react-intl';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class FollowRequestNote extends ImmutablePureComponent {
 | 
					export default class FollowRequestNote extends ImmutablePureComponent {
 | 
				
			||||||
@@ -22,12 +25,12 @@ export default class FollowRequestNote extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        <div className='follow-request-banner__action'>
 | 
					        <div className='follow-request-banner__action'>
 | 
				
			||||||
          <button type='button' className='button button-tertiary button--confirmation' onClick={onAuthorize}>
 | 
					          <button type='button' className='button button-tertiary button--confirmation' onClick={onAuthorize}>
 | 
				
			||||||
            <Icon id='check' fixedWidth />
 | 
					            <Icon id='check' icon={CheckIcon} />
 | 
				
			||||||
            <FormattedMessage id='follow_request.authorize' defaultMessage='Authorize' />
 | 
					            <FormattedMessage id='follow_request.authorize' defaultMessage='Authorize' />
 | 
				
			||||||
          </button>
 | 
					          </button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <button type='button' className='button button-tertiary button--destructive' onClick={onReject}>
 | 
					          <button type='button' className='button button-tertiary button--destructive' onClick={onReject}>
 | 
				
			||||||
            <Icon id='times' fixedWidth />
 | 
					            <Icon id='times' icon={CloseIcon} />
 | 
				
			||||||
            <FormattedMessage id='follow_request.reject' defaultMessage='Reject' />
 | 
					            <FormattedMessage id='follow_request.reject' defaultMessage='Reject' />
 | 
				
			||||||
          </button>
 | 
					          </button>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,12 @@ import { NavLink, withRouter } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/lock.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as NotificationsActiveIcon } from '@material-symbols/svg-600/outlined/notifications_active.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Avatar } from 'mastodon/components/avatar';
 | 
					import { Avatar } from 'mastodon/components/avatar';
 | 
				
			||||||
import { Badge, AutomatedBadge, GroupBadge } from 'mastodon/components/badge';
 | 
					import { Badge, AutomatedBadge, GroupBadge } from 'mastodon/components/badge';
 | 
				
			||||||
import { Button } from 'mastodon/components/button';
 | 
					import { Button } from 'mastodon/components/button';
 | 
				
			||||||
@@ -258,7 +264,7 @@ class Header extends ImmutablePureComponent {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (account.getIn(['relationship', 'requested']) || account.getIn(['relationship', 'following'])) {
 | 
					    if (account.getIn(['relationship', 'requested']) || account.getIn(['relationship', 'following'])) {
 | 
				
			||||||
      bellBtn = <IconButton icon={account.getIn(['relationship', 'notifying']) ? 'bell' : 'bell-o'} size={24} active={account.getIn(['relationship', 'notifying'])} title={intl.formatMessage(account.getIn(['relationship', 'notifying']) ? messages.disableNotifications : messages.enableNotifications, { name: account.get('username') })} onClick={this.props.onNotifyToggle} />;
 | 
					      bellBtn = <IconButton icon={account.getIn(['relationship', 'notifying']) ? 'bell' : 'bell-o'} iconComponent={account.getIn(['relationship', 'notifying']) ? NotificationsIcon : NotificationsActiveIcon}  size={24} active={account.getIn(['relationship', 'notifying'])} title={intl.formatMessage(account.getIn(['relationship', 'notifying']) ? messages.disableNotifications : messages.enableNotifications, { name: account.get('username') })} onClick={this.props.onNotifyToggle} />;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (me !== account.get('id')) {
 | 
					    if (me !== account.get('id')) {
 | 
				
			||||||
@@ -280,7 +286,7 @@ class Header extends ImmutablePureComponent {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (account.get('locked')) {
 | 
					    if (account.get('locked')) {
 | 
				
			||||||
      lockedIcon = <Icon id='lock' title={intl.formatMessage(messages.account_locked)} />;
 | 
					      lockedIcon = <Icon id='lock' icon={LockIcon} title={intl.formatMessage(messages.account_locked)} />;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (signedIn && account.get('id') !== me) {
 | 
					    if (signedIn && account.get('id') !== me) {
 | 
				
			||||||
@@ -410,7 +416,7 @@ class Header extends ImmutablePureComponent {
 | 
				
			|||||||
                  </>
 | 
					                  </>
 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <DropdownMenuContainer disabled={menu.length === 0} items={menu} icon='ellipsis-v' size={24} direction='right' />
 | 
					                <DropdownMenuContainer disabled={menu.length === 0} items={menu} icon='ellipsis-v' iconComponent={MoreHorizIcon} size={24} direction='right' />
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
            )}
 | 
					            )}
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
@@ -448,7 +454,7 @@ class Header extends ImmutablePureComponent {
 | 
				
			|||||||
                      <dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} className='translate' />
 | 
					                      <dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} className='translate' />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                      <dd className='translate' title={pair.get('value_plain')}>
 | 
					                      <dd className='translate' title={pair.get('value_plain')}>
 | 
				
			||||||
                        {pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} />
 | 
					                        {pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' icon={CheckIcon} className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} />
 | 
				
			||||||
                      </dd>
 | 
					                      </dd>
 | 
				
			||||||
                    </dl>
 | 
					                    </dl>
 | 
				
			||||||
                  ))}
 | 
					                  ))}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,10 @@ import classNames from 'classnames';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AudiotrackIcon } from '@material-symbols/svg-600/outlined/music_note.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Blurhash } from 'mastodon/components/blurhash';
 | 
					import { Blurhash } from 'mastodon/components/blurhash';
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import { autoPlayGif, displayMedia, useBlurhash } from 'mastodon/initial_state';
 | 
					import { autoPlayGif, displayMedia, useBlurhash } from 'mastodon/initial_state';
 | 
				
			||||||
@@ -69,7 +73,7 @@ export default class MediaItem extends ImmutablePureComponent {
 | 
				
			|||||||
    if (!visible) {
 | 
					    if (!visible) {
 | 
				
			||||||
      icon = (
 | 
					      icon = (
 | 
				
			||||||
        <span className='account-gallery__item__icons'>
 | 
					        <span className='account-gallery__item__icons'>
 | 
				
			||||||
          <Icon id='eye-slash' />
 | 
					          <Icon id='eye-slash' icon={VisibilityOffIcon} />
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@@ -84,9 +88,9 @@ export default class MediaItem extends ImmutablePureComponent {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (attachment.get('type') === 'audio') {
 | 
					        if (attachment.get('type') === 'audio') {
 | 
				
			||||||
          label = <Icon id='music' />;
 | 
					          label = <Icon id='music' icon={AudiotrackIcon} />;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          label = <Icon id='play' />;
 | 
					          label = <Icon id='play' icon={PlayArrowIcon} />;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else if (attachment.get('type') === 'image') {
 | 
					      } else if (attachment.get('type') === 'image') {
 | 
				
			||||||
        const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;
 | 
					        const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,12 @@ import classNames from 'classnames';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { is } from 'immutable';
 | 
					import { is } from 'immutable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as DownloadIcon } from '@material-symbols/svg-600/outlined/download.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PauseIcon } from '@material-symbols/svg-600/outlined/pause.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as VolumeUpIcon } from '@material-symbols/svg-600/outlined/volume_up.svg';
 | 
				
			||||||
import { throttle, debounce } from 'lodash';
 | 
					import { throttle, debounce } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
@@ -554,8 +560,8 @@ class Audio extends PureComponent {
 | 
				
			|||||||
        <div className='video-player__controls active'>
 | 
					        <div className='video-player__controls active'>
 | 
				
			||||||
          <div className='video-player__buttons-bar'>
 | 
					          <div className='video-player__buttons-bar'>
 | 
				
			||||||
            <div className='video-player__buttons left'>
 | 
					            <div className='video-player__buttons left'>
 | 
				
			||||||
              <button type='button' title={intl.formatMessage(paused ? messages.play : messages.pause)} aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} className='player-button' onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
 | 
					              <button type='button' title={intl.formatMessage(paused ? messages.play : messages.pause)} aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} className='player-button' onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} icon={paused ? PlayArrowIcon : PauseIcon} /></button>
 | 
				
			||||||
              <button type='button' title={intl.formatMessage(muted ? messages.unmute : messages.mute)} aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} className='player-button' onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
 | 
					              <button type='button' title={intl.formatMessage(muted ? messages.unmute : messages.mute)} aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} className='player-button' onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} icon={muted ? VolumeOffIcon : VolumeUpIcon} /></button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              <div className={classNames('video-player__volume', { active: this.state.hovered })} ref={this.setVolumeRef} onMouseDown={this.handleVolumeMouseDown}>
 | 
					              <div className={classNames('video-player__volume', { active: this.state.hovered })} ref={this.setVolumeRef} onMouseDown={this.handleVolumeMouseDown}>
 | 
				
			||||||
                <div className='video-player__volume__current' style={{ width: `${muted ? 0 : volume * 100}%`, backgroundColor: this._getAccentColor() }} />
 | 
					                <div className='video-player__volume__current' style={{ width: `${muted ? 0 : volume * 100}%`, backgroundColor: this._getAccentColor() }} />
 | 
				
			||||||
@@ -575,9 +581,9 @@ class Audio extends PureComponent {
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div className='video-player__buttons right'>
 | 
					            <div className='video-player__buttons right'>
 | 
				
			||||||
              {!editable && <button type='button' title={intl.formatMessage(messages.hide)} aria-label={intl.formatMessage(messages.hide)} className='player-button' onClick={this.toggleReveal}><Icon id='eye-slash' fixedWidth /></button>}
 | 
					              {!editable && <button type='button' title={intl.formatMessage(messages.hide)} aria-label={intl.formatMessage(messages.hide)} className='player-button' onClick={this.toggleReveal}><Icon id='eye-slash' icon={VisibilityOffIcon} /></button>}
 | 
				
			||||||
              <a title={intl.formatMessage(messages.download)} aria-label={intl.formatMessage(messages.download)} className='video-player__download__icon player-button' href={this.props.src} download>
 | 
					              <a title={intl.formatMessage(messages.download)} aria-label={intl.formatMessage(messages.download)} className='video-player__download__icon player-button' href={this.props.src} download>
 | 
				
			||||||
                <Icon id={'download'} fixedWidth />
 | 
					                <Icon id={'download'} icon={DownloadIcon} />
 | 
				
			||||||
              </a>
 | 
					              </a>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as BookmarksIcon } from '@material-symbols/svg-600/outlined/bookmarks-fill.svg';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'mastodon/actions/bookmarks';
 | 
					import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'mastodon/actions/bookmarks';
 | 
				
			||||||
@@ -79,7 +80,8 @@ class Bookmarks extends ImmutablePureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.heading)}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.heading)}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='bookmark'
 | 
					          icon='bookmarks'
 | 
				
			||||||
 | 
					          iconComponent={BookmarksIcon}
 | 
				
			||||||
          title={intl.formatMessage(messages.heading)}
 | 
					          title={intl.formatMessage(messages.heading)}
 | 
				
			||||||
          onPin={this.handlePin}
 | 
					          onPin={this.handlePin}
 | 
				
			||||||
          onMove={this.handleMove}
 | 
					          onMove={this.handleMove}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@ import { Helmet } from 'react-helmet';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
 | 
					import { DismissableBanner } from 'mastodon/components/dismissable_banner';
 | 
				
			||||||
import { domain } from 'mastodon/initial_state';
 | 
					import { domain } from 'mastodon/initial_state';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -128,6 +130,7 @@ class CommunityTimeline extends PureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='users'
 | 
					          icon='users'
 | 
				
			||||||
 | 
					          iconComponent={PeopleIcon}
 | 
				
			||||||
          active={hasUnread}
 | 
					          active={hasUnread}
 | 
				
			||||||
          title={intl.formatMessage(messages.title)}
 | 
					          title={intl.formatMessage(messages.title)}
 | 
				
			||||||
          onPin={this.handlePin}
 | 
					          onPin={this.handlePin}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@ import { defineMessages, injectIntl } from 'react-intl';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as MenuIcon } from '@material-symbols/svg-600/outlined/menu.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
 | 
					import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
@@ -60,7 +62,7 @@ class ActionBar extends PureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='compose__action-bar'>
 | 
					      <div className='compose__action-bar'>
 | 
				
			||||||
        <div className='compose__action-bar-dropdown'>
 | 
					        <div className='compose__action-bar-dropdown'>
 | 
				
			||||||
          <DropdownMenuContainer items={menu} icon='bars' size={18} direction='right' />
 | 
					          <DropdownMenuContainer items={menu} icon='bars' iconComponent={MenuIcon} size={24} direction='right' />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import classNames from 'classnames';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/lock.svg';
 | 
				
			||||||
import { length } from 'stringz';
 | 
					import { length } from 'stringz';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
@@ -229,7 +230,7 @@ class ComposeForm extends ImmutablePureComponent {
 | 
				
			|||||||
    if (this.props.isEditing) {
 | 
					    if (this.props.isEditing) {
 | 
				
			||||||
      publishText = intl.formatMessage(messages.saveChanges);
 | 
					      publishText = intl.formatMessage(messages.saveChanges);
 | 
				
			||||||
    } else if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
 | 
					    } else if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
 | 
				
			||||||
      publishText = <span className='compose-form__publish-private'><Icon id='lock' /> {intl.formatMessage(messages.publish)}</span>;
 | 
					      publishText = <><Icon id='lock' icon={LockIcon} /> {intl.formatMessage(messages.publish)}</>;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      publishText = this.props.privacy !== 'unlisted' ? intl.formatMessage(messages.publishLoud, { publish: intl.formatMessage(messages.publish) }) : intl.formatMessage(messages.publish);
 | 
					      publishText = this.props.privacy !== 'unlisted' ? intl.formatMessage(messages.publishLoud, { publish: intl.formatMessage(messages.publish) }) : intl.formatMessage(messages.publish);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,11 @@ import { PureComponent } from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { defineMessages, injectIntl } from 'react-intl';
 | 
					import { defineMessages, injectIntl } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { IconButton } from '../../../components/icon_button';
 | 
					import { IconButton } from '../../../components/icon_button';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
  add_poll: { id: 'poll_button.add_poll', defaultMessage: 'Add a poll' },
 | 
					  add_poll: { id: 'poll_button.add_poll', defaultMessage: 'Add a poll' },
 | 
				
			||||||
  remove_poll: { id: 'poll_button.remove_poll', defaultMessage: 'Remove poll' },
 | 
					  remove_poll: { id: 'poll_button.remove_poll', defaultMessage: 'Remove poll' },
 | 
				
			||||||
@@ -40,6 +43,7 @@ class PollButton extends PureComponent {
 | 
				
			|||||||
      <div className='compose-form__poll-button'>
 | 
					      <div className='compose-form__poll-button'>
 | 
				
			||||||
        <IconButton
 | 
					        <IconButton
 | 
				
			||||||
          icon='tasks'
 | 
					          icon='tasks'
 | 
				
			||||||
 | 
					          iconComponent={InsertChartIcon}
 | 
				
			||||||
          title={intl.formatMessage(active ? messages.remove_poll : messages.add_poll)}
 | 
					          title={intl.formatMessage(active ? messages.remove_poll : messages.add_poll)}
 | 
				
			||||||
          disabled={disabled}
 | 
					          disabled={disabled}
 | 
				
			||||||
          onClick={this.handleClick}
 | 
					          onClick={this.handleClick}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,9 @@ import classNames from 'classnames';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import AutosuggestInput from 'mastodon/components/autosuggest_input';
 | 
					import AutosuggestInput from 'mastodon/components/autosuggest_input';
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import { IconButton } from 'mastodon/components/icon_button';
 | 
					import { IconButton } from 'mastodon/components/icon_button';
 | 
				
			||||||
@@ -108,7 +111,7 @@ class OptionIntl extends PureComponent {
 | 
				
			|||||||
        </label>
 | 
					        </label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='poll__cancel'>
 | 
					        <div className='poll__cancel'>
 | 
				
			||||||
          <IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
 | 
					          <IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' iconComponent={CloseIcon} onClick={this.handleOptionRemove} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </li>
 | 
					      </li>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -164,7 +167,7 @@ class PollForm extends ImmutablePureComponent {
 | 
				
			|||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='poll__footer'>
 | 
					        <div className='poll__footer'>
 | 
				
			||||||
          <button type='button' disabled={options.size >= 4} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>
 | 
					          <button type='button' disabled={options.size >= 4} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' icon={AddIcon} /> <FormattedMessage {...messages.add_option} /></button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          {/* eslint-disable-next-line jsx-a11y/no-onchange */}
 | 
					          {/* eslint-disable-next-line jsx-a11y/no-onchange */}
 | 
				
			||||||
          <select value={expiresIn} onChange={this.handleSelectDuration}>
 | 
					          <select value={expiresIn} onChange={this.handleSelectDuration}>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,9 +5,15 @@ import { injectIntl, defineMessages } from 'react-intl';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import classNames from 'classnames';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/lock.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as LockOpenIcon } from '@material-symbols/svg-600/outlined/lock_open.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
 | 
				
			||||||
import { supportsPassiveEvents } from 'detect-passive-events';
 | 
					import { supportsPassiveEvents } from 'detect-passive-events';
 | 
				
			||||||
import Overlay from 'react-overlays/Overlay';
 | 
					import Overlay from 'react-overlays/Overlay';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { IconButton } from '../../../components/icon_button';
 | 
					import { IconButton } from '../../../components/icon_button';
 | 
				
			||||||
@@ -123,7 +129,7 @@ class PrivacyDropdownMenu extends PureComponent {
 | 
				
			|||||||
        {items.map(item => (
 | 
					        {items.map(item => (
 | 
				
			||||||
          <div role='option' tabIndex={0} key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
 | 
					          <div role='option' tabIndex={0} key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
 | 
				
			||||||
            <div className='privacy-dropdown__option__icon'>
 | 
					            <div className='privacy-dropdown__option__icon'>
 | 
				
			||||||
              <Icon id={item.icon} fixedWidth />
 | 
					              <Icon id={item.icon} icon={item.iconComponent} />
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div className='privacy-dropdown__option__content'>
 | 
					            <div className='privacy-dropdown__option__content'>
 | 
				
			||||||
@@ -222,14 +228,14 @@ class PrivacyDropdown extends PureComponent {
 | 
				
			|||||||
    const { intl: { formatMessage } } = this.props;
 | 
					    const { intl: { formatMessage } } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.options = [
 | 
					    this.options = [
 | 
				
			||||||
      { icon: 'globe', value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
 | 
					      { icon: 'globe', iconComponent: PublicIcon, value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
 | 
				
			||||||
      { icon: 'unlock', value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
 | 
					      { icon: 'unlock', iconComponent: LockOpenIcon,  value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
 | 
				
			||||||
      { icon: 'lock', value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
 | 
					      { icon: 'lock', iconComponent: LockIcon, value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!this.props.noDirect) {
 | 
					    if (!this.props.noDirect) {
 | 
				
			||||||
      this.options.push(
 | 
					      this.options.push(
 | 
				
			||||||
        { icon: 'at', value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },
 | 
					        { icon: 'at', iconComponent: AlternateEmailIcon, value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -253,25 +259,24 @@ class PrivacyDropdown extends PureComponent {
 | 
				
			|||||||
    const valueOption = this.options.find(item => item.value === value);
 | 
					    const valueOption = this.options.find(item => item.value === value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className={classNames('privacy-dropdown', placement, { active: open })} onKeyDown={this.handleKeyDown}>
 | 
					      <div ref={this.setTargetRef} onKeyDown={this.handleKeyDown}>
 | 
				
			||||||
        <div className={classNames('privacy-dropdown__value', { active: this.options.indexOf(valueOption) === (placement === 'bottom' ? 0 : (this.options.length - 1)) })} ref={this.setTargetRef}>
 | 
					        <IconButton
 | 
				
			||||||
          <IconButton
 | 
					          className='privacy-dropdown__value-icon'
 | 
				
			||||||
            className='privacy-dropdown__value-icon'
 | 
					          icon={valueOption.icon}
 | 
				
			||||||
            icon={valueOption.icon}
 | 
					          iconComponent={valueOption.iconComponent}
 | 
				
			||||||
            title={intl.formatMessage(messages.change_privacy)}
 | 
					          title={intl.formatMessage(messages.change_privacy)}
 | 
				
			||||||
            size={18}
 | 
					          size={18}
 | 
				
			||||||
            expanded={open}
 | 
					          expanded={open}
 | 
				
			||||||
            active={open}
 | 
					          active={open}
 | 
				
			||||||
            inverted
 | 
					          inverted
 | 
				
			||||||
            onClick={this.handleToggle}
 | 
					          onClick={this.handleToggle}
 | 
				
			||||||
            onMouseDown={this.handleMouseDown}
 | 
					          onMouseDown={this.handleMouseDown}
 | 
				
			||||||
            onKeyDown={this.handleButtonKeyDown}
 | 
					          onKeyDown={this.handleButtonKeyDown}
 | 
				
			||||||
            style={{ height: null, lineHeight: '27px' }}
 | 
					          style={{ height: null, lineHeight: '27px' }}
 | 
				
			||||||
            disabled={disabled}
 | 
					          disabled={disabled}
 | 
				
			||||||
          />
 | 
					        />
 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <Overlay show={open} placement={'bottom'} flip target={this.findTarget} container={container} popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}>
 | 
					        <Overlay show={open} placement={placement} flip target={this.findTarget} container={container} popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}>
 | 
				
			||||||
          {({ props, placement }) => (
 | 
					          {({ props, placement }) => (
 | 
				
			||||||
            <div {...props}>
 | 
					            <div {...props}>
 | 
				
			||||||
              <div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}>
 | 
					              <div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@ import { defineMessages, injectIntl } from 'react-intl';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import AttachmentList from 'mastodon/components/attachment_list';
 | 
					import AttachmentList from 'mastodon/components/attachment_list';
 | 
				
			||||||
import { WithOptionalRouterPropTypes, withOptionalRouter } from 'mastodon/utils/react_router';
 | 
					import { WithOptionalRouterPropTypes, withOptionalRouter } from 'mastodon/utils/react_router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -48,7 +50,7 @@ class ReplyIndicator extends ImmutablePureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='reply-indicator'>
 | 
					      <div className='reply-indicator'>
 | 
				
			||||||
        <div className='reply-indicator__header'>
 | 
					        <div className='reply-indicator__header'>
 | 
				
			||||||
          <div className='reply-indicator__cancel'><IconButton title={intl.formatMessage(messages.cancel)} icon='times' onClick={this.handleClick} inverted /></div>
 | 
					          <div className='reply-indicator__cancel'><IconButton title={intl.formatMessage(messages.cancel)} icon='times' iconComponent={CloseIcon} onClick={this.handleClick} inverted /></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <a href={`/@${status.getIn(['account', 'acct'])}`} onClick={this.handleAccountClick} className='reply-indicator__display-name'>
 | 
					          <a href={`/@${status.getIn(['account', 'acct'])}`} onClick={this.handleAccountClick} className='reply-indicator__display-name'>
 | 
				
			||||||
            <div className='reply-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>
 | 
					            <div className='reply-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,10 @@ import { withRouter } from 'react-router-dom';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CancelIcon } from '@material-symbols/svg-600/outlined/cancel-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as SearchIcon } from '@material-symbols/svg-600/outlined/search.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import { domain, searchEnabled } from 'mastodon/initial_state';
 | 
					import { domain, searchEnabled } from 'mastodon/initial_state';
 | 
				
			||||||
import { HASHTAG_REGEX } from 'mastodon/utils/hashtags';
 | 
					import { HASHTAG_REGEX } from 'mastodon/utils/hashtags';
 | 
				
			||||||
@@ -332,8 +336,8 @@ class Search extends PureComponent {
 | 
				
			|||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
 | 
					        <div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
 | 
				
			||||||
          <Icon id='search' className={hasValue ? '' : 'active'} />
 | 
					          <Icon id='search' icon={SearchIcon} className={hasValue ? '' : 'active'} />
 | 
				
			||||||
          <Icon id='times-circle' className={hasValue ? 'active' : ''} aria-label={intl.formatMessage(messages.placeholder)} />
 | 
					          <Icon id='times-circle' icon={CancelIcon} className={hasValue ? 'active' : ''} aria-label={intl.formatMessage(messages.placeholder)} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='search__popout'>
 | 
					        <div className='search__popout'>
 | 
				
			||||||
@@ -345,7 +349,7 @@ class Search extends PureComponent {
 | 
				
			|||||||
                {recent.size > 0 ? this._getOptions().map(({ label, action, forget }, i) => (
 | 
					                {recent.size > 0 ? this._getOptions().map(({ label, action, forget }, i) => (
 | 
				
			||||||
                  <button key={label} onMouseDown={action} className={classNames('search__popout__menu__item search__popout__menu__item--flex', { selected: selectedOption === i })}>
 | 
					                  <button key={label} onMouseDown={action} className={classNames('search__popout__menu__item search__popout__menu__item--flex', { selected: selectedOption === i })}>
 | 
				
			||||||
                    <span>{label}</span>
 | 
					                    <span>{label}</span>
 | 
				
			||||||
                    <button className='icon-button' onMouseDown={forget}><Icon id='times' /></button>
 | 
					                    <button className='icon-button' onMouseDown={forget}><Icon id='times' icon={CloseIcon} /></button>
 | 
				
			||||||
                  </button>
 | 
					                  </button>
 | 
				
			||||||
                )) : (
 | 
					                )) : (
 | 
				
			||||||
                  <div className='search__popout__menu__message'>
 | 
					                  <div className='search__popout__menu__message'>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,11 @@ import { FormattedMessage } from 'react-intl';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as FindInPageIcon } from '@material-symbols/svg-600/outlined/find_in_page.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as SearchIcon } from '@material-symbols/svg-600/outlined/search.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import { LoadMore } from 'mastodon/components/load_more';
 | 
					import { LoadMore } from 'mastodon/components/load_more';
 | 
				
			||||||
import { SearchSection } from 'mastodon/features/explore/components/search_section';
 | 
					import { SearchSection } from 'mastodon/features/explore/components/search_section';
 | 
				
			||||||
@@ -44,7 +49,7 @@ class SearchResults extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (results.get('accounts') && results.get('accounts').size > 0) {
 | 
					    if (results.get('accounts') && results.get('accounts').size > 0) {
 | 
				
			||||||
      accounts = (
 | 
					      accounts = (
 | 
				
			||||||
        <SearchSection title={<><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>}>
 | 
					        <SearchSection title={<><Icon id='users' icon={PeopleIcon} /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>}>
 | 
				
			||||||
          {withoutLastResult(results.get('accounts')).map(accountId => <AccountContainer key={accountId} id={accountId} />)}
 | 
					          {withoutLastResult(results.get('accounts')).map(accountId => <AccountContainer key={accountId} id={accountId} />)}
 | 
				
			||||||
          {(results.get('accounts').size > INITIAL_PAGE_LIMIT && results.get('accounts').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreAccounts} />}
 | 
					          {(results.get('accounts').size > INITIAL_PAGE_LIMIT && results.get('accounts').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreAccounts} />}
 | 
				
			||||||
        </SearchSection>
 | 
					        </SearchSection>
 | 
				
			||||||
@@ -53,7 +58,7 @@ class SearchResults extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (results.get('hashtags') && results.get('hashtags').size > 0) {
 | 
					    if (results.get('hashtags') && results.get('hashtags').size > 0) {
 | 
				
			||||||
      hashtags = (
 | 
					      hashtags = (
 | 
				
			||||||
        <SearchSection title={<><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>}>
 | 
					        <SearchSection title={<><Icon id='hashtag' icon={TagIcon} /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>}>
 | 
				
			||||||
          {withoutLastResult(results.get('hashtags')).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
 | 
					          {withoutLastResult(results.get('hashtags')).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
 | 
				
			||||||
          {(results.get('hashtags').size > INITIAL_PAGE_LIMIT && results.get('hashtags').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreHashtags} />}
 | 
					          {(results.get('hashtags').size > INITIAL_PAGE_LIMIT && results.get('hashtags').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreHashtags} />}
 | 
				
			||||||
        </SearchSection>
 | 
					        </SearchSection>
 | 
				
			||||||
@@ -62,7 +67,7 @@ class SearchResults extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (results.get('statuses') && results.get('statuses').size > 0) {
 | 
					    if (results.get('statuses') && results.get('statuses').size > 0) {
 | 
				
			||||||
      statuses = (
 | 
					      statuses = (
 | 
				
			||||||
        <SearchSection title={<><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>}>
 | 
					        <SearchSection title={<><Icon id='quote-right' icon={FindInPageIcon} /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>}>
 | 
				
			||||||
          {withoutLastResult(results.get('statuses')).map(statusId => <StatusContainer key={statusId} id={statusId} />)}
 | 
					          {withoutLastResult(results.get('statuses')).map(statusId => <StatusContainer key={statusId} id={statusId} />)}
 | 
				
			||||||
          {(results.get('statuses').size > INITIAL_PAGE_LIMIT && results.get('statuses').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreStatuses} />}
 | 
					          {(results.get('statuses').size > INITIAL_PAGE_LIMIT && results.get('statuses').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreStatuses} />}
 | 
				
			||||||
        </SearchSection>
 | 
					        </SearchSection>
 | 
				
			||||||
@@ -73,7 +78,7 @@ class SearchResults extends ImmutablePureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='search-results'>
 | 
					      <div className='search-results'>
 | 
				
			||||||
        <div className='search-results__header'>
 | 
					        <div className='search-results__header'>
 | 
				
			||||||
          <Icon id='search' fixedWidth />
 | 
					          <Icon id='search' icon={SearchIcon} />
 | 
				
			||||||
          <FormattedMessage id='explore.search_results' defaultMessage='Search results' />
 | 
					          <FormattedMessage id='explore.search_results' defaultMessage='Search results' />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,9 @@ import { FormattedMessage } from 'react-intl';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as InfoIcon } from '@material-symbols/svg-600/outlined/info.svg';
 | 
				
			||||||
import spring from 'react-motion/lib/spring';
 | 
					import spring from 'react-motion/lib/spring';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
@@ -47,13 +50,13 @@ export default class Upload extends ImmutablePureComponent {
 | 
				
			|||||||
          {({ scale }) => (
 | 
					          {({ scale }) => (
 | 
				
			||||||
            <div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
 | 
					            <div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
 | 
				
			||||||
              <div className='compose-form__upload__actions'>
 | 
					              <div className='compose-form__upload__actions'>
 | 
				
			||||||
                <button type='button' className='icon-button' onClick={this.handleUndoClick}><Icon id='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>
 | 
					                <button type='button' className='icon-button' onClick={this.handleUndoClick}><Icon id='times' icon={CloseIcon} /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>
 | 
				
			||||||
                <button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>
 | 
					                <button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' icon={EditIcon} /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              {(media.get('description') || '').length === 0 && (
 | 
					              {(media.get('description') || '').length === 0 && (
 | 
				
			||||||
                <div className='compose-form__upload__warning'>
 | 
					                <div className='compose-form__upload__warning'>
 | 
				
			||||||
                  <button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button>
 | 
					                  <button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' icon={InfoIcon} /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
              )}
 | 
					              )}
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AddPhotoAlternateIcon } from '@material-symbols/svg-600/outlined/add_photo_alternate.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { IconButton } from '../../../components/icon_button';
 | 
					import { IconButton } from '../../../components/icon_button';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
@@ -62,7 +64,7 @@ class UploadButton extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='compose-form__upload-button'>
 | 
					      <div className='compose-form__upload-button'>
 | 
				
			||||||
        <IconButton icon='paperclip' title={message} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} />
 | 
					        <IconButton icon='paperclip' iconComponent={AddPhotoAlternateIcon} title={message} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} />
 | 
				
			||||||
        <label>
 | 
					        <label>
 | 
				
			||||||
          <span style={{ display: 'none' }}>{message}</span>
 | 
					          <span style={{ display: 'none' }}>{message}</span>
 | 
				
			||||||
          <input
 | 
					          <input
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ import { PureComponent } from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { FormattedMessage } from 'react-intl';
 | 
					import { FormattedMessage } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as UploadFileIcon } from '@material-symbols/svg-600/outlined/upload_file.svg';
 | 
				
			||||||
import spring from 'react-motion/lib/spring';
 | 
					import spring from 'react-motion/lib/spring';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
@@ -35,7 +36,7 @@ export default class UploadProgress extends PureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='upload-progress'>
 | 
					      <div className='upload-progress'>
 | 
				
			||||||
        <div className='upload-progress__icon'>
 | 
					        <div className='upload-progress__icon'>
 | 
				
			||||||
          <Icon id='upload' />
 | 
					          <Icon id='upload' icon={UploadFileIcon} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='upload-progress__message'>
 | 
					        <div className='upload-progress__message'>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,13 @@ import { Link } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as LogoutIcon } from '@material-symbols/svg-600/outlined/logout.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as MenuIcon } from '@material-symbols/svg-600/outlined/menu.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as SettingsIcon } from '@material-symbols/svg-600/outlined/settings-fill.svg';
 | 
				
			||||||
import spring from 'react-motion/lib/spring';
 | 
					import spring from 'react-motion/lib/spring';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { openModal } from 'mastodon/actions/modal';
 | 
					import { openModal } from 'mastodon/actions/modal';
 | 
				
			||||||
@@ -101,21 +108,21 @@ class Compose extends PureComponent {
 | 
				
			|||||||
      return (
 | 
					      return (
 | 
				
			||||||
        <div className='drawer' role='region' aria-label={intl.formatMessage(messages.compose)}>
 | 
					        <div className='drawer' role='region' aria-label={intl.formatMessage(messages.compose)}>
 | 
				
			||||||
          <nav className='drawer__header'>
 | 
					          <nav className='drawer__header'>
 | 
				
			||||||
            <Link to='/getting-started' className='drawer__tab' title={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}><Icon id='bars' fixedWidth /></Link>
 | 
					            <Link to='/getting-started' className='drawer__tab' title={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}><Icon id='bars' icon={MenuIcon} /></Link>
 | 
				
			||||||
            {!columns.some(column => column.get('id') === 'HOME') && (
 | 
					            {!columns.some(column => column.get('id') === 'HOME') && (
 | 
				
			||||||
              <Link to='/home' className='drawer__tab' title={intl.formatMessage(messages.home_timeline)} aria-label={intl.formatMessage(messages.home_timeline)}><Icon id='home' fixedWidth /></Link>
 | 
					              <Link to='/home' className='drawer__tab' title={intl.formatMessage(messages.home_timeline)} aria-label={intl.formatMessage(messages.home_timeline)}><Icon id='home' icon={HomeIcon} /></Link>
 | 
				
			||||||
            )}
 | 
					            )}
 | 
				
			||||||
            {!columns.some(column => column.get('id') === 'NOTIFICATIONS') && (
 | 
					            {!columns.some(column => column.get('id') === 'NOTIFICATIONS') && (
 | 
				
			||||||
              <Link to='/notifications' className='drawer__tab' title={intl.formatMessage(messages.notifications)} aria-label={intl.formatMessage(messages.notifications)}><Icon id='bell' fixedWidth /></Link>
 | 
					              <Link to='/notifications' className='drawer__tab' title={intl.formatMessage(messages.notifications)} aria-label={intl.formatMessage(messages.notifications)}><Icon id='bell' icon={NotificationsIcon} /></Link>
 | 
				
			||||||
            )}
 | 
					            )}
 | 
				
			||||||
            {!columns.some(column => column.get('id') === 'COMMUNITY') && (
 | 
					            {!columns.some(column => column.get('id') === 'COMMUNITY') && (
 | 
				
			||||||
              <Link to='/public/local' className='drawer__tab' title={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}><Icon id='users' fixedWidth /></Link>
 | 
					              <Link to='/public/local' className='drawer__tab' title={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}><Icon id='users' icon={PeopleIcon} /></Link>
 | 
				
			||||||
            )}
 | 
					            )}
 | 
				
			||||||
            {!columns.some(column => column.get('id') === 'PUBLIC') && (
 | 
					            {!columns.some(column => column.get('id') === 'PUBLIC') && (
 | 
				
			||||||
              <Link to='/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><Icon id='globe' fixedWidth /></Link>
 | 
					              <Link to='/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><Icon id='globe' icon={PublicIcon} /></Link>
 | 
				
			||||||
            )}
 | 
					            )}
 | 
				
			||||||
            <a href='/settings/preferences' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><Icon id='cog' fixedWidth /></a>
 | 
					            <a href='/settings/preferences' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><Icon id='cog' icon={SettingsIcon} /></a>
 | 
				
			||||||
            <a href='/auth/sign_out' className='drawer__tab' title={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)} onClick={this.handleLogoutClick}><Icon id='sign-out' fixedWidth /></a>
 | 
					            <a href='/auth/sign_out' className='drawer__tab' title={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)} onClick={this.handleLogoutClick}><Icon id='sign-out' icon={LogoutIcon} /></a>
 | 
				
			||||||
          </nav>
 | 
					          </nav>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          {multiColumn && <SearchContainer /> }
 | 
					          {multiColumn && <SearchContainer /> }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,8 @@ import { Link, withRouter } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
 | 
				
			||||||
import { HotKeys } from 'react-hotkeys';
 | 
					import { HotKeys } from 'react-hotkeys';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import AttachmentList from 'mastodon/components/attachment_list';
 | 
					import AttachmentList from 'mastodon/components/attachment_list';
 | 
				
			||||||
@@ -178,7 +180,7 @@ class Conversation extends ImmutablePureComponent {
 | 
				
			|||||||
            )}
 | 
					            )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div className='status__action-bar'>
 | 
					            <div className='status__action-bar'>
 | 
				
			||||||
              <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.reply)} icon='reply' onClick={this.handleReply} />
 | 
					              <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.reply)} icon='reply' iconComponent={ReplyIcon} onClick={this.handleReply} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              <div className='status__action-bar-dropdown'>
 | 
					              <div className='status__action-bar-dropdown'>
 | 
				
			||||||
                <DropdownMenuContainer
 | 
					                <DropdownMenuContainer
 | 
				
			||||||
@@ -186,6 +188,7 @@ class Conversation extends ImmutablePureComponent {
 | 
				
			|||||||
                  status={lastStatus}
 | 
					                  status={lastStatus}
 | 
				
			||||||
                  items={menu}
 | 
					                  items={menu}
 | 
				
			||||||
                  icon='ellipsis-h'
 | 
					                  icon='ellipsis-h'
 | 
				
			||||||
 | 
					                  iconComponent={MoreHorizIcon}
 | 
				
			||||||
                  size={18}
 | 
					                  size={18}
 | 
				
			||||||
                  direction='right'
 | 
					                  direction='right'
 | 
				
			||||||
                  title={intl.formatMessage(messages.more)}
 | 
					                  title={intl.formatMessage(messages.more)}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@ import { Helmet } from 'react-helmet';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
 | 
					import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
 | 
				
			||||||
import { mountConversations, unmountConversations, expandConversations } from 'mastodon/actions/conversations';
 | 
					import { mountConversations, unmountConversations, expandConversations } from 'mastodon/actions/conversations';
 | 
				
			||||||
import { connectDirectStream } from 'mastodon/actions/streaming';
 | 
					import { connectDirectStream } from 'mastodon/actions/streaming';
 | 
				
			||||||
@@ -81,6 +83,7 @@ class DirectTimeline extends PureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='at'
 | 
					          icon='at'
 | 
				
			||||||
 | 
					          iconComponent={AlternateEmailIcon}
 | 
				
			||||||
          active={hasUnread}
 | 
					          active={hasUnread}
 | 
				
			||||||
          title={intl.formatMessage(messages.title)}
 | 
					          title={intl.formatMessage(messages.title)}
 | 
				
			||||||
          onPin={this.handlePin}
 | 
					          onPin={this.handlePin}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,8 @@ import { List as ImmutableList } from 'immutable';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { addColumn, removeColumn, moveColumn, changeColumnParams } from 'mastodon/actions/columns';
 | 
					import { addColumn, removeColumn, moveColumn, changeColumnParams } from 'mastodon/actions/columns';
 | 
				
			||||||
import { fetchDirectory, expandDirectory } from 'mastodon/actions/directory';
 | 
					import { fetchDirectory, expandDirectory } from 'mastodon/actions/directory';
 | 
				
			||||||
import Column from 'mastodon/components/column';
 | 
					import Column from 'mastodon/components/column';
 | 
				
			||||||
@@ -156,6 +158,7 @@ class Directory extends PureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='address-book-o'
 | 
					          icon='address-book-o'
 | 
				
			||||||
 | 
					          iconComponent={PeopleIcon}
 | 
				
			||||||
          title={intl.formatMessage(messages.title)}
 | 
					          title={intl.formatMessage(messages.title)}
 | 
				
			||||||
          onPin={this.handlePin}
 | 
					          onPin={this.handlePin}
 | 
				
			||||||
          onMove={this.handleMove}
 | 
					          onMove={this.handleMove}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,7 +60,7 @@ class Blocks extends ImmutablePureComponent {
 | 
				
			|||||||
    const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no blocked domains yet.' />;
 | 
					    const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no blocked domains yet.' />;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <Column bindToDocument={!multiColumn} icon='minus-circle' heading={intl.formatMessage(messages.heading)}>
 | 
					      <Column bindToDocument={!multiColumn} icon='ban' heading={intl.formatMessage(messages.heading)}>
 | 
				
			||||||
        <ColumnBackButtonSlim />
 | 
					        <ColumnBackButtonSlim />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <ScrollableList
 | 
					        <ScrollableList
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,9 @@ import { NavLink, Switch, Route } from 'react-router-dom';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as SearchIcon } from '@material-symbols/svg-600/outlined/search.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Column from 'mastodon/components/column';
 | 
					import Column from 'mastodon/components/column';
 | 
				
			||||||
import ColumnHeader from 'mastodon/components/column_header';
 | 
					import ColumnHeader from 'mastodon/components/column_header';
 | 
				
			||||||
import Search from 'mastodon/features/compose/containers/search_container';
 | 
					import Search from 'mastodon/features/compose/containers/search_container';
 | 
				
			||||||
@@ -57,6 +60,7 @@ class Explore extends PureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon={isSearching ? 'search' : 'hashtag'}
 | 
					          icon={isSearching ? 'search' : 'hashtag'}
 | 
				
			||||||
 | 
					          iconComponent={isSearching ? SearchIcon : TagIcon}
 | 
				
			||||||
          title={intl.formatMessage(isSearching ? messages.searchResults : messages.title)}
 | 
					          title={intl.formatMessage(isSearching ? messages.searchResults : messages.title)}
 | 
				
			||||||
          onClick={this.handleHeaderClick}
 | 
					          onClick={this.handleHeaderClick}
 | 
				
			||||||
          multiColumn={multiColumn}
 | 
					          multiColumn={multiColumn}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,10 @@ import { List as ImmutableList } from 'immutable';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as FindInPageIcon } from '@material-symbols/svg-600/outlined/find_in_page.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { submitSearch, expandSearch } from 'mastodon/actions/search';
 | 
					import { submitSearch, expandSearch } from 'mastodon/actions/search';
 | 
				
			||||||
import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag';
 | 
					import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag';
 | 
				
			||||||
import { Icon } from 'mastodon/components/icon';
 | 
					import { Icon } from 'mastodon/components/icon';
 | 
				
			||||||
@@ -165,19 +169,19 @@ class Results extends PureComponent {
 | 
				
			|||||||
      filteredResults = (accounts.size + hashtags.size + statuses.size) > 0 ? (
 | 
					      filteredResults = (accounts.size + hashtags.size + statuses.size) > 0 ? (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
          {accounts.size > 0 && (
 | 
					          {accounts.size > 0 && (
 | 
				
			||||||
            <SearchSection key='accounts' title={<><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>} onClickMore={this.handleLoadMoreAccounts}>
 | 
					            <SearchSection key='accounts' title={<><Icon id='users' icon={PeopleIcon} /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>} onClickMore={this.handleLoadMoreAccounts}>
 | 
				
			||||||
              {accounts.take(INITIAL_DISPLAY).map(id => <Account key={id} id={id} />)}
 | 
					              {accounts.take(INITIAL_DISPLAY).map(id => <Account key={id} id={id} />)}
 | 
				
			||||||
            </SearchSection>
 | 
					            </SearchSection>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          {hashtags.size > 0 && (
 | 
					          {hashtags.size > 0 && (
 | 
				
			||||||
            <SearchSection key='hashtags' title={<><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>} onClickMore={this.handleLoadMoreHashtags}>
 | 
					            <SearchSection key='hashtags' title={<><Icon id='hashtag' icon={TagIcon} /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>} onClickMore={this.handleLoadMoreHashtags}>
 | 
				
			||||||
              {hashtags.take(INITIAL_DISPLAY).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
 | 
					              {hashtags.take(INITIAL_DISPLAY).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
 | 
				
			||||||
            </SearchSection>
 | 
					            </SearchSection>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          {statuses.size > 0 && (
 | 
					          {statuses.size > 0 && (
 | 
				
			||||||
            <SearchSection key='statuses' title={<><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>} onClickMore={this.handleLoadMoreStatuses}>
 | 
					            <SearchSection key='statuses' title={<><Icon id='quote-right' icon={FindInPageIcon} /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>} onClickMore={this.handleLoadMoreStatuses}>
 | 
				
			||||||
              {statuses.take(INITIAL_DISPLAY).map(id => <Status key={id} id={id} />)}
 | 
					              {statuses.take(INITIAL_DISPLAY).map(id => <Status key={id} id={id} />)}
 | 
				
			||||||
            </SearchSection>
 | 
					            </SearchSection>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
 | 
					import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
 | 
				
			||||||
@@ -80,6 +81,7 @@ class Favourites extends ImmutablePureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.heading)}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.heading)}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='star'
 | 
					          icon='star'
 | 
				
			||||||
 | 
					          iconComponent={StarIcon}
 | 
				
			||||||
          title={intl.formatMessage(messages.heading)}
 | 
					          title={intl.formatMessage(messages.heading)}
 | 
				
			||||||
          onPin={this.handlePin}
 | 
					          onPin={this.handlePin}
 | 
				
			||||||
          onMove={this.handleMove}
 | 
					          onMove={this.handleMove}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as RefreshIcon } from '@material-symbols/svg-600/outlined/refresh.svg';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { fetchFavourites, expandFavourites } from 'mastodon/actions/interactions';
 | 
					import { fetchFavourites, expandFavourites } from 'mastodon/actions/interactions';
 | 
				
			||||||
@@ -73,7 +74,7 @@ class Favourites extends ImmutablePureComponent {
 | 
				
			|||||||
          showBackButton
 | 
					          showBackButton
 | 
				
			||||||
          multiColumn={multiColumn}
 | 
					          multiColumn={multiColumn}
 | 
				
			||||||
          extraButton={(
 | 
					          extraButton={(
 | 
				
			||||||
            <button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' /></button>
 | 
					            <button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' icon={RefreshIcon} /></button>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
 | 
				
			||||||
import fuzzysort from 'fuzzysort';
 | 
					import fuzzysort from 'fuzzysort';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
@@ -78,7 +79,7 @@ class SelectFilter extends PureComponent {
 | 
				
			|||||||
  renderCreateNew (name) {
 | 
					  renderCreateNew (name) {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div key='add-new-filter' role='button' tabIndex={0} className='language-dropdown__dropdown__results__item' onClick={this.handleNewFilterClick} onKeyDown={this.handleKeyDown}>
 | 
					      <div key='add-new-filter' role='button' tabIndex={0} className='language-dropdown__dropdown__results__item' onClick={this.handleNewFilterClick} onKeyDown={this.handleKeyDown}>
 | 
				
			||||||
        <Icon id='plus' fixedWidth /> <FormattedMessage id='filter_modal.select_filter.prompt_new' defaultMessage='New category: {name}' values={{ name }} />
 | 
					        <Icon id='plus' icon={AddIcon} /> <FormattedMessage id='filter_modal.select_filter.prompt_new' defaultMessage='New category: {name}' values={{ name }} />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,8 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
 | 
				
			|||||||
import { Helmet } from 'react-helmet';
 | 
					import { Helmet } from 'react-helmet';
 | 
				
			||||||
import { NavLink } from 'react-router-dom';
 | 
					import { NavLink } from 'react-router-dom';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { addColumn } from 'mastodon/actions/columns';
 | 
					import { addColumn } from 'mastodon/actions/columns';
 | 
				
			||||||
import { changeSetting } from 'mastodon/actions/settings';
 | 
					import { changeSetting } from 'mastodon/actions/settings';
 | 
				
			||||||
import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming';
 | 
					import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming';
 | 
				
			||||||
@@ -160,6 +162,7 @@ const Firehose = ({ feedType, multiColumn }) => {
 | 
				
			|||||||
    <Column bindToDocument={!multiColumn} ref={columnRef} label={intl.formatMessage(messages.title)}>
 | 
					    <Column bindToDocument={!multiColumn} ref={columnRef} label={intl.formatMessage(messages.title)}>
 | 
				
			||||||
      <ColumnHeader
 | 
					      <ColumnHeader
 | 
				
			||||||
        icon='globe'
 | 
					        icon='globe'
 | 
				
			||||||
 | 
					        iconComponent={PublicIcon}
 | 
				
			||||||
        active={hasUnread}
 | 
					        active={hasUnread}
 | 
				
			||||||
        title={intl.formatMessage(messages.title)}
 | 
					        title={intl.formatMessage(messages.title)}
 | 
				
			||||||
        onPin={handlePin}
 | 
					        onPin={handlePin}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,9 @@ import { Link } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Avatar } from '../../../components/avatar';
 | 
					import { Avatar } from '../../../components/avatar';
 | 
				
			||||||
import { DisplayName } from '../../../components/display_name';
 | 
					import { DisplayName } from '../../../components/display_name';
 | 
				
			||||||
import { IconButton } from '../../../components/icon_button';
 | 
					import { IconButton } from '../../../components/icon_button';
 | 
				
			||||||
@@ -41,8 +44,8 @@ class AccountAuthorize extends ImmutablePureComponent {
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='account--panel'>
 | 
					        <div className='account--panel'>
 | 
				
			||||||
          <div className='account--panel__button'><IconButton title={intl.formatMessage(messages.authorize)} icon='check' onClick={onAuthorize} /></div>
 | 
					          <div className='account--panel__button'><IconButton title={intl.formatMessage(messages.authorize)} icon='check' iconComponent={CheckIcon} onClick={onAuthorize} /></div>
 | 
				
			||||||
          <div className='account--panel__button'><IconButton title={intl.formatMessage(messages.reject)} icon='times' onClick={onReject} /></div>
 | 
					          <div className='account--panel__button'><IconButton title={intl.formatMessage(messages.reject)} icon='times' iconComponent={CloseIcon} onClick={onReject} /></div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { expandFollowedHashtags, fetchFollowedHashtags } from 'mastodon/actions/tags';
 | 
					import { expandFollowedHashtags, fetchFollowedHashtags } from 'mastodon/actions/tags';
 | 
				
			||||||
@@ -55,6 +56,7 @@ class FollowedTags extends ImmutablePureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn}>
 | 
					      <Column bindToDocument={!multiColumn}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='hashtag'
 | 
					          icon='hashtag'
 | 
				
			||||||
 | 
					          iconComponent={TagIcon}
 | 
				
			||||||
          title={intl.formatMessage(messages.heading)}
 | 
					          title={intl.formatMessage(messages.heading)}
 | 
				
			||||||
          showBackButton
 | 
					          showBackButton
 | 
				
			||||||
          multiColumn={multiColumn}
 | 
					          multiColumn={multiColumn}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,9 @@ import { withRouter } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ChevronLeftIcon } from '@material-symbols/svg-600/outlined/chevron_left.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ChevronRightIcon } from '@material-symbols/svg-600/outlined/chevron_right.svg';
 | 
				
			||||||
import TransitionMotion from 'react-motion/lib/TransitionMotion';
 | 
					import TransitionMotion from 'react-motion/lib/TransitionMotion';
 | 
				
			||||||
import spring from 'react-motion/lib/spring';
 | 
					import spring from 'react-motion/lib/spring';
 | 
				
			||||||
import ReactSwipeableViews from 'react-swipeable-views';
 | 
					import ReactSwipeableViews from 'react-swipeable-views';
 | 
				
			||||||
@@ -294,7 +297,7 @@ class ReactionsBar extends ImmutablePureComponent {
 | 
				
			|||||||
              />
 | 
					              />
 | 
				
			||||||
            ))}
 | 
					            ))}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            {visibleReactions.size < 8 && <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={<Icon id='plus' />} />}
 | 
					            {visibleReactions.size < 8 && <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={<Icon id='plus' icon={AddIcon} />} />}
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
      </TransitionMotion>
 | 
					      </TransitionMotion>
 | 
				
			||||||
@@ -440,9 +443,9 @@ class Announcements extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          {announcements.size > 1 && (
 | 
					          {announcements.size > 1 && (
 | 
				
			||||||
            <div className='announcements__pagination'>
 | 
					            <div className='announcements__pagination'>
 | 
				
			||||||
              <IconButton disabled={announcements.size === 1} title={intl.formatMessage(messages.previous)} icon='chevron-left' onClick={this.handlePrevClick} size={13} />
 | 
					              <IconButton disabled={announcements.size === 1} title={intl.formatMessage(messages.previous)} icon='chevron-left' iconComponent={ChevronLeftIcon} onClick={this.handlePrevClick} size={13} />
 | 
				
			||||||
              <span>{index + 1} / {announcements.size}</span>
 | 
					              <span>{index + 1} / {announcements.size}</span>
 | 
				
			||||||
              <IconButton disabled={announcements.size === 1} title={intl.formatMessage(messages.next)} icon='chevron-right' onClick={this.handleNextClick} size={13} />
 | 
					              <IconButton disabled={announcements.size === 1} title={intl.formatMessage(messages.next)} icon='chevron-right' iconComponent={ChevronRightIcon} onClick={this.handleNextClick} size={13} />
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,18 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as BookmarksIcon } from '@material-symbols/svg-600/outlined/bookmarks-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as MenuIcon } from '@material-symbols/svg-600/outlined/menu.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as SettingsIcon } from '@material-symbols/svg-600/outlined/settings-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { fetchFollowRequests } from 'mastodon/actions/accounts';
 | 
					import { fetchFollowRequests } from 'mastodon/actions/accounts';
 | 
				
			||||||
import Column from 'mastodon/components/column';
 | 
					import Column from 'mastodon/components/column';
 | 
				
			||||||
import ColumnHeader from 'mastodon/components/column_header';
 | 
					import ColumnHeader from 'mastodon/components/column_header';
 | 
				
			||||||
@@ -101,38 +113,38 @@ class GettingStarted extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (showTrends) {
 | 
					    if (showTrends) {
 | 
				
			||||||
      navItems.push(
 | 
					      navItems.push(
 | 
				
			||||||
        <ColumnLink key='explore' icon='hashtag' text={intl.formatMessage(messages.explore)} to='/explore' />,
 | 
					        <ColumnLink key='explore' icon='hashtag' iconComponent={TagIcon} text={intl.formatMessage(messages.explore)} to='/explore' />,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    navItems.push(
 | 
					    navItems.push(
 | 
				
			||||||
      <ColumnLink key='community_timeline' icon='users' text={intl.formatMessage(messages.community_timeline)} to='/public/local' />,
 | 
					      <ColumnLink key='community_timeline' icon='users' iconComponent={PeopleIcon} text={intl.formatMessage(messages.community_timeline)} to='/public/local' />,
 | 
				
			||||||
      <ColumnLink key='public_timeline' icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/public' />,
 | 
					      <ColumnLink key='public_timeline' icon='globe' iconComponent={PublicIcon} text={intl.formatMessage(messages.public_timeline)} to='/public' />,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (signedIn) {
 | 
					    if (signedIn) {
 | 
				
			||||||
      navItems.push(
 | 
					      navItems.push(
 | 
				
			||||||
        <ColumnSubheading key='header-personal' text={intl.formatMessage(messages.personal)} />,
 | 
					        <ColumnSubheading key='header-personal' text={intl.formatMessage(messages.personal)} />,
 | 
				
			||||||
        <ColumnLink key='home' icon='home' text={intl.formatMessage(messages.home_timeline)} to='/home' />,
 | 
					        <ColumnLink key='home' icon='home' iconComponent={HomeIcon} text={intl.formatMessage(messages.home_timeline)} to='/home' />,
 | 
				
			||||||
        <ColumnLink key='direct' icon='at' text={intl.formatMessage(messages.direct)} to='/conversations' />,
 | 
					        <ColumnLink key='direct' icon='at' iconComponent={AlternateEmailIcon} text={intl.formatMessage(messages.direct)} to='/conversations' />,
 | 
				
			||||||
        <ColumnLink key='bookmark' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />,
 | 
					        <ColumnLink key='bookmark' icon='bookmarks' iconComponent={BookmarksIcon} text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />,
 | 
				
			||||||
        <ColumnLink key='favourites' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />,
 | 
					        <ColumnLink key='favourites' icon='star' iconComponent={StarIcon} text={intl.formatMessage(messages.favourites)} to='/favourites' />,
 | 
				
			||||||
        <ColumnLink key='lists' icon='list-ul' text={intl.formatMessage(messages.lists)} to='/lists' />,
 | 
					        <ColumnLink key='lists' icon='list-ul' iconComponent={ListAltIcon} text={intl.formatMessage(messages.lists)} to='/lists' />,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (myAccount.get('locked') || unreadFollowRequests > 0) {
 | 
					      if (myAccount.get('locked') || unreadFollowRequests > 0) {
 | 
				
			||||||
        navItems.push(<ColumnLink key='follow_requests' icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
 | 
					        navItems.push(<ColumnLink key='follow_requests' icon='user-plus' iconComponent={PersonAddIcon} text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      navItems.push(
 | 
					      navItems.push(
 | 
				
			||||||
        <ColumnSubheading key='header-settings' text={intl.formatMessage(messages.settings_subheading)} />,
 | 
					        <ColumnSubheading key='header-settings' text={intl.formatMessage(messages.settings_subheading)} />,
 | 
				
			||||||
        <ColumnLink key='preferences' icon='gears' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />,
 | 
					        <ColumnLink key='preferences' icon='cog' iconComponent={SettingsIcon} text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <Column>
 | 
					      <Column>
 | 
				
			||||||
        {(signedIn && !multiColumn) ? <NavigationContainer /> : <ColumnHeader title={intl.formatMessage(messages.menu)} icon='bars' multiColumn={multiColumn} />}
 | 
					        {(signedIn && !multiColumn) ? <NavigationContainer /> : <ColumnHeader title={intl.formatMessage(messages.menu)} icon='bars' iconComponent={MenuIcon} multiColumn={multiColumn} />}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='getting-started scrollable scrollable--flex'>
 | 
					        <div className='getting-started scrollable scrollable--flex'>
 | 
				
			||||||
          <div className='getting-started__wrapper'>
 | 
					          <div className='getting-started__wrapper'>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import { Helmet } from 'react-helmet';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
 | 
				
			||||||
import { isEqual } from 'lodash';
 | 
					import { isEqual } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
 | 
					import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
 | 
				
			||||||
@@ -190,6 +191,7 @@ class HashtagTimeline extends PureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn} ref={this.setRef} label={`#${id}`}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setRef} label={`#${id}`}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='hashtag'
 | 
					          icon='hashtag'
 | 
				
			||||||
 | 
					          iconComponent={TagIcon}
 | 
				
			||||||
          active={hasUnread}
 | 
					          active={hasUnread}
 | 
				
			||||||
          title={this.title()}
 | 
					          title={this.title()}
 | 
				
			||||||
          onPin={this.handlePin}
 | 
					          onPin={this.handlePin}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,9 @@ import { List as ImmutableList } from 'immutable';
 | 
				
			|||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import { createSelector } from 'reselect';
 | 
					import { createSelector } from 'reselect';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CampaignIcon } from '@material-symbols/svg-600/outlined/campaign.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/announcements';
 | 
					import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/announcements';
 | 
				
			||||||
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
 | 
					import { IconWithBadge } from 'mastodon/components/icon_with_badge';
 | 
				
			||||||
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
 | 
					import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
 | 
				
			||||||
@@ -181,7 +184,7 @@ class HomeTimeline extends PureComponent {
 | 
				
			|||||||
          aria-label={intl.formatMessage(showAnnouncements ? messages.hide_announcements : messages.show_announcements)}
 | 
					          aria-label={intl.formatMessage(showAnnouncements ? messages.hide_announcements : messages.show_announcements)}
 | 
				
			||||||
          onClick={this.handleToggleAnnouncementsClick}
 | 
					          onClick={this.handleToggleAnnouncementsClick}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <IconWithBadge id='bullhorn' count={unreadAnnouncements} />
 | 
					          <IconWithBadge id='bullhorn' icon={CampaignIcon} count={unreadAnnouncements} />
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -198,6 +201,7 @@ class HomeTimeline extends PureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='home'
 | 
					          icon='home'
 | 
				
			||||||
 | 
					          iconComponent={HomeIcon}
 | 
				
			||||||
          active={hasUnread}
 | 
					          active={hasUnread}
 | 
				
			||||||
          title={intl.formatMessage(messages.title)}
 | 
					          title={intl.formatMessage(messages.title)}
 | 
				
			||||||
          onPin={this.handlePin}
 | 
					          onPin={this.handlePin}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,10 @@ import classNames from 'classnames';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star.svg';
 | 
				
			||||||
import { throttle, escapeRegExp } from 'lodash';
 | 
					import { throttle, escapeRegExp } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { openModal, closeModal } from 'mastodon/actions/modal';
 | 
					import { openModal, closeModal } from 'mastodon/actions/modal';
 | 
				
			||||||
@@ -354,22 +358,22 @@ class InteractionModal extends React.PureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    switch(type) {
 | 
					    switch(type) {
 | 
				
			||||||
    case 'reply':
 | 
					    case 'reply':
 | 
				
			||||||
      icon = <Icon id='reply' />;
 | 
					      icon = <Icon id='reply' icon={ReplyIcon} />;
 | 
				
			||||||
      title = <FormattedMessage id='interaction_modal.title.reply' defaultMessage="Reply to {name}'s post" values={{ name }} />;
 | 
					      title = <FormattedMessage id='interaction_modal.title.reply' defaultMessage="Reply to {name}'s post" values={{ name }} />;
 | 
				
			||||||
      actionDescription = <FormattedMessage id='interaction_modal.description.reply' defaultMessage='With an account on Mastodon, you can respond to this post.' />;
 | 
					      actionDescription = <FormattedMessage id='interaction_modal.description.reply' defaultMessage='With an account on Mastodon, you can respond to this post.' />;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case 'reblog':
 | 
					    case 'reblog':
 | 
				
			||||||
      icon = <Icon id='retweet' />;
 | 
					      icon = <Icon id='retweet' icon={RepeatIcon} />;
 | 
				
			||||||
      title = <FormattedMessage id='interaction_modal.title.reblog' defaultMessage="Boost {name}'s post" values={{ name }} />;
 | 
					      title = <FormattedMessage id='interaction_modal.title.reblog' defaultMessage="Boost {name}'s post" values={{ name }} />;
 | 
				
			||||||
      actionDescription = <FormattedMessage id='interaction_modal.description.reblog' defaultMessage='With an account on Mastodon, you can boost this post to share it with your own followers.' />;
 | 
					      actionDescription = <FormattedMessage id='interaction_modal.description.reblog' defaultMessage='With an account on Mastodon, you can boost this post to share it with your own followers.' />;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case 'favourite':
 | 
					    case 'favourite':
 | 
				
			||||||
      icon = <Icon id='star' />;
 | 
					      icon = <Icon id='star' icon={StarIcon} />;
 | 
				
			||||||
      title = <FormattedMessage id='interaction_modal.title.favourite' defaultMessage="Favorite {name}'s post" values={{ name }} />;
 | 
					      title = <FormattedMessage id='interaction_modal.title.favourite' defaultMessage="Favorite {name}'s post" values={{ name }} />;
 | 
				
			||||||
      actionDescription = <FormattedMessage id='interaction_modal.description.favourite' defaultMessage='With an account on Mastodon, you can favorite this post to let the author know you appreciate it and save it for later.' />;
 | 
					      actionDescription = <FormattedMessage id='interaction_modal.description.favourite' defaultMessage='With an account on Mastodon, you can favorite this post to let the author know you appreciate it and save it for later.' />;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case 'follow':
 | 
					    case 'follow':
 | 
				
			||||||
      icon = <Icon id='user-plus' />;
 | 
					      icon = <Icon id='user-plus' icon={PersonAddIcon} />;
 | 
				
			||||||
      title = <FormattedMessage id='interaction_modal.title.follow' defaultMessage='Follow {name}' values={{ name }} />;
 | 
					      title = <FormattedMessage id='interaction_modal.title.follow' defaultMessage='Follow {name}' values={{ name }} />;
 | 
				
			||||||
      actionDescription = <FormattedMessage id='interaction_modal.description.follow' defaultMessage='With an account on Mastodon, you can follow {name} to receive their posts in your home feed.' values={{ name }} />;
 | 
					      actionDescription = <FormattedMessage id='interaction_modal.description.follow' defaultMessage='With an account on Mastodon, you can follow {name} to receive their posts in your home feed.' values={{ name }} />;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,8 @@ import { Helmet } from 'react-helmet';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as InfoIcon } from '@material-symbols/svg-600/outlined/info.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Column from 'mastodon/components/column';
 | 
					import Column from 'mastodon/components/column';
 | 
				
			||||||
import ColumnHeader from 'mastodon/components/column_header';
 | 
					import ColumnHeader from 'mastodon/components/column_header';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -27,7 +29,8 @@ class KeyboardShortcuts extends ImmutablePureComponent {
 | 
				
			|||||||
      <Column>
 | 
					      <Column>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          title={intl.formatMessage(messages.heading)}
 | 
					          title={intl.formatMessage(messages.heading)}
 | 
				
			||||||
          icon='question'
 | 
					          icon='info-circle'
 | 
				
			||||||
 | 
					          iconComponent={InfoIcon}
 | 
				
			||||||
          multiColumn={multiColumn}
 | 
					          multiColumn={multiColumn}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { removeFromListAdder, addToListAdder } from '../../../actions/lists';
 | 
					import { removeFromListAdder, addToListAdder } from '../../../actions/lists';
 | 
				
			||||||
@@ -46,16 +50,16 @@ class List extends ImmutablePureComponent {
 | 
				
			|||||||
    let button;
 | 
					    let button;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (added) {
 | 
					    if (added) {
 | 
				
			||||||
      button = <IconButton icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
 | 
					      button = <IconButton icon='times' iconComponent={CloseIcon} title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      button = <IconButton icon='plus' title={intl.formatMessage(messages.add)} onClick={onAdd} />;
 | 
					      button = <IconButton icon='plus' iconComponent={AddIcon} title={intl.formatMessage(messages.add)} onClick={onAdd} />;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='list'>
 | 
					      <div className='list'>
 | 
				
			||||||
        <div className='list__wrapper'>
 | 
					        <div className='list__wrapper'>
 | 
				
			||||||
          <div className='list__display-name'>
 | 
					          <div className='list__display-name'>
 | 
				
			||||||
            <Icon id='list-ul' className='column-link__icon' fixedWidth />
 | 
					            <Icon id='list-ul' icon={ListAltIcon} className='column-link__icon' />
 | 
				
			||||||
            {list.get('title')}
 | 
					            {list.get('title')}
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { removeFromListEditor, addToListEditor } from '../../../actions/lists';
 | 
					import { removeFromListEditor, addToListEditor } from '../../../actions/lists';
 | 
				
			||||||
import { Avatar } from '../../../components/avatar';
 | 
					import { Avatar } from '../../../components/avatar';
 | 
				
			||||||
import { DisplayName } from '../../../components/display_name';
 | 
					import { DisplayName } from '../../../components/display_name';
 | 
				
			||||||
@@ -53,9 +56,9 @@ class Account extends ImmutablePureComponent {
 | 
				
			|||||||
    let button;
 | 
					    let button;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (added) {
 | 
					    if (added) {
 | 
				
			||||||
      button = <IconButton icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
 | 
					      button = <IconButton icon='times' iconComponent={CloseIcon} title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      button = <IconButton icon='plus' title={intl.formatMessage(messages.add)} onClick={onAdd} />;
 | 
					      button = <IconButton icon='plus' iconComponent={AddIcon} title={intl.formatMessage(messages.add)} onClick={onAdd} />;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@ import { defineMessages, injectIntl } from 'react-intl';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { changeListEditorTitle, submitListEditor } from '../../../actions/lists';
 | 
					import { changeListEditorTitle, submitListEditor } from '../../../actions/lists';
 | 
				
			||||||
import { IconButton } from '../../../components/icon_button';
 | 
					import { IconButton } from '../../../components/icon_button';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,6 +63,7 @@ class ListForm extends PureComponent {
 | 
				
			|||||||
        <IconButton
 | 
					        <IconButton
 | 
				
			||||||
          disabled={disabled}
 | 
					          disabled={disabled}
 | 
				
			||||||
          icon='check'
 | 
					          icon='check'
 | 
				
			||||||
 | 
					          iconComponent={CheckIcon}
 | 
				
			||||||
          title={title}
 | 
					          title={title}
 | 
				
			||||||
          onClick={this.handleClick}
 | 
					          onClick={this.handleClick}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,9 @@ import classNames from 'classnames';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CancelIcon } from '@material-symbols/svg-600/outlined/cancel.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as SearchIcon } from '@material-symbols/svg-600/outlined/search.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../actions/lists';
 | 
					import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../actions/lists';
 | 
				
			||||||
@@ -69,8 +72,8 @@ class Search extends PureComponent {
 | 
				
			|||||||
        </label>
 | 
					        </label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
 | 
					        <div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
 | 
				
			||||||
          <Icon id='search' className={classNames({ active: !hasValue })} />
 | 
					          <Icon id='search' icon={SearchIcon} className={classNames({ active: !hasValue })} />
 | 
				
			||||||
          <Icon id='times-circle' aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} />
 | 
					          <Icon id='times-circle' icon={CancelIcon} aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,9 @@ import { withRouter } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as DeleteIcon } from '@material-symbols/svg-600/outlined/delete.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
 | 
				
			||||||
import Toggle from 'react-toggle';
 | 
					import Toggle from 'react-toggle';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
 | 
					import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
 | 
				
			||||||
@@ -181,6 +184,7 @@ class ListTimeline extends PureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn} ref={this.setRef} label={title}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setRef} label={title}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='list-ul'
 | 
					          icon='list-ul'
 | 
				
			||||||
 | 
					          iconComponent={ListAltIcon}
 | 
				
			||||||
          active={hasUnread}
 | 
					          active={hasUnread}
 | 
				
			||||||
          title={title}
 | 
					          title={title}
 | 
				
			||||||
          onPin={this.handlePin}
 | 
					          onPin={this.handlePin}
 | 
				
			||||||
@@ -191,11 +195,11 @@ class ListTimeline extends PureComponent {
 | 
				
			|||||||
        >
 | 
					        >
 | 
				
			||||||
          <div className='column-settings__row column-header__links'>
 | 
					          <div className='column-settings__row column-header__links'>
 | 
				
			||||||
            <button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleEditClick}>
 | 
					            <button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleEditClick}>
 | 
				
			||||||
              <Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
 | 
					              <Icon id='pencil' icon={EditIcon} /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
 | 
				
			||||||
            </button>
 | 
					            </button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleDeleteClick}>
 | 
					            <button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleDeleteClick}>
 | 
				
			||||||
              <Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
 | 
					              <Icon id='trash' icon={DeleteIcon} /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
 | 
				
			||||||
            </button>
 | 
					            </button>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			|||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import { createSelector } from 'reselect';
 | 
					import { createSelector } from 'reselect';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { fetchLists } from 'mastodon/actions/lists';
 | 
					import { fetchLists } from 'mastodon/actions/lists';
 | 
				
			||||||
import Column from 'mastodon/components/column';
 | 
					import Column from 'mastodon/components/column';
 | 
				
			||||||
import ColumnHeader from 'mastodon/components/column_header';
 | 
					import ColumnHeader from 'mastodon/components/column_header';
 | 
				
			||||||
@@ -65,7 +67,7 @@ class Lists extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.heading)}>
 | 
					      <Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.heading)}>
 | 
				
			||||||
        <ColumnHeader title={intl.formatMessage(messages.heading)} icon='list-ul' multiColumn={multiColumn} />
 | 
					        <ColumnHeader title={intl.formatMessage(messages.heading)} icon='list-ul' iconComponent={ListAltIcon} multiColumn={multiColumn} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <NewListForm />
 | 
					        <NewListForm />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -76,7 +78,7 @@ class Lists extends ImmutablePureComponent {
 | 
				
			|||||||
          bindToDocument={!multiColumn}
 | 
					          bindToDocument={!multiColumn}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          {lists.map(list =>
 | 
					          {lists.map(list =>
 | 
				
			||||||
            <ColumnLink key={list.get('id')} to={`/lists/${list.get('id')}`} icon='list-ul' text={list.get('title')} />,
 | 
					            <ColumnLink key={list.get('id')} to={`/lists/${list.get('id')}`} icon='list-ul' iconComponent={ListAltIcon} text={list.get('title')} />,
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
        </ScrollableList>
 | 
					        </ScrollableList>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off.svg';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { fetchMutes, expandMutes } from '../../actions/mutes';
 | 
					import { fetchMutes, expandMutes } from '../../actions/mutes';
 | 
				
			||||||
@@ -61,7 +62,7 @@ class Mutes extends ImmutablePureComponent {
 | 
				
			|||||||
    const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />;
 | 
					    const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <Column bindToDocument={!multiColumn} icon='volume-off' heading={intl.formatMessage(messages.heading)}>
 | 
					      <Column bindToDocument={!multiColumn} icon='volume-off' iconComponent={VolumeOffIcon} heading={intl.formatMessage(messages.heading)}>
 | 
				
			||||||
        <ColumnBackButtonSlim />
 | 
					        <ColumnBackButtonSlim />
 | 
				
			||||||
        <ScrollableList
 | 
					        <ScrollableList
 | 
				
			||||||
          scrollKey='mutes'
 | 
					          scrollKey='mutes'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,8 @@ import { PureComponent } from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { FormattedMessage } from 'react-intl';
 | 
					import { FormattedMessage } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as DeleteForeverIcon } from '@material-symbols/svg-600/outlined/delete_forever.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class ClearColumnButton extends PureComponent {
 | 
					export default class ClearColumnButton extends PureComponent {
 | 
				
			||||||
@@ -13,7 +15,7 @@ export default class ClearColumnButton extends PureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <button className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.props.onClick}><Icon id='eraser' /> <FormattedMessage id='notifications.clear' defaultMessage='Clear notifications' /></button>
 | 
					      <button className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.props.onClick}><Icon id='eraser' icon={DeleteForeverIcon} /> <FormattedMessage id='notifications.clear' defaultMessage='Clear notifications' /></button>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,13 @@ import { PureComponent } from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
					import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlined/reply_all.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const tooltips = defineMessages({
 | 
					const tooltips = defineMessages({
 | 
				
			||||||
@@ -66,42 +73,42 @@ class FilterBar extends PureComponent {
 | 
				
			|||||||
          onClick={this.onClick('mention')}
 | 
					          onClick={this.onClick('mention')}
 | 
				
			||||||
          title={intl.formatMessage(tooltips.mentions)}
 | 
					          title={intl.formatMessage(tooltips.mentions)}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <Icon id='reply-all' fixedWidth />
 | 
					          <Icon id='reply-all' icon={ReplyAllIcon} />
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          className={selectedFilter === 'favourite' ? 'active' : ''}
 | 
					          className={selectedFilter === 'favourite' ? 'active' : ''}
 | 
				
			||||||
          onClick={this.onClick('favourite')}
 | 
					          onClick={this.onClick('favourite')}
 | 
				
			||||||
          title={intl.formatMessage(tooltips.favourites)}
 | 
					          title={intl.formatMessage(tooltips.favourites)}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <Icon id='star' fixedWidth />
 | 
					          <Icon id='star' icon={StarIcon} />
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          className={selectedFilter === 'reblog' ? 'active' : ''}
 | 
					          className={selectedFilter === 'reblog' ? 'active' : ''}
 | 
				
			||||||
          onClick={this.onClick('reblog')}
 | 
					          onClick={this.onClick('reblog')}
 | 
				
			||||||
          title={intl.formatMessage(tooltips.boosts)}
 | 
					          title={intl.formatMessage(tooltips.boosts)}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <Icon id='retweet' fixedWidth />
 | 
					          <Icon id='retweet' icon={RepeatIcon} />
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          className={selectedFilter === 'poll' ? 'active' : ''}
 | 
					          className={selectedFilter === 'poll' ? 'active' : ''}
 | 
				
			||||||
          onClick={this.onClick('poll')}
 | 
					          onClick={this.onClick('poll')}
 | 
				
			||||||
          title={intl.formatMessage(tooltips.polls)}
 | 
					          title={intl.formatMessage(tooltips.polls)}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <Icon id='tasks' fixedWidth />
 | 
					          <Icon id='tasks' icon={InsertChartIcon} />
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          className={selectedFilter === 'status' ? 'active' : ''}
 | 
					          className={selectedFilter === 'status' ? 'active' : ''}
 | 
				
			||||||
          onClick={this.onClick('status')}
 | 
					          onClick={this.onClick('status')}
 | 
				
			||||||
          title={intl.formatMessage(tooltips.statuses)}
 | 
					          title={intl.formatMessage(tooltips.statuses)}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <Icon id='home' fixedWidth />
 | 
					          <Icon id='home' icon={HomeIcon} />
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          className={selectedFilter === 'follow' ? 'active' : ''}
 | 
					          className={selectedFilter === 'follow' ? 'active' : ''}
 | 
				
			||||||
          onClick={this.onClick('follow')}
 | 
					          onClick={this.onClick('follow')}
 | 
				
			||||||
          title={intl.formatMessage(tooltips.follows)}
 | 
					          title={intl.formatMessage(tooltips.follows)}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <Icon id='user-plus' fixedWidth />
 | 
					          <Icon id='user-plus' icon={PersonAddIcon} />
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,9 @@ import { Link } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Avatar } from 'mastodon/components/avatar';
 | 
					import { Avatar } from 'mastodon/components/avatar';
 | 
				
			||||||
import { DisplayName } from 'mastodon/components/display_name';
 | 
					import { DisplayName } from 'mastodon/components/display_name';
 | 
				
			||||||
import { IconButton } from 'mastodon/components/icon_button';
 | 
					import { IconButton } from 'mastodon/components/icon_button';
 | 
				
			||||||
@@ -50,8 +53,8 @@ class FollowRequest extends ImmutablePureComponent {
 | 
				
			|||||||
          </Link>
 | 
					          </Link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <div className='account__relationship'>
 | 
					          <div className='account__relationship'>
 | 
				
			||||||
            <IconButton title={intl.formatMessage(messages.authorize)} icon='check' onClick={onAuthorize} />
 | 
					            <IconButton title={intl.formatMessage(messages.authorize)} icon='check' iconComponent={CheckIcon} onClick={onAuthorize} />
 | 
				
			||||||
            <IconButton title={intl.formatMessage(messages.reject)} icon='times' onClick={onReject} />
 | 
					            <IconButton title={intl.formatMessage(messages.reject)} icon='times' iconComponent={CloseIcon} onClick={onReject} />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,14 @@ import { Link, withRouter } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as FlagIcon } from '@material-symbols/svg-600/outlined/flag-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PersonIcon } from '@material-symbols/svg-600/outlined/person-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
 | 
				
			||||||
import { HotKeys } from 'react-hotkeys';
 | 
					import { HotKeys } from 'react-hotkeys';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
@@ -128,9 +136,7 @@ class Notification extends ImmutablePureComponent {
 | 
				
			|||||||
      <HotKeys handlers={this.getHandlers()}>
 | 
					      <HotKeys handlers={this.getHandlers()}>
 | 
				
			||||||
        <div className={classNames('notification notification-follow focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.follow, { name: account.get('acct') }), notification.get('created_at'))}>
 | 
					        <div className={classNames('notification notification-follow focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.follow, { name: account.get('acct') }), notification.get('created_at'))}>
 | 
				
			||||||
          <div className='notification__message'>
 | 
					          <div className='notification__message'>
 | 
				
			||||||
            <div className='notification__favourite-icon-wrapper'>
 | 
					            <Icon id='user-plus' icon={PersonAddIcon} />
 | 
				
			||||||
              <Icon id='user-plus' fixedWidth />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <span title={notification.get('created_at')}>
 | 
					            <span title={notification.get('created_at')}>
 | 
				
			||||||
              <FormattedMessage id='notification.follow' defaultMessage='{name} followed you' values={{ name: link }} />
 | 
					              <FormattedMessage id='notification.follow' defaultMessage='{name} followed you' values={{ name: link }} />
 | 
				
			||||||
@@ -150,9 +156,7 @@ class Notification extends ImmutablePureComponent {
 | 
				
			|||||||
      <HotKeys handlers={this.getHandlers()}>
 | 
					      <HotKeys handlers={this.getHandlers()}>
 | 
				
			||||||
        <div className={classNames('notification notification-follow-request focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.follow_request', defaultMessage: '{name} has requested to follow you' }, { name: account.get('acct') }), notification.get('created_at'))}>
 | 
					        <div className={classNames('notification notification-follow-request focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.follow_request', defaultMessage: '{name} has requested to follow you' }, { name: account.get('acct') }), notification.get('created_at'))}>
 | 
				
			||||||
          <div className='notification__message'>
 | 
					          <div className='notification__message'>
 | 
				
			||||||
            <div className='notification__favourite-icon-wrapper'>
 | 
					            <Icon id='user' icon={PersonIcon} />
 | 
				
			||||||
              <Icon id='user' fixedWidth />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <span title={notification.get('created_at')}>
 | 
					            <span title={notification.get('created_at')}>
 | 
				
			||||||
              <FormattedMessage id='notification.follow_request' defaultMessage='{name} has requested to follow you' values={{ name: link }} />
 | 
					              <FormattedMessage id='notification.follow_request' defaultMessage='{name} has requested to follow you' values={{ name: link }} />
 | 
				
			||||||
@@ -190,9 +194,7 @@ class Notification extends ImmutablePureComponent {
 | 
				
			|||||||
      <HotKeys handlers={this.getHandlers()}>
 | 
					      <HotKeys handlers={this.getHandlers()}>
 | 
				
			||||||
        <div className={classNames('notification notification-favourite focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.favourite, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
 | 
					        <div className={classNames('notification notification-favourite focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.favourite, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
 | 
				
			||||||
          <div className='notification__message'>
 | 
					          <div className='notification__message'>
 | 
				
			||||||
            <div className='notification__favourite-icon-wrapper'>
 | 
					            <Icon id='star' icon={StarIcon} className='star-icon' />
 | 
				
			||||||
              <Icon id='star' className='star-icon' fixedWidth />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <span title={notification.get('created_at')}>
 | 
					            <span title={notification.get('created_at')}>
 | 
				
			||||||
              <FormattedMessage id='notification.favourite' defaultMessage='{name} favorited your status' values={{ name: link }} />
 | 
					              <FormattedMessage id='notification.favourite' defaultMessage='{name} favorited your status' values={{ name: link }} />
 | 
				
			||||||
@@ -222,9 +224,7 @@ class Notification extends ImmutablePureComponent {
 | 
				
			|||||||
      <HotKeys handlers={this.getHandlers()}>
 | 
					      <HotKeys handlers={this.getHandlers()}>
 | 
				
			||||||
        <div className={classNames('notification notification-reblog focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.reblog, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
 | 
					        <div className={classNames('notification notification-reblog focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.reblog, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
 | 
				
			||||||
          <div className='notification__message'>
 | 
					          <div className='notification__message'>
 | 
				
			||||||
            <div className='notification__favourite-icon-wrapper'>
 | 
					            <Icon id='retweet' icon={RepeatIcon} />
 | 
				
			||||||
              <Icon id='retweet' fixedWidth />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <span title={notification.get('created_at')}>
 | 
					            <span title={notification.get('created_at')}>
 | 
				
			||||||
              <FormattedMessage id='notification.reblog' defaultMessage='{name} boosted your status' values={{ name: link }} />
 | 
					              <FormattedMessage id='notification.reblog' defaultMessage='{name} boosted your status' values={{ name: link }} />
 | 
				
			||||||
@@ -258,9 +258,7 @@ class Notification extends ImmutablePureComponent {
 | 
				
			|||||||
      <HotKeys handlers={this.getHandlers()}>
 | 
					      <HotKeys handlers={this.getHandlers()}>
 | 
				
			||||||
        <div className={classNames('notification notification-status focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.status, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
 | 
					        <div className={classNames('notification notification-status focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.status, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
 | 
				
			||||||
          <div className='notification__message'>
 | 
					          <div className='notification__message'>
 | 
				
			||||||
            <div className='notification__favourite-icon-wrapper'>
 | 
					            <Icon id='home' icon={HomeIcon} />
 | 
				
			||||||
              <Icon id='home' fixedWidth />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <span title={notification.get('created_at')}>
 | 
					            <span title={notification.get('created_at')}>
 | 
				
			||||||
              <FormattedMessage id='notification.status' defaultMessage='{name} just posted' values={{ name: link }} />
 | 
					              <FormattedMessage id='notification.status' defaultMessage='{name} just posted' values={{ name: link }} />
 | 
				
			||||||
@@ -295,9 +293,7 @@ class Notification extends ImmutablePureComponent {
 | 
				
			|||||||
      <HotKeys handlers={this.getHandlers()}>
 | 
					      <HotKeys handlers={this.getHandlers()}>
 | 
				
			||||||
        <div className={classNames('notification notification-update focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.update, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
 | 
					        <div className={classNames('notification notification-update focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.update, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
 | 
				
			||||||
          <div className='notification__message'>
 | 
					          <div className='notification__message'>
 | 
				
			||||||
            <div className='notification__favourite-icon-wrapper'>
 | 
					            <Icon id='pencil' icon={EditIcon} />
 | 
				
			||||||
              <Icon id='pencil' fixedWidth />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <span title={notification.get('created_at')}>
 | 
					            <span title={notification.get('created_at')}>
 | 
				
			||||||
              <FormattedMessage id='notification.update' defaultMessage='{name} edited a post' values={{ name: link }} />
 | 
					              <FormattedMessage id='notification.update' defaultMessage='{name} edited a post' values={{ name: link }} />
 | 
				
			||||||
@@ -334,9 +330,7 @@ class Notification extends ImmutablePureComponent {
 | 
				
			|||||||
      <HotKeys handlers={this.getHandlers()}>
 | 
					      <HotKeys handlers={this.getHandlers()}>
 | 
				
			||||||
        <div className={classNames('notification notification-poll focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, message, notification.get('created_at'))}>
 | 
					        <div className={classNames('notification notification-poll focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, message, notification.get('created_at'))}>
 | 
				
			||||||
          <div className='notification__message'>
 | 
					          <div className='notification__message'>
 | 
				
			||||||
            <div className='notification__favourite-icon-wrapper'>
 | 
					            <Icon id='tasks' icon={InsertChartIcon} />
 | 
				
			||||||
              <Icon id='tasks' fixedWidth />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <span title={notification.get('created_at')}>
 | 
					            <span title={notification.get('created_at')}>
 | 
				
			||||||
              {ownPoll ? (
 | 
					              {ownPoll ? (
 | 
				
			||||||
@@ -371,9 +365,7 @@ class Notification extends ImmutablePureComponent {
 | 
				
			|||||||
      <HotKeys handlers={this.getHandlers()}>
 | 
					      <HotKeys handlers={this.getHandlers()}>
 | 
				
			||||||
        <div className={classNames('notification notification-admin-sign-up focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminSignUp, { name: account.get('acct') }), notification.get('created_at'))}>
 | 
					        <div className={classNames('notification notification-admin-sign-up focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminSignUp, { name: account.get('acct') }), notification.get('created_at'))}>
 | 
				
			||||||
          <div className='notification__message'>
 | 
					          <div className='notification__message'>
 | 
				
			||||||
            <div className='notification__favourite-icon-wrapper'>
 | 
					            <Icon id='user-plus' icon={PersonAddIcon} />
 | 
				
			||||||
              <Icon id='user-plus' fixedWidth />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <span title={notification.get('created_at')}>
 | 
					            <span title={notification.get('created_at')}>
 | 
				
			||||||
              <FormattedMessage id='notification.admin.sign_up' defaultMessage='{name} signed up' values={{ name: link }} />
 | 
					              <FormattedMessage id='notification.admin.sign_up' defaultMessage='{name} signed up' values={{ name: link }} />
 | 
				
			||||||
@@ -401,9 +393,7 @@ class Notification extends ImmutablePureComponent {
 | 
				
			|||||||
      <HotKeys handlers={this.getHandlers()}>
 | 
					      <HotKeys handlers={this.getHandlers()}>
 | 
				
			||||||
        <div className={classNames('notification notification-admin-report focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminReport, { name: account.get('acct'), target: notification.getIn(['report', 'target_account', 'acct']) }), notification.get('created_at'))}>
 | 
					        <div className={classNames('notification notification-admin-report focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminReport, { name: account.get('acct'), target: notification.getIn(['report', 'target_account', 'acct']) }), notification.get('created_at'))}>
 | 
				
			||||||
          <div className='notification__message'>
 | 
					          <div className='notification__message'>
 | 
				
			||||||
            <div className='notification__favourite-icon-wrapper'>
 | 
					            <Icon id='flag' icon={FlagIcon} />
 | 
				
			||||||
              <Icon id='flag' fixedWidth />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <span title={notification.get('created_at')}>
 | 
					            <span title={notification.get('created_at')}>
 | 
				
			||||||
              <FormattedMessage id='notification.admin.report' defaultMessage='{name} reported {target}' values={{ name: link, target: targetLink }} />
 | 
					              <FormattedMessage id='notification.admin.report' defaultMessage='{name} reported {target}' values={{ name: link, target: targetLink }} />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,9 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as TuneIcon } from '@material-symbols/svg-600/outlined/tune.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { requestBrowserPermission } from 'mastodon/actions/notifications';
 | 
					import { requestBrowserPermission } from 'mastodon/actions/notifications';
 | 
				
			||||||
import { changeSetting } from 'mastodon/actions/settings';
 | 
					import { changeSetting } from 'mastodon/actions/settings';
 | 
				
			||||||
import { Button } from 'mastodon/components/button';
 | 
					import { Button } from 'mastodon/components/button';
 | 
				
			||||||
@@ -36,11 +39,11 @@ class NotificationsPermissionBanner extends PureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='notifications-permission-banner'>
 | 
					      <div className='notifications-permission-banner'>
 | 
				
			||||||
        <div className='notifications-permission-banner__close'>
 | 
					        <div className='notifications-permission-banner__close'>
 | 
				
			||||||
          <IconButton icon='times' onClick={this.handleClose} title={intl.formatMessage(messages.close)} />
 | 
					          <IconButton icon='times' iconComponent={CloseIcon} onClick={this.handleClose} title={intl.formatMessage(messages.close)} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <h2><FormattedMessage id='notifications_permission_banner.title' defaultMessage='Never miss a thing' /></h2>
 | 
					        <h2><FormattedMessage id='notifications_permission_banner.title' defaultMessage='Never miss a thing' /></h2>
 | 
				
			||||||
        <p><FormattedMessage id='notifications_permission_banner.how_to_control' defaultMessage="To receive notifications when Mastodon isn't open, enable desktop notifications. You can control precisely which types of interactions generate desktop notifications through the {icon} button above once they're enabled." values={{ icon: <Icon id='sliders' /> }} /></p>
 | 
					        <p><FormattedMessage id='notifications_permission_banner.how_to_control' defaultMessage="To receive notifications when Mastodon isn't open, enable desktop notifications. You can control precisely which types of interactions generate desktop notifications through the {icon} button above once they're enabled." values={{ icon: <Icon id='sliders' icon={TuneIcon} /> }} /></p>
 | 
				
			||||||
        <Button onClick={this.handleClick}><FormattedMessage id='notifications_permission_banner.enable' defaultMessage='Enable desktop notifications' /></Button>
 | 
					        <Button onClick={this.handleClick}><FormattedMessage id='notifications_permission_banner.enable' defaultMessage='Enable desktop notifications' /></Button>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import { createSelector } from 'reselect';
 | 
					import { createSelector } from 'reselect';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as DoneAllIcon } from '@material-symbols/svg-600/outlined/done_all.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { compareId } from 'mastodon/compare_id';
 | 
					import { compareId } from 'mastodon/compare_id';
 | 
				
			||||||
@@ -260,7 +262,7 @@ class Notifications extends PureComponent {
 | 
				
			|||||||
          onClick={this.handleMarkAsRead}
 | 
					          onClick={this.handleMarkAsRead}
 | 
				
			||||||
          className='column-header__button'
 | 
					          className='column-header__button'
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <Icon id='check' />
 | 
					          <Icon id='done-all' icon={DoneAllIcon} />
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -269,6 +271,7 @@ class Notifications extends PureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn} ref={this.setColumnRef} label={intl.formatMessage(messages.title)}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setColumnRef} label={intl.formatMessage(messages.title)}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='bell'
 | 
					          icon='bell'
 | 
				
			||||||
 | 
					          iconComponent={NotificationsIcon}
 | 
				
			||||||
          active={isUnread}
 | 
					          active={isUnread}
 | 
				
			||||||
          title={intl.formatMessage(messages.title)}
 | 
					          title={intl.formatMessage(messages.title)}
 | 
				
			||||||
          onPin={this.handlePin}
 | 
					          onPin={this.handlePin}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +0,0 @@
 | 
				
			|||||||
const ArrowSmallRight = () => (
 | 
					 | 
				
			||||||
  <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='currentColor'>
 | 
					 | 
				
			||||||
    <path fillRule='evenodd' d='M5 10a.75.75 0 01.75-.75h6.638L10.23 7.29a.75.75 0 111.04-1.08l3.5 3.25a.75.75 0 010 1.08l-3.5 3.25a.75.75 0 11-1.04-1.08l2.158-1.96H5.75A.75.75 0 015 10z' clipRule='evenodd' />
 | 
					 | 
				
			||||||
  </svg>
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default ArrowSmallRight;
 | 
					 | 
				
			||||||
@@ -3,7 +3,9 @@ import { Fragment } from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import classNames from 'classnames';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Check } from 'mastodon/components/check';
 | 
					import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/done.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProgressIndicator = ({ steps, completed }) => (
 | 
					const ProgressIndicator = ({ steps, completed }) => (
 | 
				
			||||||
  <div className='onboarding__progress-indicator'>
 | 
					  <div className='onboarding__progress-indicator'>
 | 
				
			||||||
@@ -12,7 +14,7 @@ const ProgressIndicator = ({ steps, completed }) => (
 | 
				
			|||||||
        {i > 0 && <div className={classNames('onboarding__progress-indicator__line', { active: completed > i })} />}
 | 
					        {i > 0 && <div className={classNames('onboarding__progress-indicator__line', { active: completed > i })} />}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className={classNames('onboarding__progress-indicator__step', { active: completed > i })}>
 | 
					        <div className={classNames('onboarding__progress-indicator__step', { active: completed > i })}>
 | 
				
			||||||
          {completed > i && <Check />}
 | 
					          {completed > i && <Icon icon={CheckIcon} />}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </Fragment>
 | 
					      </Fragment>
 | 
				
			||||||
    ))}
 | 
					    ))}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,15 @@
 | 
				
			|||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Check } from 'mastodon/components/check';
 | 
					import { ReactComponent as ArrowRightAltIcon } from '@material-symbols/svg-600/outlined/arrow_right_alt.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/done.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ArrowSmallRight from './arrow_small_right';
 | 
					const Step = ({ label, description, icon, iconComponent, completed, onClick, href }) => {
 | 
				
			||||||
 | 
					 | 
				
			||||||
const Step = ({ label, description, icon, completed, onClick, href }) => {
 | 
					 | 
				
			||||||
  const content = (
 | 
					  const content = (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <div className='onboarding__steps__item__icon'>
 | 
					      <div className='onboarding__steps__item__icon'>
 | 
				
			||||||
        <Icon id={icon} />
 | 
					        <Icon id={icon} icon={iconComponent} />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div className='onboarding__steps__item__description'>
 | 
					      <div className='onboarding__steps__item__description'>
 | 
				
			||||||
@@ -18,7 +18,7 @@ const Step = ({ label, description, icon, completed, onClick, href }) => {
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div className={completed ? 'onboarding__steps__item__progress' : 'onboarding__steps__item__go'}>
 | 
					      <div className={completed ? 'onboarding__steps__item__progress' : 'onboarding__steps__item__go'}>
 | 
				
			||||||
        {completed ? <Check /> : <ArrowSmallRight />}
 | 
					        {completed ? <Icon icon={CheckIcon} /> : <Icon icon={ArrowRightAltIcon} />}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
@@ -42,6 +42,7 @@ Step.propTypes = {
 | 
				
			|||||||
  label: PropTypes.node,
 | 
					  label: PropTypes.node,
 | 
				
			||||||
  description: PropTypes.node,
 | 
					  description: PropTypes.node,
 | 
				
			||||||
  icon: PropTypes.string,
 | 
					  icon: PropTypes.string,
 | 
				
			||||||
 | 
					  iconComponent: PropTypes.func,
 | 
				
			||||||
  completed: PropTypes.bool,
 | 
					  completed: PropTypes.bool,
 | 
				
			||||||
  href: PropTypes.string,
 | 
					  href: PropTypes.string,
 | 
				
			||||||
  onClick: PropTypes.func,
 | 
					  onClick: PropTypes.func,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,19 +9,24 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AccountCircleIcon } from '@material-symbols/svg-600/outlined/account_circle.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ArrowRightAltIcon } from '@material-symbols/svg-600/outlined/arrow_right_alt.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ContentCopyIcon } from '@material-symbols/svg-600/outlined/content_copy.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as EditNoteIcon } from '@material-symbols/svg-600/outlined/edit_note.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import illustration from 'mastodon/../images/elephant_ui_conversation.svg';
 | 
					import illustration from 'mastodon/../images/elephant_ui_conversation.svg';
 | 
				
			||||||
import { fetchAccount } from 'mastodon/actions/accounts';
 | 
					import { fetchAccount } from 'mastodon/actions/accounts';
 | 
				
			||||||
import { focusCompose } from 'mastodon/actions/compose';
 | 
					import { focusCompose } from 'mastodon/actions/compose';
 | 
				
			||||||
import { closeOnboarding } from 'mastodon/actions/onboarding';
 | 
					import { closeOnboarding } from 'mastodon/actions/onboarding';
 | 
				
			||||||
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import Column from 'mastodon/features/ui/components/column';
 | 
					import Column from 'mastodon/features/ui/components/column';
 | 
				
			||||||
import { me } from 'mastodon/initial_state';
 | 
					import { me } from 'mastodon/initial_state';
 | 
				
			||||||
import { makeGetAccount } from 'mastodon/selectors';
 | 
					import { makeGetAccount } from 'mastodon/selectors';
 | 
				
			||||||
import { assetHost } from 'mastodon/utils/config';
 | 
					import { assetHost } from 'mastodon/utils/config';
 | 
				
			||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
					import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ArrowSmallRight from './components/arrow_small_right';
 | 
					 | 
				
			||||||
import Step from './components/step';
 | 
					import Step from './components/step';
 | 
				
			||||||
import Follows from './follows';
 | 
					import Follows from './follows';
 | 
				
			||||||
import Share from './share';
 | 
					import Share from './share';
 | 
				
			||||||
@@ -115,10 +120,10 @@ class Onboarding extends ImmutablePureComponent {
 | 
				
			|||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <div className='onboarding__steps'>
 | 
					          <div className='onboarding__steps'>
 | 
				
			||||||
            <Step onClick={this.handleProfileClick} href='/settings/profile' completed={(!account.get('avatar').endsWith('missing.png')) || (account.get('display_name').length > 0 && account.get('note').length > 0)} icon='address-book-o' label={<FormattedMessage id='onboarding.steps.setup_profile.title' defaultMessage='Customize your profile' />} description={<FormattedMessage id='onboarding.steps.setup_profile.body' defaultMessage='Others are more likely to interact with you with a filled out profile.' />} />
 | 
					            <Step onClick={this.handleProfileClick} href='/settings/profile' completed={(!account.get('avatar').endsWith('missing.png')) || (account.get('display_name').length > 0 && account.get('note').length > 0)} icon='address-book-o' iconComponent={AccountCircleIcon} label={<FormattedMessage id='onboarding.steps.setup_profile.title' defaultMessage='Customize your profile' />} description={<FormattedMessage id='onboarding.steps.setup_profile.body' defaultMessage='Others are more likely to interact with you with a filled out profile.' />} />
 | 
				
			||||||
            <Step onClick={this.handleFollowClick} completed={(account.get('following_count') * 1) >= 7} icon='user-plus' label={<FormattedMessage id='onboarding.steps.follow_people.title' defaultMessage='Find at least {count, plural, one {one person} other {# people}} to follow' values={{ count: 7 }} />} description={<FormattedMessage id='onboarding.steps.follow_people.body' defaultMessage="You curate your own home feed. Let's fill it with interesting people." />} />
 | 
					            <Step onClick={this.handleFollowClick} completed={(account.get('following_count') * 1) >= 7} icon='user-plus' iconComponent={PersonAddIcon} label={<FormattedMessage id='onboarding.steps.follow_people.title' defaultMessage='Find at least {count, plural, one {one person} other {# people}} to follow' values={{ count: 7 }} />} description={<FormattedMessage id='onboarding.steps.follow_people.body' defaultMessage="You curate your own home feed. Let's fill it with interesting people." />} />
 | 
				
			||||||
            <Step onClick={this.handleComposeClick} completed={(account.get('statuses_count') * 1) >= 1} icon='pencil-square-o' label={<FormattedMessage id='onboarding.steps.publish_status.title' defaultMessage='Make your first post' />} description={<FormattedMessage id='onboarding.steps.publish_status.body' defaultMessage='Say hello to the world.' values={{ emoji: <img className='emojione' alt='🐘' src={`${assetHost}/emoji/1f418.svg`} /> }} />} />
 | 
					            <Step onClick={this.handleComposeClick} completed={(account.get('statuses_count') * 1) >= 1} icon='pencil-square-o' iconComponent={EditNoteIcon} label={<FormattedMessage id='onboarding.steps.publish_status.title' defaultMessage='Make your first post' />} description={<FormattedMessage id='onboarding.steps.publish_status.body' defaultMessage='Say hello to the world.' values={{ emoji: <img className='emojione' alt='🐘' src={`${assetHost}/emoji/1f418.svg`} /> }} />} />
 | 
				
			||||||
            <Step onClick={this.handleShareClick} completed={shareClicked} icon='copy' label={<FormattedMessage id='onboarding.steps.share_profile.title' defaultMessage='Share your profile' />} description={<FormattedMessage id='onboarding.steps.share_profile.body' defaultMessage='Let your friends know how to find you on Mastodon!' />} />
 | 
					            <Step onClick={this.handleShareClick} completed={shareClicked} icon='copy' iconComponent={ContentCopyIcon} label={<FormattedMessage id='onboarding.steps.share_profile.title' defaultMessage='Share your profile' />} description={<FormattedMessage id='onboarding.steps.share_profile.body' defaultMessage='Let your friends know how to find you on Mastodon!' />} />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <p className='onboarding__lead'><FormattedMessage id='onboarding.start.skip' defaultMessage="Don't need help getting started?" /></p>
 | 
					          <p className='onboarding__lead'><FormattedMessage id='onboarding.start.skip' defaultMessage="Don't need help getting started?" /></p>
 | 
				
			||||||
@@ -126,12 +131,12 @@ class Onboarding extends ImmutablePureComponent {
 | 
				
			|||||||
          <div className='onboarding__links'>
 | 
					          <div className='onboarding__links'>
 | 
				
			||||||
            <Link to='/explore' className='onboarding__link'>
 | 
					            <Link to='/explore' className='onboarding__link'>
 | 
				
			||||||
              <FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' />
 | 
					              <FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' />
 | 
				
			||||||
              <ArrowSmallRight />
 | 
					              <Icon icon={ArrowRightAltIcon} />
 | 
				
			||||||
            </Link>
 | 
					            </Link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <Link to='/home' className='onboarding__link'>
 | 
					            <Link to='/home' className='onboarding__link'>
 | 
				
			||||||
              <FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' />
 | 
					              <FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' />
 | 
				
			||||||
              <ArrowSmallRight />
 | 
					              <Icon icon={ArrowRightAltIcon} />
 | 
				
			||||||
            </Link>
 | 
					            </Link>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,8 @@ import { Link } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as ArrowRightAltIcon } from '@material-symbols/svg-600/outlined/arrow_right_alt.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ContentCopyIcon } from '@material-symbols/svg-600/outlined/content_copy.svg';
 | 
				
			||||||
import SwipeableViews from 'react-swipeable-views';
 | 
					import SwipeableViews from 'react-swipeable-views';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Column from 'mastodon/components/column';
 | 
					import Column from 'mastodon/components/column';
 | 
				
			||||||
@@ -16,8 +18,6 @@ import ColumnBackButton from 'mastodon/components/column_back_button';
 | 
				
			|||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import { me, domain } from 'mastodon/initial_state';
 | 
					import { me, domain } from 'mastodon/initial_state';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ArrowSmallRight from './components/arrow_small_right';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
  shareableMessage: { id: 'onboarding.share.message', defaultMessage: 'I\'m {username} on #Mastodon! Come follow me at {url}' },
 | 
					  shareableMessage: { id: 'onboarding.share.message', defaultMessage: 'I\'m {username} on #Mastodon! Come follow me at {url}' },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
@@ -79,7 +79,7 @@ class CopyPasteText extends PureComponent {
 | 
				
			|||||||
        <textarea readOnly value={value} ref={this.setRef} onClick={this.handleInputClick} onFocus={this.handleFocus} onBlur={this.handleBlur} />
 | 
					        <textarea readOnly value={value} ref={this.setRef} onClick={this.handleInputClick} onFocus={this.handleFocus} onBlur={this.handleBlur} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <button className='button' onClick={this.handleButtonClick}>
 | 
					        <button className='button' onClick={this.handleButtonClick}>
 | 
				
			||||||
          <Icon id='copy' /> {copied ? <FormattedMessage id='copypaste.copied' defaultMessage='Copied' /> : <FormattedMessage id='copypaste.copy_to_clipboard' defaultMessage='Copy to clipboard' />}
 | 
					          <Icon id='copy' icon={ContentCopyIcon} /> {copied ? <FormattedMessage id='copypaste.copied' defaultMessage='Copied' /> : <FormattedMessage id='copypaste.copy_to_clipboard' defaultMessage='Copy to clipboard' />}
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -178,12 +178,12 @@ class Share extends PureComponent {
 | 
				
			|||||||
          <div className='onboarding__links'>
 | 
					          <div className='onboarding__links'>
 | 
				
			||||||
            <Link to='/home' className='onboarding__link'>
 | 
					            <Link to='/home' className='onboarding__link'>
 | 
				
			||||||
              <FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' />
 | 
					              <FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' />
 | 
				
			||||||
              <ArrowSmallRight />
 | 
					              <Icon icon={ArrowRightAltIcon} />
 | 
				
			||||||
            </Link>
 | 
					            </Link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <Link to='/explore' className='onboarding__link'>
 | 
					            <Link to='/explore' className='onboarding__link'>
 | 
				
			||||||
              <FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' />
 | 
					              <FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' />
 | 
				
			||||||
              <ArrowSmallRight />
 | 
					              <Icon icon={ArrowRightAltIcon} />
 | 
				
			||||||
            </Link>
 | 
					            </Link>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,12 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as OpenInNewIcon } from '@material-symbols/svg-600/outlined/open_in_new.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlined/reply_all.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { initBoostModal } from 'mastodon/actions/boosts';
 | 
					import { initBoostModal } from 'mastodon/actions/boosts';
 | 
				
			||||||
import { replyCompose } from 'mastodon/actions/compose';
 | 
					import { replyCompose } from 'mastodon/actions/compose';
 | 
				
			||||||
import { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions';
 | 
					import { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions';
 | 
				
			||||||
@@ -169,13 +175,15 @@ class Footer extends ImmutablePureComponent {
 | 
				
			|||||||
    const publicStatus  = ['public', 'unlisted'].includes(status.get('visibility'));
 | 
					    const publicStatus  = ['public', 'unlisted'].includes(status.get('visibility'));
 | 
				
			||||||
    const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
 | 
					    const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let replyIcon, replyTitle;
 | 
					    let replyIcon, replyIconComponent, replyTitle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (status.get('in_reply_to_id', null) === null) {
 | 
					    if (status.get('in_reply_to_id', null) === null) {
 | 
				
			||||||
      replyIcon = 'reply';
 | 
					      replyIcon = 'reply';
 | 
				
			||||||
 | 
					      replyIconComponent = RepeatIcon;
 | 
				
			||||||
      replyTitle = intl.formatMessage(messages.reply);
 | 
					      replyTitle = intl.formatMessage(messages.reply);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      replyIcon = 'reply-all';
 | 
					      replyIcon = 'reply-all';
 | 
				
			||||||
 | 
					      replyIconComponent = ReplyAllIcon;
 | 
				
			||||||
      replyTitle = intl.formatMessage(messages.replyAll);
 | 
					      replyTitle = intl.formatMessage(messages.replyAll);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -193,10 +201,10 @@ class Footer extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='picture-in-picture__footer'>
 | 
					      <div className='picture-in-picture__footer'>
 | 
				
			||||||
        <IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
 | 
					        <IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
 | 
				
			||||||
        <IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate}  active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
 | 
					        <IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate}  active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
 | 
				
			||||||
        <IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
 | 
					        <IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={StarIcon} onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
 | 
				
			||||||
        {withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' onClick={this.handleOpenClick} href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} />}
 | 
					        {withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' iconComponent={OpenInNewIcon} onClick={this.handleOpenClick} href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} />}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Avatar } from 'mastodon/components/avatar';
 | 
					import { Avatar } from 'mastodon/components/avatar';
 | 
				
			||||||
import { DisplayName } from 'mastodon/components/display_name';
 | 
					import { DisplayName } from 'mastodon/components/display_name';
 | 
				
			||||||
import { IconButton } from 'mastodon/components/icon_button';
 | 
					import { IconButton } from 'mastodon/components/icon_button';
 | 
				
			||||||
@@ -40,7 +42,7 @@ class Header extends ImmutablePureComponent {
 | 
				
			|||||||
          <DisplayName account={account} />
 | 
					          <DisplayName account={account} />
 | 
				
			||||||
        </Link>
 | 
					        </Link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <IconButton icon='times' onClick={onClose} title={intl.formatMessage(messages.close)} />
 | 
					        <IconButton icon='times' iconComponent={CloseIcon} onClick={onClose} title={intl.formatMessage(messages.close)} />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as PushPinIcon } from '@material-symbols/svg-600/outlined/push_pin.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { getStatusList } from 'mastodon/selectors';
 | 
					import { getStatusList } from 'mastodon/selectors';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { fetchPinnedStatuses } from '../../actions/pin_statuses';
 | 
					import { fetchPinnedStatuses } from '../../actions/pin_statuses';
 | 
				
			||||||
@@ -50,7 +52,7 @@ class PinnedStatuses extends ImmutablePureComponent {
 | 
				
			|||||||
    const { intl, statusIds, hasMore, multiColumn } = this.props;
 | 
					    const { intl, statusIds, hasMore, multiColumn } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <Column bindToDocument={!multiColumn} icon='thumb-tack' heading={intl.formatMessage(messages.heading)} ref={this.setRef}>
 | 
					      <Column bindToDocument={!multiColumn} icon='thumb-tack' iconComponent={PushPinIcon} heading={intl.formatMessage(messages.heading)} ref={this.setRef}>
 | 
				
			||||||
        <ColumnBackButtonSlim />
 | 
					        <ColumnBackButtonSlim />
 | 
				
			||||||
        <StatusList
 | 
					        <StatusList
 | 
				
			||||||
          statusIds={statusIds}
 | 
					          statusIds={statusIds}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@ import { Helmet } from 'react-helmet';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
 | 
					import { DismissableBanner } from 'mastodon/components/dismissable_banner';
 | 
				
			||||||
import { domain } from 'mastodon/initial_state';
 | 
					import { domain } from 'mastodon/initial_state';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,6 +133,7 @@ class PublicTimeline extends PureComponent {
 | 
				
			|||||||
      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
					      <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
 | 
				
			||||||
        <ColumnHeader
 | 
					        <ColumnHeader
 | 
				
			||||||
          icon='globe'
 | 
					          icon='globe'
 | 
				
			||||||
 | 
					          iconComponent={PublicIcon}
 | 
				
			||||||
          active={hasUnread}
 | 
					          active={hasUnread}
 | 
				
			||||||
          title={intl.formatMessage(messages.title)}
 | 
					          title={intl.formatMessage(messages.title)}
 | 
				
			||||||
          onPin={this.handlePin}
 | 
					          onPin={this.handlePin}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as RefreshIcon } from '@material-symbols/svg-600/outlined/refresh.svg';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
@@ -74,7 +75,7 @@ class Reblogs extends ImmutablePureComponent {
 | 
				
			|||||||
          showBackButton
 | 
					          showBackButton
 | 
				
			||||||
          multiColumn={multiColumn}
 | 
					          multiColumn={multiColumn}
 | 
				
			||||||
          extraButton={(
 | 
					          extraButton={(
 | 
				
			||||||
            <button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' /></button>
 | 
					            <button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' icon={RefreshIcon} /></button>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,9 @@ import { PureComponent } from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import classNames from 'classnames';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Check } from 'mastodon/components/check';
 | 
					import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/done.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class Option extends PureComponent {
 | 
					export default class Option extends PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,7 +49,7 @@ export default class Option extends PureComponent {
 | 
				
			|||||||
          onKeyPress={this.handleKeyPress}
 | 
					          onKeyPress={this.handleKeyPress}
 | 
				
			||||||
          aria-checked={checked}
 | 
					          aria-checked={checked}
 | 
				
			||||||
          aria-label={label}
 | 
					          aria-label={label}
 | 
				
			||||||
        >{checked && <Check />}</span>
 | 
					        >{checked && <Icon icon={CheckIcon} />}</span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {labelComponent ? labelComponent : (
 | 
					        {labelComponent ? labelComponent : (
 | 
				
			||||||
          <span className='poll__option__text'>
 | 
					          <span className='poll__option__text'>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,26 +1,17 @@
 | 
				
			|||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import { PureComponent } from 'react';
 | 
					import { PureComponent } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { injectIntl, defineMessages } from 'react-intl';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Avatar } from 'mastodon/components/avatar';
 | 
					import { Avatar } from 'mastodon/components/avatar';
 | 
				
			||||||
import { DisplayName } from 'mastodon/components/display_name';
 | 
					import { DisplayName } from 'mastodon/components/display_name';
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					 | 
				
			||||||
import MediaAttachments from 'mastodon/components/media_attachments';
 | 
					import MediaAttachments from 'mastodon/components/media_attachments';
 | 
				
			||||||
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
 | 
					import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
 | 
				
			||||||
import StatusContent from 'mastodon/components/status_content';
 | 
					import StatusContent from 'mastodon/components/status_content';
 | 
				
			||||||
 | 
					import { VisibilityIcon } from 'mastodon/components/visibility_icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Option from './option';
 | 
					import Option from './option';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					 | 
				
			||||||
  public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
 | 
					 | 
				
			||||||
  unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
 | 
					 | 
				
			||||||
  private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
 | 
					 | 
				
			||||||
  direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StatusCheckBox extends PureComponent {
 | 
					class StatusCheckBox extends PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
@@ -37,21 +28,12 @@ class StatusCheckBox extends PureComponent {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { status, checked, intl } = this.props;
 | 
					    const { status, checked } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (status.get('reblog')) {
 | 
					    if (status.get('reblog')) {
 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const visibilityIconInfo = {
 | 
					 | 
				
			||||||
      'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
 | 
					 | 
				
			||||||
      'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
 | 
					 | 
				
			||||||
      'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
 | 
					 | 
				
			||||||
      'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const visibilityIcon = visibilityIconInfo[status.get('visibility')];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const labelComponent = (
 | 
					    const labelComponent = (
 | 
				
			||||||
      <div className='status-check-box__status poll__option__text'>
 | 
					      <div className='status-check-box__status poll__option__text'>
 | 
				
			||||||
        <div className='detailed-status__display-name'>
 | 
					        <div className='detailed-status__display-name'>
 | 
				
			||||||
@@ -60,7 +42,7 @@ class StatusCheckBox extends PureComponent {
 | 
				
			|||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <div>
 | 
					          <div>
 | 
				
			||||||
            <DisplayName account={status.get('account')} /> · <span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span> <RelativeTimestamp timestamp={status.get('created_at')} />
 | 
					            <DisplayName account={status.get('account')} /> · <span className='status__visibility-icon'><VisibilityIcon visibility={status.get('visibility')} /></span> <RelativeTimestamp timestamp={status.get('created_at')} />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -84,4 +66,4 @@ class StatusCheckBox extends PureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default injectIntl(StatusCheckBox);
 | 
					export default StatusCheckBox;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,15 @@ import { withRouter } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as BookmarkIcon } from '@material-symbols/svg-600/outlined/bookmark-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as BookmarkBorderIcon } from '@material-symbols/svg-600/outlined/bookmark.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlined/reply_all.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
 | 
					import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
 | 
				
			||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
					import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -270,10 +279,13 @@ class ActionBar extends PureComponent {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let replyIcon;
 | 
					    let replyIcon;
 | 
				
			||||||
 | 
					    let replyIconComponent;
 | 
				
			||||||
    if (status.get('in_reply_to_id', null) === null) {
 | 
					    if (status.get('in_reply_to_id', null) === null) {
 | 
				
			||||||
      replyIcon = 'reply';
 | 
					      replyIcon = 'reply';
 | 
				
			||||||
 | 
					      replyIconComponent = ReplyIcon;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      replyIcon = 'reply-all';
 | 
					      replyIcon = 'reply-all';
 | 
				
			||||||
 | 
					      replyIconComponent = ReplyAllIcon;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
 | 
					    const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
 | 
				
			||||||
@@ -291,13 +303,13 @@ class ActionBar extends PureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='detailed-status__action-bar'>
 | 
					      <div className='detailed-status__action-bar'>
 | 
				
			||||||
        <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div>
 | 
					        <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent}  onClick={this.handleReplyClick} /></div>
 | 
				
			||||||
        <div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} /></div>
 | 
					        <div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} /></div>
 | 
				
			||||||
        <div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>
 | 
					        <div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} /></div>
 | 
				
			||||||
        <div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div>
 | 
					        <div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} /></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='detailed-status__action-bar-dropdown'>
 | 
					        <div className='detailed-status__action-bar-dropdown'>
 | 
				
			||||||
          <DropdownMenuContainer size={18} icon='ellipsis-h' status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} />
 | 
					          <DropdownMenuContainer icon='ellipsis-h' iconComponent={MoreHorizIcon} status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,10 @@ import classNames from 'classnames';
 | 
				
			|||||||
import Immutable from 'immutable';
 | 
					import Immutable from 'immutable';
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as DescriptionIcon } from '@material-symbols/svg-600/outlined/description.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as OpenInNewIcon } from '@material-symbols/svg-600/outlined/open_in_new.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Blurhash } from 'mastodon/components/blurhash';
 | 
					import { Blurhash } from 'mastodon/components/blurhash';
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
 | 
					import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
 | 
				
			||||||
@@ -197,8 +201,8 @@ export default class Card extends PureComponent {
 | 
				
			|||||||
            {revealed ? (
 | 
					            {revealed ? (
 | 
				
			||||||
              <div className='status-card__actions' onClick={this.handleEmbedClick} role='none'>
 | 
					              <div className='status-card__actions' onClick={this.handleEmbedClick} role='none'>
 | 
				
			||||||
                <div>
 | 
					                <div>
 | 
				
			||||||
                  <button type='button' onClick={this.handleEmbedClick}><Icon id='play' /></button>
 | 
					                  <button type='button' onClick={this.handleEmbedClick}><Icon id='play' icon={PlayArrowIcon} /></button>
 | 
				
			||||||
                  <a href={card.get('url')} target='_blank' rel='noopener noreferrer'><Icon id='external-link' /></a>
 | 
					                  <a href={card.get('url')} target='_blank' rel='noopener noreferrer'><Icon id='external-link' icon={OpenInNewIcon} /></a>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
            ) : spoilerButton}
 | 
					            ) : spoilerButton}
 | 
				
			||||||
@@ -222,7 +226,7 @@ export default class Card extends PureComponent {
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      embed = (
 | 
					      embed = (
 | 
				
			||||||
        <div className='status-card__image'>
 | 
					        <div className='status-card__image'>
 | 
				
			||||||
          <Icon id='file-text' />
 | 
					          <Icon id='file-text' icon={DescriptionIcon} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { injectIntl, defineMessages, FormattedDate, FormattedMessage } from 'react-intl';
 | 
					import { FormattedDate, FormattedMessage } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import classNames from 'classnames';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
import { Link, withRouter } from 'react-router-dom';
 | 
					import { Link, withRouter } from 'react-router-dom';
 | 
				
			||||||
@@ -8,11 +8,16 @@ import { Link, withRouter } from 'react-router-dom';
 | 
				
			|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { AnimatedNumber } from 'mastodon/components/animated_number';
 | 
					import { AnimatedNumber } from 'mastodon/components/animated_number';
 | 
				
			||||||
import EditedTimestamp from 'mastodon/components/edited_timestamp';
 | 
					import EditedTimestamp from 'mastodon/components/edited_timestamp';
 | 
				
			||||||
import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
 | 
					import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
 | 
					import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
 | 
				
			||||||
 | 
					import { VisibilityIcon } from 'mastodon/components/visibility_icon';
 | 
				
			||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
					import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Avatar } from '../../../components/avatar';
 | 
					import { Avatar } from '../../../components/avatar';
 | 
				
			||||||
@@ -25,13 +30,6 @@ import Video from '../../video';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import Card from './card';
 | 
					import Card from './card';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					 | 
				
			||||||
  public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
 | 
					 | 
				
			||||||
  unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
 | 
					 | 
				
			||||||
  private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
 | 
					 | 
				
			||||||
  direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class DetailedStatus extends ImmutablePureComponent {
 | 
					class DetailedStatus extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
@@ -137,7 +135,7 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			|||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const status = this._properStatus();
 | 
					    const status = this._properStatus();
 | 
				
			||||||
    const outerStyle = { boxSizing: 'border-box' };
 | 
					    const outerStyle = { boxSizing: 'border-box' };
 | 
				
			||||||
    const { intl, compact, pictureInPicture } = this.props;
 | 
					    const { compact, pictureInPicture } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!status) {
 | 
					    if (!status) {
 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
@@ -146,7 +144,8 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			|||||||
    let media           = '';
 | 
					    let media           = '';
 | 
				
			||||||
    let applicationLink = '';
 | 
					    let applicationLink = '';
 | 
				
			||||||
    let reblogLink = '';
 | 
					    let reblogLink = '';
 | 
				
			||||||
    let reblogIcon = 'retweet';
 | 
					    const reblogIcon = 'retweet';
 | 
				
			||||||
 | 
					    const reblogIconComponent = RepeatIcon;
 | 
				
			||||||
    let favouriteLink = '';
 | 
					    let favouriteLink = '';
 | 
				
			||||||
    let edited = '';
 | 
					    let edited = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -223,15 +222,7 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			|||||||
      applicationLink = <> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></>;
 | 
					      applicationLink = <> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></>;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const visibilityIconInfo = {
 | 
					    const visibilityLink = <> · <VisibilityIcon visibility={status.get('visibility')} /></>;
 | 
				
			||||||
      'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
 | 
					 | 
				
			||||||
      'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
 | 
					 | 
				
			||||||
      'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
 | 
					 | 
				
			||||||
      'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const visibilityIcon = visibilityIconInfo[status.get('visibility')];
 | 
					 | 
				
			||||||
    const visibilityLink = <> · <Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></>;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (['private', 'direct'].includes(status.get('visibility'))) {
 | 
					    if (['private', 'direct'].includes(status.get('visibility'))) {
 | 
				
			||||||
      reblogLink = '';
 | 
					      reblogLink = '';
 | 
				
			||||||
@@ -240,7 +231,7 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			|||||||
        <>
 | 
					        <>
 | 
				
			||||||
          {' · '}
 | 
					          {' · '}
 | 
				
			||||||
          <Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`} className='detailed-status__link'>
 | 
					          <Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`} className='detailed-status__link'>
 | 
				
			||||||
            <Icon id={reblogIcon} />
 | 
					            <Icon id={reblogIcon} icon={reblogIconComponent} />
 | 
				
			||||||
            <span className='detailed-status__reblogs'>
 | 
					            <span className='detailed-status__reblogs'>
 | 
				
			||||||
              <AnimatedNumber value={status.get('reblogs_count')} />
 | 
					              <AnimatedNumber value={status.get('reblogs_count')} />
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
@@ -252,7 +243,7 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			|||||||
        <>
 | 
					        <>
 | 
				
			||||||
          {' · '}
 | 
					          {' · '}
 | 
				
			||||||
          <a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
 | 
					          <a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
 | 
				
			||||||
            <Icon id={reblogIcon} />
 | 
					            <Icon id={reblogIcon} icon={reblogIconComponent} />
 | 
				
			||||||
            <span className='detailed-status__reblogs'>
 | 
					            <span className='detailed-status__reblogs'>
 | 
				
			||||||
              <AnimatedNumber value={status.get('reblogs_count')} />
 | 
					              <AnimatedNumber value={status.get('reblogs_count')} />
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
@@ -264,7 +255,7 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			|||||||
    if (this.props.history) {
 | 
					    if (this.props.history) {
 | 
				
			||||||
      favouriteLink = (
 | 
					      favouriteLink = (
 | 
				
			||||||
        <Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/favourites`} className='detailed-status__link'>
 | 
					        <Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/favourites`} className='detailed-status__link'>
 | 
				
			||||||
          <Icon id='star' />
 | 
					          <Icon id='star' icon={StarIcon} />
 | 
				
			||||||
          <span className='detailed-status__favorites'>
 | 
					          <span className='detailed-status__favorites'>
 | 
				
			||||||
            <AnimatedNumber value={status.get('favourites_count')} />
 | 
					            <AnimatedNumber value={status.get('favourites_count')} />
 | 
				
			||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
@@ -273,7 +264,7 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      favouriteLink = (
 | 
					      favouriteLink = (
 | 
				
			||||||
        <a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
 | 
					        <a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
 | 
				
			||||||
          <Icon id='star' />
 | 
					          <Icon id='star' icon={StarIcon} />
 | 
				
			||||||
          <span className='detailed-status__favorites'>
 | 
					          <span className='detailed-status__favorites'>
 | 
				
			||||||
            <AnimatedNumber value={status.get('favourites_count')} />
 | 
					            <AnimatedNumber value={status.get('favourites_count')} />
 | 
				
			||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
@@ -298,7 +289,7 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			|||||||
        <div ref={this.setRef} className={classNames('detailed-status', { compact })}>
 | 
					        <div ref={this.setRef} className={classNames('detailed-status', { compact })}>
 | 
				
			||||||
          {status.get('visibility') === 'direct' && (
 | 
					          {status.get('visibility') === 'direct' && (
 | 
				
			||||||
            <div className='status__prepend'>
 | 
					            <div className='status__prepend'>
 | 
				
			||||||
              <div className='status__prepend-icon-wrapper'><Icon id='at' className='status__prepend-icon' fixedWidth /></div>
 | 
					              <div className='status__prepend-icon-wrapper'><Icon id='at' icon={AlternateEmailIcon} className='status__prepend-icon' /></div>
 | 
				
			||||||
              <FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
 | 
					              <FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
@@ -331,4 +322,4 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default withRouter(injectIntl(DetailedStatus));
 | 
					export default withRouter(DetailedStatus);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			|||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import { createSelector } from 'reselect';
 | 
					import { createSelector } from 'reselect';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as VisibilityIcon } from '@material-symbols/svg-600/outlined/visibility.svg';
 | 
				
			||||||
 | 
					import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
 | 
				
			||||||
import { HotKeys } from 'react-hotkeys';
 | 
					import { HotKeys } from 'react-hotkeys';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
@@ -685,7 +687,7 @@ class Status extends ImmutablePureComponent {
 | 
				
			|||||||
          showBackButton
 | 
					          showBackButton
 | 
				
			||||||
          multiColumn={multiColumn}
 | 
					          multiColumn={multiColumn}
 | 
				
			||||||
          extraButton={(
 | 
					          extraButton={(
 | 
				
			||||||
            <button type='button' className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} /></button>
 | 
					            <button type='button' className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} icon={status.get('hidden') ? VisibilityOffIcon : VisibilityIcon} /></button>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			|||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import { createSelector } from 'reselect';
 | 
					import { createSelector } from 'reselect';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { followAccount } from 'mastodon/actions/accounts';
 | 
					import { followAccount } from 'mastodon/actions/accounts';
 | 
				
			||||||
import { Button } from 'mastodon/components/button';
 | 
					import { Button } from 'mastodon/components/button';
 | 
				
			||||||
import { IconButton } from 'mastodon/components/icon_button';
 | 
					import { IconButton } from 'mastodon/components/icon_button';
 | 
				
			||||||
@@ -101,7 +103,7 @@ class SubscribedLanguagesModal extends ImmutablePureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='modal-root__modal report-dialog-modal'>
 | 
					      <div className='modal-root__modal report-dialog-modal'>
 | 
				
			||||||
        <div className='report-modal__target'>
 | 
					        <div className='report-modal__target'>
 | 
				
			||||||
          <IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={20} />
 | 
					          <IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={20} />
 | 
				
			||||||
          <FormattedMessage id='subscribed_languages.target' defaultMessage='Change subscribed languages for {target}' values={{ target: <strong>{acct}</strong> }} />
 | 
					          <FormattedMessage id='subscribed_languages.target' defaultMessage='Change subscribed languages for {target}' values={{ target: <strong>{acct}</strong> }} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,12 +20,12 @@ export default class ActionsModal extends ImmutablePureComponent {
 | 
				
			|||||||
      return <li key={`sep-${i}`} className='dropdown-menu__separator' />;
 | 
					      return <li key={`sep-${i}`} className='dropdown-menu__separator' />;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { icon = null, text, meta = null, active = false, href = '#' } = action;
 | 
					    const { icon = null, iconComponent = null, text, meta = null, active = false, href = '#' } = action;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <li key={`${text}-${i}`}>
 | 
					      <li key={`${text}-${i}`}>
 | 
				
			||||||
        <a href={href} target='_blank' rel='noopener noreferrer' onClick={this.props.onClick} data-index={i} className={classNames({ active })}>
 | 
					        <a href={href} target='_blank' rel='noopener noreferrer' onClick={this.props.onClick} data-index={i} className={classNames({ active })}>
 | 
				
			||||||
          {icon && <IconButton title={text} icon={icon} role='presentation' tabIndex={-1} inverted />}
 | 
					          {icon && <IconButton title={text} icon={icon} iconComponent={iconComponent} role='presentation' tabIndex={-1} inverted />}
 | 
				
			||||||
          <div>
 | 
					          <div>
 | 
				
			||||||
            <div className={classNames({ 'actions-modal__item-label': !!meta })}>{text}</div>
 | 
					            <div className={classNames({ 'actions-modal__item-label': !!meta })}>{text}</div>
 | 
				
			||||||
            <div>{meta}</div>
 | 
					            <div>{meta}</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,9 +9,12 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { changeBoostPrivacy } from 'mastodon/actions/boosts';
 | 
					import { changeBoostPrivacy } from 'mastodon/actions/boosts';
 | 
				
			||||||
import AttachmentList from 'mastodon/components/attachment_list';
 | 
					import AttachmentList from 'mastodon/components/attachment_list';
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					import { VisibilityIcon } from 'mastodon/components/visibility_icon';
 | 
				
			||||||
import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdown';
 | 
					import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdown';
 | 
				
			||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
					import { WithRouterPropTypes } from 'mastodon/utils/react_router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,10 +27,6 @@ import StatusContent from '../../../components/status_content';
 | 
				
			|||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
  cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
 | 
					  cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
 | 
				
			||||||
  reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
 | 
					  reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
 | 
				
			||||||
  public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
 | 
					 | 
				
			||||||
  unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
 | 
					 | 
				
			||||||
  private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
 | 
					 | 
				
			||||||
  direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapStateToProps = state => {
 | 
					const mapStateToProps = state => {
 | 
				
			||||||
@@ -76,22 +75,13 @@ class BoostModal extends ImmutablePureComponent {
 | 
				
			|||||||
    const { status, privacy, intl } = this.props;
 | 
					    const { status, privacy, intl } = this.props;
 | 
				
			||||||
    const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;
 | 
					    const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const visibilityIconInfo = {
 | 
					 | 
				
			||||||
      'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
 | 
					 | 
				
			||||||
      'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
 | 
					 | 
				
			||||||
      'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
 | 
					 | 
				
			||||||
      'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const visibilityIcon = visibilityIconInfo[status.get('visibility')];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='modal-root__modal boost-modal'>
 | 
					      <div className='modal-root__modal boost-modal'>
 | 
				
			||||||
        <div className='boost-modal__container'>
 | 
					        <div className='boost-modal__container'>
 | 
				
			||||||
          <div className={classNames('status', `status-${status.get('visibility')}`, 'light')}>
 | 
					          <div className={classNames('status', `status-${status.get('visibility')}`, 'light')}>
 | 
				
			||||||
            <div className='status__info'>
 | 
					            <div className='status__info'>
 | 
				
			||||||
              <a href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
 | 
					              <a href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
 | 
				
			||||||
                <span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span>
 | 
					                <span className='status__visibility-icon'><VisibilityIcon visibility={status.get('visibility')} /></span>
 | 
				
			||||||
                <RelativeTimestamp timestamp={status.get('created_at')} />
 | 
					                <RelativeTimestamp timestamp={status.get('created_at')} />
 | 
				
			||||||
              </a>
 | 
					              </a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -116,7 +106,7 @@ class BoostModal extends ImmutablePureComponent {
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='boost-modal__action-bar'>
 | 
					        <div className='boost-modal__action-bar'>
 | 
				
			||||||
          <div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} /></div>
 | 
					          <div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' icon={RepeatIcon} /></span> }} /></div>
 | 
				
			||||||
          {status.get('visibility') !== 'private' && !status.get('reblogged') && (
 | 
					          {status.get('visibility') !== 'private' && !status.get('reblogged') && (
 | 
				
			||||||
            <PrivacyDropdown
 | 
					            <PrivacyDropdown
 | 
				
			||||||
              noDirect
 | 
					              noDirect
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,8 @@ import { PureComponent } from 'react';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { defineMessages, injectIntl } from 'react-intl';
 | 
					import { defineMessages, injectIntl } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ReactComponent as RefreshIcon } from '@material-symbols/svg-600/outlined/refresh.svg';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { IconButton } from '../../../components/icon_button';
 | 
					import { IconButton } from '../../../components/icon_button';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
@@ -31,7 +33,7 @@ class BundleModalError extends PureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='modal-root__modal error-modal'>
 | 
					      <div className='modal-root__modal error-modal'>
 | 
				
			||||||
        <div className='error-modal__body'>
 | 
					        <div className='error-modal__body'>
 | 
				
			||||||
          <IconButton title={formatMessage(messages.retry)} icon='refresh' onClick={this.handleRetry} size={64} />
 | 
					          <IconButton title={formatMessage(messages.retry)} icon='refresh' iconComponent={RefreshIcon} onClick={this.handleRetry} size={64} />
 | 
				
			||||||
          {formatMessage(messages.error)}
 | 
					          {formatMessage(messages.error)}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ export default class Column extends PureComponent {
 | 
				
			|||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    heading: PropTypes.string,
 | 
					    heading: PropTypes.string,
 | 
				
			||||||
    icon: PropTypes.string,
 | 
					    icon: PropTypes.string,
 | 
				
			||||||
 | 
					    iconComponent: PropTypes.func,
 | 
				
			||||||
    children: PropTypes.node,
 | 
					    children: PropTypes.node,
 | 
				
			||||||
    active: PropTypes.bool,
 | 
					    active: PropTypes.bool,
 | 
				
			||||||
    hideHeadingOnMobile: PropTypes.bool,
 | 
					    hideHeadingOnMobile: PropTypes.bool,
 | 
				
			||||||
@@ -50,13 +51,13 @@ export default class Column extends PureComponent {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { heading, icon, children, active, hideHeadingOnMobile } = this.props;
 | 
					    const { heading, icon, iconComponent, children, active, hideHeadingOnMobile } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const showHeading = heading && (!hideHeadingOnMobile || (hideHeadingOnMobile && !isMobile(window.innerWidth)));
 | 
					    const showHeading = heading && (!hideHeadingOnMobile || (hideHeadingOnMobile && !isMobile(window.innerWidth)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const columnHeaderId = showHeading && heading.replace(/ /g, '-');
 | 
					    const columnHeaderId = showHeading && heading.replace(/ /g, '-');
 | 
				
			||||||
    const header = showHeading && (
 | 
					    const header = showHeading && (
 | 
				
			||||||
      <ColumnHeader icon={icon} active={active} type={heading} onClick={this.handleHeaderClick} columnHeaderId={columnHeaderId} />
 | 
					      <ColumnHeader icon={icon} iconComponent={iconComponent} active={active} type={heading} onClick={this.handleHeaderClick} columnHeaderId={columnHeaderId} />
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ export default class ColumnHeader extends PureComponent {
 | 
				
			|||||||
    let iconElement = '';
 | 
					    let iconElement = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (icon) {
 | 
					    if (icon) {
 | 
				
			||||||
      iconElement = <Icon id={icon} fixedWidth className='column-header__icon' />;
 | 
					      iconElement = <Icon id={icon} className='column-header__icon' />;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,10 @@ import { NavLink } from 'react-router-dom';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { Icon }  from 'mastodon/components/icon';
 | 
					import { Icon }  from 'mastodon/components/icon';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ColumnLink = ({ icon, text, to, href, method, badge, transparent, ...other }) => {
 | 
					const ColumnLink = ({ icon, iconComponent, text, to, href, method, badge, transparent, ...other }) => {
 | 
				
			||||||
  const className = classNames('column-link', { 'column-link--transparent': transparent });
 | 
					  const className = classNames('column-link', { 'column-link--transparent': transparent });
 | 
				
			||||||
  const badgeElement = typeof badge !== 'undefined' ? <span className='column-link__badge'>{badge}</span> : null;
 | 
					  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;
 | 
					  const iconElement = (typeof icon === 'string' || iconComponent) ? <Icon id={icon} icon={iconComponent} className='column-link__icon' /> : icon;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (href) {
 | 
					  if (href) {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
@@ -31,6 +31,7 @@ const ColumnLink = ({ icon, text, to, href, method, badge, transparent, ...other
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
ColumnLink.propTypes = {
 | 
					ColumnLink.propTypes = {
 | 
				
			||||||
  icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
 | 
					  icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
 | 
				
			||||||
 | 
					  iconComponent: PropTypes.func,
 | 
				
			||||||
  text: PropTypes.string.isRequired,
 | 
					  text: PropTypes.string.isRequired,
 | 
				
			||||||
  to: PropTypes.string,
 | 
					  to: PropTypes.string,
 | 
				
			||||||
  href: PropTypes.string,
 | 
					  href: PropTypes.string,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,32 +0,0 @@
 | 
				
			|||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import Column from '../../../components/column';
 | 
					 | 
				
			||||||
import ColumnHeader from '../../../components/column_header';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default class ColumnLoading extends ImmutablePureComponent {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static propTypes = {
 | 
					 | 
				
			||||||
    title: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
 | 
					 | 
				
			||||||
    icon: PropTypes.string,
 | 
					 | 
				
			||||||
    multiColumn: PropTypes.bool,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static defaultProps = {
 | 
					 | 
				
			||||||
    title: '',
 | 
					 | 
				
			||||||
    icon: '',
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render() {
 | 
					 | 
				
			||||||
    let { title, icon, multiColumn } = this.props;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <Column>
 | 
					 | 
				
			||||||
        <ColumnHeader icon={icon} title={title} multiColumn={multiColumn} focusable={false} placeholder />
 | 
					 | 
				
			||||||
        <div className='scrollable' />
 | 
					 | 
				
			||||||
      </Column>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					import Column from '../../../components/column';
 | 
				
			||||||
 | 
					import ColumnHeader from '../../../components/column_header';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface Props {
 | 
				
			||||||
 | 
					  multiColumn?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ColumnLoading: React.FC<Props> = (otherProps) => (
 | 
				
			||||||
 | 
					  <Column>
 | 
				
			||||||
 | 
					    <ColumnHeader {...otherProps} />
 | 
				
			||||||
 | 
					    <div className='scrollable' />
 | 
				
			||||||
 | 
					  </Column>
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
@@ -23,7 +23,7 @@ import {
 | 
				
			|||||||
} from '../util/async-components';
 | 
					} from '../util/async-components';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import BundleColumnError from './bundle_column_error';
 | 
					import BundleColumnError from './bundle_column_error';
 | 
				
			||||||
import ColumnLoading from './column_loading';
 | 
					import { ColumnLoading } from './column_loading';
 | 
				
			||||||
import ComposePanel from './compose_panel';
 | 
					import ComposePanel from './compose_panel';
 | 
				
			||||||
import DrawerLoading from './drawer_loading';
 | 
					import DrawerLoading from './drawer_loading';
 | 
				
			||||||
import NavigationPanel from './navigation_panel';
 | 
					import NavigationPanel from './navigation_panel';
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user