Use upstream's Icon component

Rework the codebase to avoid unnecessary differences with upstream
This commit is contained in:
Thibaut Girka 2019-09-09 15:28:45 +02:00 committed by ThibG
parent f2b307af25
commit f154d9d6e9
18 changed files with 62 additions and 66 deletions

View File

@ -1,26 +1,21 @@
// Package imports.
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
export default class Icon extends React.PureComponent {
static propTypes = {
id: PropTypes.string.isRequired,
className: PropTypes.string,
fixedWidth: PropTypes.bool,
};
render () {
const { id, className, fixedWidth, ...other } = this.props;
return (
<i role='img' className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })} {...other} />
);
}
// This just renders a FontAwesome icon.
export default function Icon ({
className,
fullwidth,
icon,
}) {
const computedClass = classNames('icon', 'fa', { 'fa-fw': fullwidth }, `fa-${icon}`, className);
return icon ? (
<span
aria-hidden='true'
className={computedClass}
/>
) : null;
} }
// Props.
Icon.propTypes = {
className: PropTypes.string,
fullwidth: PropTypes.bool,
icon: PropTypes.string,
};

View File

@ -3,6 +3,7 @@ import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring'; import spring from 'react-motion/lib/spring';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import Icon from 'flavours/glitch/components/icon';
export default class IconButton extends React.PureComponent { export default class IconButton extends React.PureComponent {
@ -133,7 +134,7 @@ export default class IconButton extends React.PureComponent {
tabIndex={tabIndex} tabIndex={tabIndex}
disabled={disabled} disabled={disabled}
> >
<i className={`fa fa-fw fa-${icon}`} aria-hidden='true' /> <Icon id={icon} fixedWidth aria-hidden='true' />
</button> </button>
); );
} }
@ -155,7 +156,7 @@ export default class IconButton extends React.PureComponent {
tabIndex={tabIndex} tabIndex={tabIndex}
disabled={disabled} disabled={disabled}
> >
<i style={{ transform: `rotate(${rotate}deg)` }} className={`fa fa-fw fa-${icon}`} aria-hidden='true' /> <Icon id={icon} style={{ transform: `rotate(${rotate}deg)` }} fixedWidth aria-hidden='true' />
{this.props.label} {this.props.label}
</button>) </button>)
} }

View File

@ -6,7 +6,7 @@ const formatNumber = num => num > 40 ? '40+' : num;
const IconWithBadge = ({ id, count, className }) => ( const IconWithBadge = ({ id, count, className }) => (
<i className='icon-with-badge'> <i className='icon-with-badge'>
<Icon icon={id} fixedWidth className={className} /> <Icon id={id} fixedWidth className={className} />
{count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>} {count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>}
</i> </i>
); );

View File

@ -31,7 +31,7 @@ class ActionBar extends React.PureComponent {
if (account.get('acct') !== account.get('username')) { if (account.get('acct') !== account.get('username')) {
extraInfo = ( extraInfo = (
<div className='account__disclaimer'> <div className='account__disclaimer'>
<Icon icon='info-circle' fixedWidth /> <FormattedMessage <Icon id='info-circle' fixedWidth /> <FormattedMessage
id='account.disclaimer_full' id='account.disclaimer_full'
defaultMessage="Information below may reflect the user's profile incompletely." defaultMessage="Information below may reflect the user's profile incompletely."
/> />

View File

@ -158,7 +158,7 @@ class Header extends ImmutablePureComponent {
} }
if (account.get('locked')) { if (account.get('locked')) {
lockedIcon = <Icon icon='lock' title={intl.formatMessage(messages.account_locked)} />; lockedIcon = <Icon id='lock' title={intl.formatMessage(messages.account_locked)} />;
} }
if (account.get('id') !== me) { if (account.get('id') !== me) {
@ -256,7 +256,7 @@ class Header extends ImmutablePureComponent {
<div className='account__header__tabs__buttons'> <div className='account__header__tabs__buttons'>
{actionBtn} {actionBtn}
<DropdownMenuContainer items={menu} icon='ellipsis-v' size={24} direction='right' /> <DropdownMenuContainer items={menu} id='ellipsis-v' size={24} direction='right' />
</div> </div>
</div> </div>

View File

@ -198,8 +198,8 @@ class Audio extends React.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' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><Icon icon={paused ? 'play' : 'pause'} fixedWidth /></button> <button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
<button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><Icon icon={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button> <button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
<div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}> <div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
<div className='video-player__volume__current' style={{ width: `${volumeWidth}px` }} /> <div className='video-player__volume__current' style={{ width: `${volumeWidth}px` }} />

View File

@ -185,7 +185,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent
if (on !== null && typeof on !== 'undefined') { if (on !== null && typeof on !== 'undefined') {
prefix = <Toggle checked={on} onChange={this.handleClick} />; prefix = <Toggle checked={on} onChange={this.handleClick} />;
} else if (icon) { } else if (icon) {
prefix = <Icon className='icon' fullwidth icon={icon} /> prefix = <Icon className='icon' fixedWidth id={icon} />
} }
return ( return (

View File

@ -82,13 +82,13 @@ class Header extends ImmutablePureComponent {
aria-label={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}
title={intl.formatMessage(messages.start)} title={intl.formatMessage(messages.start)}
to='/getting-started' to='/getting-started'
><Icon icon='asterisk' /></Link> ><Icon id='asterisk' /></Link>
{renderForColumn('HOME', ( {renderForColumn('HOME', (
<Link <Link
aria-label={intl.formatMessage(messages.home_timeline)} aria-label={intl.formatMessage(messages.home_timeline)}
title={intl.formatMessage(messages.home_timeline)} title={intl.formatMessage(messages.home_timeline)}
to='/timelines/home' to='/timelines/home'
><Icon icon='home' /></Link> ><Icon id='home' /></Link>
))} ))}
{renderForColumn('NOTIFICATIONS', ( {renderForColumn('NOTIFICATIONS', (
<Link <Link
@ -97,7 +97,7 @@ class Header extends ImmutablePureComponent {
to='/notifications' to='/notifications'
> >
<span className='icon-badge-wrapper'> <span className='icon-badge-wrapper'>
<Icon icon='bell' /> <Icon id='bell' />
{ showNotificationsBadge && unreadNotifications > 0 && <div className='icon-badge' />} { showNotificationsBadge && unreadNotifications > 0 && <div className='icon-badge' />}
</span> </span>
</Link> </Link>
@ -107,27 +107,27 @@ class Header extends ImmutablePureComponent {
aria-label={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}
title={intl.formatMessage(messages.community)} title={intl.formatMessage(messages.community)}
to='/timelines/public/local' to='/timelines/public/local'
><Icon icon='users' /></Link> ><Icon id='users' /></Link>
))} ))}
{renderForColumn('PUBLIC', ( {renderForColumn('PUBLIC', (
<Link <Link
aria-label={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}
title={intl.formatMessage(messages.public)} title={intl.formatMessage(messages.public)}
to='/timelines/public' to='/timelines/public'
><Icon icon='globe' /></Link> ><Icon id='globe' /></Link>
))} ))}
<a <a
aria-label={intl.formatMessage(messages.settings)} aria-label={intl.formatMessage(messages.settings)}
onClick={onSettingsClick} onClick={onSettingsClick}
href='#' href='#'
title={intl.formatMessage(messages.settings)} title={intl.formatMessage(messages.settings)}
><Icon icon='cogs' /></a> ><Icon id='cogs' /></a>
<a <a
aria-label={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)}
onClick={this.handleLogoutClick} onClick={this.handleLogoutClick}
href={ signOutLink } href={ signOutLink }
title={intl.formatMessage(messages.logout)} title={intl.formatMessage(messages.logout)}
><Icon icon='sign-out' /></a> ><Icon id='sign-out' /></a>
</nav> </nav>
); );
}; };

View File

@ -79,7 +79,7 @@ class Option extends React.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)} id='times' onClick={this.handleOptionRemove} />
</div> </div>
</li> </li>
); );
@ -132,7 +132,7 @@ class PollForm extends ImmutablePureComponent {
{options.size < pollLimits.max_options && ( {options.size < pollLimits.max_options && (
<label className='poll__text editable'> <label className='poll__text editable'>
<span className={classNames('poll__input')} style={{ opacity: 0 }} /> <span className={classNames('poll__input')} style={{ opacity: 0 }} />
<button className='button button-secondary' onClick={this.handleAddOption}><Icon icon='plus' /> <FormattedMessage {...messages.add_option} /></button> <button className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>
</label> </label>
)} )}
</ul> </ul>

View File

@ -58,7 +58,7 @@ class Publisher extends ImmutablePureComponent {
text={ text={
<span> <span>
<Icon <Icon
icon={{ id={{
public: 'globe', public: 'globe',
unlisted: 'unlock', unlisted: 'unlock',
private: 'lock', private: 'lock',
@ -80,7 +80,7 @@ class Publisher extends ImmutablePureComponent {
return ( return (
<span> <span>
<Icon <Icon
icon={{ id={{
direct: 'envelope', direct: 'envelope',
private: 'lock', private: 'lock',
public: 'globe', public: 'globe',

View File

@ -153,8 +153,8 @@ class Search extends React.PureComponent {
role='button' role='button'
tabIndex='0' tabIndex='0'
> >
<Icon icon='search' className={hasValue ? '' : 'active'} /> <Icon id='search' className={hasValue ? '' : 'active'} />
<Icon icon='times-circle' className={hasValue ? 'active' : ''} /> <Icon id='times-circle' className={hasValue ? 'active' : ''} />
</div> </div>
<Overlay show={expanded && !hasValue} placement='bottom' target={this}> <Overlay show={expanded && !hasValue} placement='bottom' target={this}>

View File

@ -82,7 +82,7 @@ class SearchResults extends ImmutablePureComponent {
count += results.get('accounts').size; count += results.get('accounts').size;
accounts = ( accounts = (
<section> <section>
<h5><Icon icon='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='People' /></h5> <h5><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='People' /></h5>
{results.get('accounts').map(accountId => <AccountContainer id={accountId} key={accountId} />)} {results.get('accounts').map(accountId => <AccountContainer id={accountId} key={accountId} />)}
@ -95,7 +95,7 @@ class SearchResults extends ImmutablePureComponent {
count += results.get('statuses').size; count += results.get('statuses').size;
statuses = ( statuses = (
<section> <section>
<h5><Icon icon='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5> <h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
{results.get('statuses').map(statusId => <StatusContainer id={statusId} key={statusId}/>)} {results.get('statuses').map(statusId => <StatusContainer id={statusId} key={statusId}/>)}
@ -108,7 +108,7 @@ class SearchResults extends ImmutablePureComponent {
count += results.get('hashtags').size; count += results.get('hashtags').size;
hashtags = ( hashtags = (
<section> <section>
<h5><Icon icon='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></h5> <h5><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></h5>
{results.get('hashtags').map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)} {results.get('hashtags').map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
@ -121,7 +121,7 @@ class SearchResults extends ImmutablePureComponent {
return ( return (
<div className='drawer--results'> <div className='drawer--results'>
<header className='search-results__header'> <header className='search-results__header'>
<Icon icon='search' fixedWidth /> <Icon id='search' fixedWidth />
<FormattedMessage id='search_results.total' defaultMessage='{count, number} {count, plural, one {result} other {results}}' values={{ count }} /> <FormattedMessage id='search_results.total' defaultMessage='{count, number} {count, plural, one {result} other {results}}' values={{ count }} />
</header> </header>

View File

@ -47,8 +47,8 @@ class TextareaIcons extends ImmutablePureComponent {
title={intl.formatMessage(message)} title={intl.formatMessage(message)}
> >
<Icon <Icon
fullwidth fixedWidth
icon={icon} id={icon}
/> />
</span> </span>
) : null ) : null

View File

@ -44,7 +44,7 @@ export default class Upload extends ImmutablePureComponent {
{({ scale }) => ( {({ scale }) => (
<div style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}> <div style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
<div className={classNames('composer--upload_form--actions', { active: true })}> <div className={classNames('composer--upload_form--actions', { active: true })}>
<button className='icon-button' onClick={this.handleUndoClick}><Icon icon='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button> <button className='icon-button' onClick={this.handleUndoClick}><Icon id='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>
<button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button> <button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>
</div> </div>
</div> </div>

View File

@ -22,7 +22,7 @@ export default class UploadProgress extends React.PureComponent {
return ( return (
<div className='composer--upload_form--progress'> <div className='composer--upload_form--progress'>
<Icon icon={icon} /> <Icon id={icon} />
<div className='message'> <div className='message'>
{message} {message}

View File

@ -68,8 +68,8 @@ export default class ActionsModal extends ImmutablePureComponent {
return ( return (
<Icon <Icon
className='icon' className='icon'
fullwidth fixedWidth
icon={icon} id={icon}
/> />
); );
default: default:

View File

@ -46,7 +46,7 @@ class ListPanel extends ImmutablePureComponent {
<hr /> <hr />
{lists.map(list => ( {lists.map(list => (
<NavLink key={list.get('id')} className='column-link column-link--transparent' strict to={`/timelines/list/${list.get('id')}`}><Icon className='column-link__icon' icon='list-ul' fixedWidth />{list.get('title')}</NavLink> <NavLink key={list.get('id')} className='column-link column-link--transparent' strict to={`/timelines/list/${list.get('id')}`}><Icon className='column-link__icon' id='list-ul' fixedWidth />{list.get('title')}</NavLink>
))} ))}
</div> </div>
); );

View File

@ -11,23 +11,23 @@ import TrendsContainer from 'flavours/glitch/features/getting_started/containers
const NavigationPanel = ({ onOpenSettings }) => ( const NavigationPanel = ({ onOpenSettings }) => (
<div className='navigation-panel'> <div className='navigation-panel'>
<NavLink className='column-link column-link--transparent' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon className='column-link__icon' icon='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink> <NavLink className='column-link column-link--transparent' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon className='column-link__icon' id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>
<NavLink className='column-link column-link--transparent' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon className='column-link__icon' /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink> <NavLink className='column-link column-link--transparent' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon className='column-link__icon' /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>
<FollowRequestsNavLink /> <FollowRequestsNavLink />
<NavLink className='column-link column-link--transparent' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon className='column-link__icon' icon='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink> <NavLink className='column-link column-link--transparent' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>
<NavLink className='column-link column-link--transparent' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon className='column-link__icon' icon='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink> <NavLink className='column-link column-link--transparent' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon className='column-link__icon' id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>
<NavLink className='column-link column-link--transparent' to='/timelines/direct'><Icon className='column-link__icon' icon='envelope' fixedWidth /><FormattedMessage id='navigation_bar.direct' defaultMessage='Direct messages' /></NavLink> <NavLink className='column-link column-link--transparent' to='/timelines/direct'><Icon className='column-link__icon' id='envelope' fixedWidth /><FormattedMessage id='navigation_bar.direct' defaultMessage='Direct messages' /></NavLink>
<NavLink className='column-link column-link--transparent' to='/bookmarks'><Icon className='column-link__icon' icon='bookmark' fixedWidth /><FormattedMessage id='navigation_bar.bookmarks' defaultMessage='Bookmarks' /></NavLink> <NavLink className='column-link column-link--transparent' to='/bookmarks'><Icon className='column-link__icon' id='bookmark' fixedWidth /><FormattedMessage id='navigation_bar.bookmarks' defaultMessage='Bookmarks' /></NavLink>
{profile_directory && <NavLink className='column-link column-link--transparent' to='/directory'><Icon className='column-link__icon' icon='address-book-o' fixedWidth /><FormattedMessage id='getting_started.directory' defaultMessage='Profile directory' /></NavLink>} {profile_directory && <NavLink className='column-link column-link--transparent' to='/directory'><Icon className='column-link__icon' id='address-book-o' fixedWidth /><FormattedMessage id='getting_started.directory' defaultMessage='Profile directory' /></NavLink>}
<NavLink className='column-link column-link--transparent' to='/lists'><Icon className='column-link__icon' icon='list-ul' fixedWidth /><FormattedMessage id='navigation_bar.lists' defaultMessage='Lists' /></NavLink> <NavLink className='column-link column-link--transparent' to='/lists'><Icon className='column-link__icon' id='list-ul' fixedWidth /><FormattedMessage id='navigation_bar.lists' defaultMessage='Lists' /></NavLink>
<ListPanel /> <ListPanel />
<hr /> <hr />
{!!preferencesLink && <a className='column-link column-link--transparent' href={preferencesLink} target='_blank'><Icon className='column-link__icon' icon='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a>} {!!preferencesLink && <a className='column-link column-link--transparent' href={preferencesLink} target='_blank'><Icon className='column-link__icon' id='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a>}
<a className='column-link column-link--transparent' href='#' onClick={onOpenSettings}><Icon className='column-link__icon' icon='cogs' fixedWidth /><FormattedMessage id='navigation_bar.app_settings' defaultMessage='App settings' /></a> <a className='column-link column-link--transparent' href='#' onClick={onOpenSettings}><Icon className='column-link__icon' id='cogs' fixedWidth /><FormattedMessage id='navigation_bar.app_settings' defaultMessage='App settings' /></a>
{!!relationshipsLink && <a className='column-link column-link--transparent' href={relationshipsLink} target='_blank'><Icon className='column-link__icon' icon='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a>} {!!relationshipsLink && <a className='column-link column-link--transparent' href={relationshipsLink} target='_blank'><Icon className='column-link__icon' id='users' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a>}
{showTrends && <div className='flex-spacer' />} {showTrends && <div className='flex-spacer' />}
{showTrends && <TrendsContainer />} {showTrends && <TrendsContainer />}